REFERENCE
- Gallery page: https://magpui.com/en/i/hand-drawn-jittery-line-clock-bc2a82
- First frame (image): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/hand-drawn-jittery-line-clock-bc2a82/shot.jpg
- Clip (mp4): https://dnioievkvxejjbxgwvko.supabase.co/storage/v1/object/public/media/hand-drawn-jittery-line-clock-bc2a82/clip.mp4
- Original post: https://x.com/kitasenjudesign/status/2114683411260694530 by @kitasenjudesign
Before building, download the first frame and look at it. If ffmpeg is available, download the clip and extract frames (ffmpeg -i clip.mp4 -vf fps=2 frame-%02d.png), then study the motion frame by frame. Match what you see; the text below describes it, the frames are the truth.
BUILD: A full-screen generative clock that shows one large digit at a time as a thin white outline on a near-black background. The outline is not a clean font path: it is redrawn every frame with noise, so the stroke boils, wobbles and grows small spiky frays, like an animated pencil sketch. Digits advance in sequence (for example the seconds of the current time, or a 2, 4, 6, 8, 0 count), and the roughness slowly builds up over each digit's life before the next clean digit appears. It should feel quiet, technical and hand made.
DESIGN SYSTEM: Background #111111. A faint crosshair grid of 1px lines #222222 splits the screen into cells, with tiny 8px monospace captions #444444 near the grid lines like a lab readout. Digit: rounded geometric sans figure, about 40% of the viewport height, centered in its cell, stroke 1px to 1.25px #D9D9D9, no fill. Lots of empty space around it.
MOTION: Every frame, sample points along the digit's outline (about 400 to 800 points per contour) and offset each point along its normal by smooth noise, amplitude 1.5px at the start of the digit's life rising to about 6px, with a second higher-frequency noise layer that adds occasional spikes up to 10px near the end. Noise moves over time at about 0.6 units per second so the line boils rather than flickers; redraw at 12 to 24 fps on purpose for a stop-motion feel. Digit change every 1000ms: the new digit appears clean (low amplitude) with a 120ms opacity cross-fade from the old one. Captions update with the digit value.
SECTIONS: Canvas stage; grid and captions layer; single digit outline; optional time source (current seconds or a looping sequence).
IMPLEMENTATION: Canvas 2D or p5.js-style loop. Get each digit's outline by converting a font glyph to a path (opentype.js) or by drawing the text to an offscreen canvas and tracing contours; resample contours to evenly spaced points once per digit and cache them. Apply simplex noise per point per frame and stroke with a single path per contour. Handle devicePixelRatio for crisp 1px lines. prefers-reduced-motion: freeze the noise at low amplitude and only change digits. Pause the loop when the tab is hidden. Give the canvas an aria-label with the current value.
ADAPT TO THE PROJECT: Reuse the project's fonts for the digit shapes and its dark palette tokens; map colors to the nearest existing tokens. Do not copy the original captions or any branding; use placeholder labels.
SUCCESS CHECK:
- The outline visibly boils every frame while the digit stays clearly readable.
- Roughness grows across a digit's life and resets when the next digit appears.
- Lines stay crisp on retina screens and the loop stops when the tab is hidden.