To create the spiral effect, I use a main <canvas> and an offscreen <canvas>. The main <canvas> is what the viewer sees on the page. I use the offscreen <canvas> to scale and rotate the image from the main <canvas>. Normally, I would tell the browser not to display the offscreen <canvas>.

(Main <canvas>)

(Offscreen <canvas>)


I animate the spiral heart by drawing a new frame to the main <canvas> every 100 milliseconds. It takes ten steps to draw each frame. Use the number field to cycle through all ten steps and see how a frame is assembled.

In step 1, I clear the offscreen <canvas>. It looks like nothing happens in this step because the offscreen <canvas> is already blank, but if there were a drawing on the offscreen <canvas>, it would be erased in this step.

In step 2, I translate the origin of the offscreen context to (100, 210). This is the center of the spiral in both contexts. When I rotate the context, I need to do it around this origin point.

In step 3, I scale the offscreen context by a factor of 0.9.

In step 4, I rotate the offscreen context by 27°.

In step 5, I translate the origin of the offscreen context to (-100, -210). This ”undoes“ the translation from step 2. The origin of the context is now where the top left corner of the <canvas> would be if we scaled it by a factor of 0.9 and rotated it 27° around (100, 210).

In step 6, I copy the image from the main <canvas> and paste it on the offscreen <canvas>. Copying an image from a <canvas> is like taking a screenshot or a photograph—we are just copying pixels. When I paste the image on the offscreen <canvas>, this happens within the offscreen context—so the image is automatically scaled and rotated in the outside view.

In step 7, I restore the offscreen context back to its original state.

In step 8, I clear the main <canvas>.

In step 9, I copy the image from the offscreen <canvas> and paste it on the main <canvas>.

In step 10, I draw a new heart with a slightly pinker fill color on the main <canvas>.

Although it takes multiple steps to draw a new frame, those steps happen in memory and get drawn to the screen all at once. That’s why we don’t see any of the individual steps when they’re happening. Whenever I’ve shown a drawing being drawn in stages, I’ve used timers to put breaks between steps.

Background color

Spiral center: x: , y: ; scale factor: ; rotation angle: °

Heart position relative to spiral center: x: , y: ; circle radius:

By tweaking a handful of variables, we can experiment with different spirals and find the spiral that makes us happiest.

Add color stops and transitions.