Shape Studio
Draw a shape on the dot grid and turn it into a <NeuShape>-ready path. Edit moves
vertices; Clear starts blank. Snap toggles 1 / ½ unit, and Undo / Redo
(⌘Z / ⌘⇧Z) go back up to 10 steps. Begin from a Template, a generator, or build your own.
- Select a point or a line — click a vertex to select it, Shift-click to select several, then drag any one to move the whole group. Click an edge to select that line (drag to move it). With a line selected, + Point on line drops a new vertex at its centre.
- Exact side lengths — click a length label on the canvas (or the Length field) and type the value you want. Combined with the Polygon / Star generators (set Sides first), equilateral triangles, pentagons, hexagons and stars are one click.
- Per-vertex type — each vertex is a Corner (straight edges, rounded by its radius — convex fillets and concave notches) or Smooth (the curve passes through it). One shape can mix both. All → Corners / Smooth flips every vertex; Smoothing sets curve looseness.
- Outline — turns the shape into a single even-odd band path: the ring between the shape and its outward offset (its own path, set the Width), rather than the solid fill.
- Fill — the neumorphic surface, a theme gradient, or an image clipped to the shape (paste any URL). The preview on the right shows the finished composition.
- Export — copy a
<NeuShape>snippet, copy the raw pathd, or Download SVG (a self-contained file with the theme colours baked in).
0.5
The engine is lib/shape-path.ts — a single pass turns the polygon into a path, and a
corner's turn direction decides whether its arc bulges out (convex) or scoops in
(concave), so notches need no special handling. Use it in code, too:
import { roundedPath, pathBounds } from '@/lib/shape-path'
const pts = [
{ x: 2, y: 2, r: 1 }, { x: 16, y: 2, r: 1 }, { x: 16, y: 11, r: 1 },
{ x: 11, y: 11, r: 2 }, { x: 11, y: 7, r: 1 }, { x: 7, y: 7, r: 1 },
{ x: 7, y: 11, r: 2 }, { x: 2, y: 11, r: 1 },
]
const d = roundedPath(pts, { defaultRadius: 1 })
const { viewBox } = pathBounds(pts, 1.5)
// <NeuShape viewBox={viewBox} d={d} variant="raised" />