21

I love flow fields but canvas ones get blurry when someone zooms the page or exports to print. I wanted the same look as pure SVG paths so it stays vector-crisp forever.

My naive prompt drew thousands of tiny <line> segments and the DOM died. The fix was telling the model to integrate each streamline into ONE <path> with many points, cap the path count, and animate with stroke-dashoffset instead of redrawing. I also insisted on a seeded RNG so a nice field could be reproduced.

Any tricks for varying stroke width along a single path without splitting it into segments?

THE PROMPT
Generate a single inline SVG (plus a small inline <script>) that renders an animated flow field as vector streamlines. Constraints:
- Seeded PRNG (mulberry32 from a `seed` const) drives everything; no Math.random.
- Vector field: angle at (x,y) = fbm-ish value noise * TAU; implement lightweight value noise in JS.
- Trace exactly {LINES} streamlines (default 240), each integrated with RK2 steps for up to 200 points, and emit each as ONE `<path>` with a smooth `d` (use Catmull-Rom to Bezier). BANNED: one <line> per segment.
- Color each path by its starting angle via HSL; thin strokes (0.6-1.4px) with `stroke-linecap='round'`.
- Animate a 'drawing on' effect using stroke-dasharray/stroke-dashoffset with staggered delays, respecting prefers-reduced-motion (show final static state).
- viewBox 0 0 1000 1000, no external libs.
Report the total path count and confirm it stays under 300 nodes so the DOM stays light.
3Catmull-Rom to bezier for the path d is what makes these read as hand-drawn rather than jagged. good detail to pin down.gradient_grace 2 months ago
add a comment

2 Answers

14

RK2 for streamlines in SVG is a good tradeoff. For variable stroke width along one path without splitting: you can't with plain stroke, but you can convert the centerline to a filled polygon by offsetting normals left/right by your width function and closing it. One <path> fill, tapered ends, still crisp.

THE PROMPT
Instead of stroking, for each streamline build a filled ribbon: offset each point by +/- (width(t)/2) along the local normal, concatenate the left edge forward and right edge backward into one closed path, and fill it. width(t) can taper with sin(t*PI).
12

Counterpoint from the canvas side: if you don't actually need infinite zoom, a canvas flow field at 2x DPR exports fine to PNG and handles 5x the line count. SVG is the right call only if vector export or CSS-driven animation is a hard requirement. Worth naming that tradeoff in the prompt.

Your Answer