# Construct geometry

Reads a freehand stroke — resampled by arc length, measured into a frame, classified into an archetype — and forges it into a filled construct, with the draw it costs.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/construct-geometry.json
```

Registry item: `construct-geometry` · [`https://robocn.dev/r/construct-geometry.json`](https://robocn.dev/r/construct-geometry.json)

## Notes

- Pure functions over plain objects: no React, no three.js, no dependencies.
- The measurement and the classification are solved; the archetype outlines are drawings — a glove is a glove because it is drawn as one, not because a fist was solved.
- No stroke is kept. What survives a gesture is the seven numbers of its frame.

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `resampleStroke(points, count?)` | `(points: Vec2[], count?: number) => Vec2[]` | — | The stroke, evenly spaced by arc length. A pointer emits points at its own rate, so nothing downstream can be trusted until this has run. Non-finite points are dropped and a click comes back as a point rather than a division by zero. |
| `strokeFrame(points, count?)` | `(points: Vec2[], count?: number) => StrokeFrame` | — | Centroid, the principal axis from the samples' covariance, the spans along and across it, path length, closure, enclosed area, circularity 4πA/P², corner count and total turning. Never returns NaN. |
| `classifyStroke(frame)` | `(frame: StrokeFrame) => StrokeVerdict` | — | Which construct the stroke is asking for, with a score for every archetype so a near miss reads as a near miss. It always names one. |
| `constructOutline(archetype, frame?, options?)` | `(archetype: ConstructArchetype, frame?: StrokeFrame, options?: { scale?: number }) => Vec2[]` | — | The archetype fitted to the stroke's frame: scaled to its spans, turned onto its principal axis, centred on its centroid. An unknown archetype falls back to a bubble. |
| `constructLattice(outline, options)` | `(outline: Vec2[], options: { spacing: number; angle?: number }) => [Vec2, Vec2][]` | — | The fill lines, each one the real intersection of the outline with a line at the given rake, so the hatch follows the shape. A spacing that could not terminate returns nothing. |
| `constructCost(outline)` | `(outline: Vec2[]) => number` | — | What holding the construct draws from the reserve, 0 to 1, proportional to the area it encloses. |
| `constructSettle(age, duration)` | `(age: number, duration: number) => number` | — | How solid a construct is at `age`: in over the first fifth, held, let go over the last third, and nothing outside its own life. |
| `forgeConstruct(points, options?)` | `(points: Vec2[], options?: ForgeOptions) => ForgedConstruct` | — | A raw pointer path all the way to something drawable: frame, verdict, outline, lattice and cost. |
| `polygonArea(points)` | `(points: Vec2[]) => number` | — | Shoelace area, 0 for anything that is not a polygon. |
| `constructArchetypes` | `readonly ConstructArchetype[]` | — | bubble, shield, cage, glove, hammer, bridge, claw. |

## Source

- `src/lib/robocn/construct.ts`
