| name | squiggle-draw-on |
| description | motion-graphic primitive — wobbly hand-drawn SVG path that strokes on with `stroke-dasharray` / `stroke-dashoffset` animation, often ending in a hand-drawn arrow tip. used for underlines, accent marks, arrows, traces. central to SP-B (pinterest doodles) and SP-G (riso motion-lines). avoids vector-perfection by adding per-vertex jitter to the path. |
squiggle-draw-on
Purpose
Render a hand-drawn-feeling SVG line that animates as if being drawn live — used for underlines under headlines, arrow callouts, accent squiggles around logo lockups, or motion-line trails behind a traveling element-handoff object.
The visual signal of "not perfectly vector" is a critical anti-AI tell across reference videos. Sterile straight lines look algorithmic; squiggles with light per-vertex jitter feel human.
Params (params.schema.json)
{
"id": "squiggle-under-headline",
"path_kind": "underline | arrow | squiggle | underline-with-arrow | circle-around",
"anchor_target": { "kind": "element-id" | "absolute", "value": "h1" },
"start_x": 60,
"start_y": 320,
"end_x": 480,
"end_y": 320,
"control_points": [],
"stroke_color": "#0F0F0F",
"stroke_width_px": 5,
"stroke_linecap": "round",
"wobble_amplitude_px": 6,
"wobble_frequency": 0.3,
"wobble_seed": 17,
"arrow_tip": true,
"arrow_size_px": 24,
"draw_duration_frames": 14,
"draw_easing": "bezier(0.22, 1, 0.36, 1)",
"draw_start_frame": 0
}
Behaviour
- Generate an SVG path from
start → end using control_points (or a default arc if none given).
- Apply per-vertex jitter: walk the path at ~12px intervals, perturb each sample by
wobble_amplitude_px * noise(t, seed).
- Compute path total length via
getTotalLength().
- Set
stroke-dasharray = pathLength; stroke-dashoffset = pathLength * (1 - progress) where progress interpolates 0→1 over draw_duration_frames.
- If
arrow_tip = true, append a small hand-drawn triangle at the end position, also drawn-on after the line completes (last 4 frames).
Implementation: a React component using SVG, useCurrentFrame(), and interpolate.
Style pack overrides
SP-B (pinterest-saturated)
stroke_width_px: 4, wobble_amplitude_px: 6, arrow_tip: true.
- Stroke color: ink (#0F0F0F) — high contrast on saturated bgs.
SP-E (chaos-card)
stroke_width_px: 6, wobble_amplitude_px: 8 (more chaotic).
- Stroke color: card's complement.
SP-G (riso-illustration)
stroke_width_px: 5, wobble_amplitude_px: 6.
- Path-follows-element: when
anchor_target = "element-handoff:ball", the path geometrically traces the ball's keyframe trajectory.
SP-A (marshmallow)
- Not used. Marshmallow's aesthetic is vector-clean, no doodles.
SP-C (editorial-cinematic)
- Not used. Editorial pack uses crop-marks and corner ornaments, not squiggles.
When to use
- Underline accent under a headline (SP-B, SP-G).
- Arrow callout pointing at a UI element (SP-B).
- Decorative squiggles around a logo lockup (SP-B, SP-E, SP-G).
- Motion-line trail tracing an element-handoff path (SP-G).
When NOT to use
- SP-A or SP-D — pack aesthetic doesn't include hand-drawn elements.
- More than 3 squiggles per scene (reads as clutter).
- As a primary subject (it's an accent, never a hero).
Quality Checks
- Path renders within canvas bounds at every frame.
- Stroke-dashoffset animation reaches 0 by
draw_start_frame + draw_duration_frames (line fully drawn).
- Arrow tip renders ON the end of the line, not floating nearby.
- Wobble amplitude is visible but not chaotic — viewer should perceive "drawn by hand" not "earthquake".
Failure Modes
- Line draws but never reaches its endpoint. Stroke-dasharray miscalculated. Verify
pathLength was measured after applying jitter.
- Wobble looks like a sine wave (too regular). Use perlin/simplex noise, not pure sin().
- Arrow tip points the wrong direction. Compute tangent at path end and orient triangle accordingly.
- Line clips at canvas edges. Constrain start/end + jitter to safe area (88% rect).