SVG, presets & building blocks
SVG without React
import { writeFileSync } from "node:fs";
import { toSvg } from "linescape";
const svg = toSvg(
[{ path: { through: "center", angle: -12 }, width: 220, paint: "#ffe3d3" }],
{ width: 1440, height: 900 },
);
writeFileSync("hero-lines.svg", svg);One <svg>, decorative (aria-hidden), with coordinates rounded to two decimals: the same lines at the same size always give the same bytes. Animations are included as CSS and SMIL inside the SVG.
| Option | Default | Meaning |
|---|---|---|
width, height | required | The element's size, in px. |
idPrefix | "linescape" | Prefix for ids, class names and keyframes. Give each SVG its own when inlining several into one page. |
precision | 2 | Decimal places for coordinates. |
motion | true | false leaves out undulation (SMIL), which CSS can't switch off for reduced motion. |
render() takes the same arguments and returns the SVG as a plain tree of nodes ({ tag, attrs, children }), which serialize() turns into a string. <Linescape> renders the same tree as React elements, so both always draw the same thing.
Presets
Hand-made starting points. Spread one and change what you like:
import { presets } from "linescape";
<Linescape line={{ ...presets.swoosh, paint: "#0a7" }} />band, swoosh, underline, ridgeline, swirl, stripes, ribbon, coil, zigzag, brush, frame, orbit, parallel, current, scribble. See them all on the home page.
Suggestions
import { suggest } from "linescape";
suggest({ seed: "hero" }); // any kind
suggest({ seed: 7, kind: "swirl" }); // band, sweep, squiggle, loops, swirl,
// ridges, stripes, brush, coil, frame
suggest({ seed: 8, keep: { path: myLine.path } }); // keep what you've settled onsuggest() generates a complete line from a seed: a starting point rather than a blank page. The result is a plain, static spec; print it, paste it and change it. Nothing is random when a line renders. The same seed always gives the same suggestion. The playground's Shuffle button is built on it, with locks for the parts to keep.
resolve()
resolve(line) fills every default and validates, returning the complete line as plain data. It's what the renderer works from, and what the playground edits. Invalid specs throw an error starting linescape: that names the field.
Building blocks
For drawing lines your own way: buildBackbone() (the path, measured by arc length), buildCurve() (with patterns and features), emit() (fitted path data), resolvePoint() and resolveLength() (positions), and parsePath().
Stability
The same spec and element size always produce the same output, on the server and in the browser. From 1.0, the same spec, size and major version produce byte-identical output: any change to generated output, presets and suggest() included, is a major release. Before 1.0, a minor version may still change output; patch versions never do.