Sai Ram Ved Vijapurapu has taken part in Genuary, a January challenge that offers a new generative art prompt each day, for several years. His sketches focus on motion rather than color or form: how to make things move in ways that feel satisfying. In this follow-along workshop he rebuilt one of last year’s pieces, a stack of black and white shapes whose motion is driven by trigonometric functions, from an empty p5.js sketch.
He started with habits he uses in most sketches: a full-window canvas, sizes defined relative to the canvas width, and translate() to move the origin to the center so the x and y arguments stay free for motion. frameCount supplied a steadily increasing number, and the graphing calculator Desmos showed how sin() turns that number into a smooth wave between −1 and 1. Because that range is only a pixel or two, he used map() to stretch it to a quarter of the canvas height and slowed the input by multiplying frameCount by 0.1.
A loop drew many circles, largest first so each smaller one sits on top, alternating black and white using the remainder of the loop index divided by 2. Subtracting a small multiple of the loop index from each circle’s input made each one lag slightly behind the next, producing a rippling pattern from about 20 lines of code. He then turned to the 12 principles of animation from Disney animators, using a circle-based visualization of them, and focused on easing: real objects speed up and slow down, as in the windup and release of a throw. A pure sine wave is smooth but plain. Experimenting in Desmos, he nested functions to reshape the motion, landing on atan(10 × sin(x)), which lingers at each end and moves quickly through the middle. Graphing first showed him the new minimum and maximum to use in map().
To finish, he made a perfect loop. Since sine repeats every 2π, setting the input to TWO_PI × frameCount ÷ 120 completes one cycle in exactly 120 frames, and saveGif() with frame units records just that cycle. Swapping circles for squares with rectMode(CENTER) recreated the original piece. He encouraged everyone to try Genuary, saying that a daily practice and his own black-and-white constraint had helped him develop a recognizable style, echoing Daniel Shiffman’s keynote.
Three takeaways
- Graph before you code. Desmos makes it easy to see how a function behaves and what its range is before mapping it to motion (00:09:25–00:11:00, 00:31:11–00:36:46).
- Small offsets make rich patterns. Subtracting a little of the loop index from each shape’s input creates lagging waves (00:22:22–00:26:30).
- Plan the loop length. Tie the input to TWO_PI divided by a frame count so the animation repeats exactly, then save that many frames (00:41:11–00:49:00).
Try it
From the workshop: in p5.js, draw ten nested circles whose y position is map(sin(x − i × 0.1), −1, 1, −height/4, height/4). Replace sin(x) with atan(10 × sin(x)), find its new range in Desmos, and update map(). Then set x to TWO_PI × frameCount / 120 and record one 120-frame loop with saveGif(‘loop’, 120, { units: ‘frames’ }).
Watch and explore
Replay: Watch on YouTube
From the original program
Published before the event
Delightful motion loops
In this workshop, we'll graph looping trigonometric easing functions in Desmos and bring them over to p5.js to let them drive the movement of simple shapes. We'll then see how to record these as perfectly looping animations to share over the interwebs!
About the presenters
Sai Ram Ved Vijapurapu
he/him
Sai is an information designer crafting delightful experiences with data & technology who draws inspiration from natural phenomena, often using code as a means to that end. In the past, his work has been recognised and celebrated by CultureHub, Metropolitan Transportation Authority, Bangalore International Center and Information is Beautiful, among others. Sai is currently at SOOT where he continues to imbue interactivity in his work.