Architecture
One geometry source
You must follow a single data flow:
Config (parameter object) → pure render → geometry IR → 2D canvas / 3D view / exported file
The 3D view must consume the same geometry IR as the 2D canvas and the exported file. Do not write a second geometry pipeline on the 3D side — the preview and the export will drift apart.
Coordinate systems
Each rendering space uses the conventions below, and they must be documented in one place rather than rediscovered per file:
| Space | Unit / origin / axes |
|---|---|
| IR (canonical space) | mm, centred at (0,0), Y down (2D — no Z) |
| 3D (three.js) | mm, Y up, Z is thickness |
Outlines are built in the XY plane and extruded along +Z, so the part faces the camera. Flip IR to Y-up by mirroring, not rotating — set group.scale.y = -1 once, on the content group; rotating it flat moves thickness onto another axis.
Two ways the flip goes wrong:
- One part is upside-down and mirrored while everything around it is correct — that mesh set
scale.yitself. It already inherits the group's flip, so the second one cancels it. - Every face renders inside-out — the flip was applied to the geometry (
geometry.scale(1, -1, 1)). three.js compensates the winding order frommatrixWorldat the object level only; there is no compensation at the geometry level.
Path conversion
SVG paths for text and complex shapes must go through new SVGLoader().parse() and SVGLoader.createShapes() to become a THREE.Shape — that path applies the fill rule correctly, so holes and letter counters come out right — and then through ExtrudeGeometry. Do not write your own SVG path parser.