This makes me wonder how they pulled off something similar in Macromedia Flash (RIP) well over 20 years ago. I vividly remember being amazed by how it smoothed out curves when drawing freehand, with such limited processing power compared to today's CPUs.
Smoothing is a different operation where you are simplifying the bezier curve by removing redundant(ish) points. So if you draw an almost straight line, you may have created 100 control points, and then the software simplifies it down to 4 points.
For what it’s worth, perfect freehand (the library I wrote that they’re using for the digital ink) does not use Bézier curves at all to determine the position of points or create the “stroke” polygon that wraps the input points. Curves are only used to draw the line around that stroke polygon.
I tried to incorporate simplification into the perfect freehand algorithm but eventually gave up because I could not find any “stable” algorithm that would not cause the line to jump around as you drew / added points to the end. As far as I know none exist. Most apps that use simplification solve this problem by simplifying the line only after you’ve finished drawing, however for handwriting or artistic drawing this is especially bad as it “undoes” legitimate decisions you’ve made about where to place detail. In addition, the perfect-freehand algorithm simulates pressure based on density of points, so simplifying the line (ie removing points) without creating a corresponding pressure curve will cause a reduction in line variation, which is part of the fun of using it in the first place!
I’d love to learn more about what the canva team has done here though. Freehand drawing is a fascinating problem space, even without the ml / shape recognition stuff.
I suspect it took mouse events, and initially drew straight lines between them. That's necessary on 1990's hardware because drawing straight lines is fast, and you need to do it fast.
Then, when you are done drawing, it redraws the line, using the same points as before, but this time as input to a spline curve algorithm.
Drawing splines isn't much harder computationally, but notably if you add one more point to the end of a spline curve, then part of the line that you have already drawn changes. That in itself is very computationally heavy, since everything behind that line now needs to be redrawn - certainly not something you can be sure can be done at 60 fps!
Drawing lines is faster than you think! The perfect-freehand algorithm that I wrote / that canva is using here does not use splines but it does recompute the entire line on every frame. It’s fine at 60fps (and also fine at 120fps) up to a few thousand points on somewhat modern hardware before the paths get too slow to render. The algo itself is just blazing fast, in part because it does not rely on splines (which are much more complex).
For an svg-style approach to ink (as opposed to a raster / dab-style brush) there’s no other option than recomputing the whole line each time. As a bonus, you can adjust the properties after the fact very easily. (You can try that at perfectfreehand.com.)
But on 90's hardware, you still have no compositing or back buffers, so if you want to 'move' previous bits of line, you must redraw the background, which is the expensive bit.