feat(proxy): add offset param to inset or outset traced shapes

Trace results can now be inset (negative) or outset (positive) by a
pixel amount. Offset the outline and holes in opposite directions with
clipper-lib's miter joins, then recombine with a boolean difference so
holes grow on inset and shrink on outset. Collapsed shapes return an
empty outline; a split outline keeps the largest ring. Document the
parameter and the new dependency.
This commit is contained in:
2026-08-08 15:37:27 +08:00
parent c7f4bd03fd
commit 9094ad58e0
12 changed files with 284 additions and 17 deletions
+13 -6
View File
@@ -241,16 +241,23 @@ Hono server exposing search + fetch.
headers, which would block three.js loaders in the browser; routing through
the proxy makes those assets loadable. Only `http(s)` URLs are allowed.
- `routes/trace.ts`
- `GET /trace?url=...&mode=alpha&threshold=128&format=shape` — fetch an
image, trace it into a vector shape, and return the result BSON-encoded.
`mode` is `alpha` (default), `bw`, or `color`; `format` is `shape`
(default) or `svg`. `shape` returns a parsed `{ outline, holes }` polygon
matching `@tts/mesh`'s `Shape` interface, ready to extrude.
- `GET /trace?url=...&mode=alpha&threshold=128&format=shape&offset=...` —
fetch an image, trace it into a vector shape, and return the result
BSON-encoded. `mode` is `alpha` (default), `bw`, or `color`; `format` is
`shape` (default) or `svg`; `offset` (optional) insets (negative) or
outsets (positive) the shape in pixels. `shape` returns a parsed
`{ outline, holes }` polygon matching `@tts/mesh`'s `Shape` interface,
ready to extrude.
- `routes/svgShape.ts`
- `parseSvgShape(svg)` — parse a vtracer SVG into a `TracedShape`
(`{ outline, holes }`): flatten beziers to polylines, split subpaths into
rings, classify by winding (CCW outline / CW hole), and assign holes to
their containing outline.
- `offsetShape(shape, delta)` — inset/outset a `TracedShape` via
`clipper-lib` (Clipper miter joins); outline and holes offset in opposite
directions and are recombined with a boolean difference, so holes grow on
inset and shrink on outset. Collapsed shapes return an empty outline; a
split outline keeps the largest ring.
- `routes/health.ts`
- `GET /health` — liveness.
- `env.ts` — zod validation of `STEAM_API_KEY`, `PORT`.
@@ -309,7 +316,7 @@ proxy API and `packages/extract` directly for analysis.
| GET | `/items/:id` | Full parsed `TTSMod` (`?fileUrl=` skips key) | key* |
| GET | `/items/:id/file` | Raw save bytes, filename from header | key* |
| GET | `/asset?url=` | CORS-safe proxy for external assets | — |
| GET | `/trace?url=&mode=&format=` | Trace an image into a vector shape (BSON) | — |
| GET | `/trace?url=&mode=&format=&offset=` | Trace an image into a vector shape (BSON) | — |
\* `STEAM_API_KEY` is optional; `/items/*` works without it when a `fileUrl`
query param is supplied.