an.stage.path_wobble#
A hand-drawn wobble for stroked paths, applied at compile time (an#161).
A ruled line reads as a diagram; a line that wanders a little reads as drawn
by hand. The wobble displaces the FLATTENED polyline sideways (along its
normal) by a smooth seeded noise, before it reaches the wire, so the runtime
and its parity spec (an.stage.path_geometry) never learn about it:
trim, dashes and arrowheads work on the wobbly polyline exactly as on any
other.
Deterministic everywhere. The noise is value noise over knots one wavelength apart, each knot’s value read from
sha256(seed:k), joined by a cubic smoothstep: only+ - * /,floorandsqrt, no trigonometry, so the compiled points are the same bytes on every machine.Seeded by the entity (
"<entity id>:<wobble_seed>"), like a character’s blink phase: two arrows sharing one document wobble differently, and the same arrow wobbles the same way every render.The ends stay put. The amplitude ramps up over the first and down over the last wavelength, so a route still starts and ends where it was drawn to, and an arrowhead’s tip lands on its target.
Static. One displacement per path. A boil (a wobble that changes on twos) is several displaced polylines on a step channel; not built.
>>> pts = wobble_polyline([(0.0, 0.0), (200.0, 0.0)], amplitude=4.0, wavelength=50.0, seed="route:0")
>>> pts[0], pts[-1] # the ends are where they were
((0.0, 0.0), (200.0, 0.0))
>>> 0.0 < max(abs(y) for _, y in pts) <= 4.0
True
>>> pts == wobble_polyline([(0.0, 0.0), (200.0, 0.0)], amplitude=4.0, wavelength=50.0, seed="route:0")
True
Module Attributes
enough that the wobble reads as a curve, not a zig-zag, at any amplitude a stroke should take. |
|
The most points a wobbled path may carry. |
Functions
|
|
|
|
|
How many samples a wobble of |
- an.stage.path_wobble.MAX_WOBBLE_POINTS: int = 20000#
The most points a wobbled path may carry. Every point is redrawn each frame a trim or dash moves; past this the wavelength is too short for the path’s length (a hair-fine wobble over a long route).
- an.stage.path_wobble.WOBBLE_SAMPLES_PER_WAVELENGTH: int = 8#
enough that the wobble reads as a curve, not a zig-zag, at any amplitude a stroke should take.
- Type:
Samples per wavelength of the noise
- an.stage.path_wobble.wobble_point_count(length, wavelength)[source]#
How many samples a wobble of
wavelengthputs alonglengthpx.- Return type:
- an.stage.path_wobble.wobble_polyline(points, *, amplitude, wavelength, seed)[source]#
pointsresampled and wobbled; seewobble_with_vertices().
- an.stage.path_wobble.wobble_with_vertices(points, *, amplitude, wavelength, seed)[source]#
pointsresampled everywavelength / 8px and each sample moved up toamplitudepx along the path’s normal by seeded smooth noise.The original vertices are kept as samples (a corner stays a corner) and move along the bisector of their two legs. Raises
ValueErrorwhen the result would carry more thanMAX_WOBBLE_POINTSpoints.Also returns, for each input point, its index in the output (where a vertex landed), so a caller can find the authored points on the wobbled line (
an.stage.paths.drawn_polyline()).