@parametron/svg — plan-view SVG renderer
The smallest reference renderer: it consumes the same one-shot contract as @parametron/three (Model.toScene() → SceneJSON) and returns a standalone SVG document string — the scene projected onto the XY plane (world Y up, flipped to SVG's y-down). No DOM, no dependencies: it runs in a Web Worker or Node just as well as in the browser, which makes it the natural adapter for 2D consumers — texture layouts (texturic), cut profiles, plans, .svg file export.
import { sceneToSvg } from "@parametron/svg"
const scene = model.toScene()
const svg = sceneToSvg(scene, {
background: "#a8a098",
fill: "#b2644e",
materialColors: { accent: "#4477aa" },
})
// display: <img src={"data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg)}>
// or save as a .svg file — the string is a complete document.What each scene entity becomes
| SceneJSON | SVG output |
|---|---|
SceneNode | <g id="key"> — the SVG keeps the model's node tree (empty groups are skipped, duplicate keys deduped) |
Mesh from a planar face | one <path fill-rule="evenodd"> — boundary loops (profile + holes), not triangles |
Mesh from a closed solid | <path fill-rule="nonzero"> of projected triangles — the filled silhouette |
Curve (already a polyline) | <polyline fill="none"> |
Point | <circle> |
Face fill uses SVG's own cascade: the root <svg> carries the default fill, a node with a material puts fill on its <g>, and an entity with its own material overrides on the element — which is exactly the nearest-ancestor material rule SceneJSON specifies, enforced by the format itself. Opening the file in Inkscape/Illustrator/Figma shows the model structure, and recoloring a group recolors its subtree.
Faces come out as clean outline paths because the renderer re-derives the tessellation boundary: an edge used by exactly one triangle lies on the face border, and chaining those edges reconstructs the exact profile and hole loops. A closed solid has no boundary edges, so it degrades to its silhouette (interior triangle edges cancel pairwise under nonzero fill — no seams).
Options
All geometry is in world units (mm).
viewBox— explicit world-space window (Y up); defaults to scene bounds.padding— extra world units around auto bounds.background— backdrop<rect>color; omitted → transparent.fill/stroke/strokeWidth— defaults when no material color resolves.materialColors—SceneJSONreferences materials by name only (bodies live in the Store); map names to CSS colors here.pointRadius— point marker radius.
Material resolution follows the scene contract: an entity's own material, else the nearest ancestor node's — same nearest-ancestor rule the Three.js renderer applies.