Import a brick set
Work from the repository root. The useful precedent is sources/10416-1.json, src/farmInventory.ts, docs/farm-10416.md, and tests/farm.test.ts. Read only the relevant files. This workflow changes the catalog and connection engine; importing a set does not authorize replacing the user's live assembly.
Inventory and identity
- Start with the exact set number and LEGO's instruction PDF. Its last inventory page is often more reliable than a replacement-parts feed, which can include alternates. Render the assembly pages too: a list of part names does not reveal attachment behavior.
- Cross-check the rows against a parts catalog. Save a compact source snapshot in
sources/ with part/design number, color, quantity, LEGO element ID, source URLs, reviewed date, and any count discrepancy. Count figures, exclude spares unless requested, and assert the total.
- Match existing design + color + print/mold variant, not names. DUPLO
40666 is the catalog's 4538; 76371 maps to 4066. Keep existing public part IDs and saved anchors. Different printed designs or real mold differences remain distinct even when their base CAD is shared.
- Keep quantities per kit.
collectionInventory() sums identical IDs across kits; do not pre-sum shared counts or mutate INVENTORY. Add the kit to KITS and its part entries to PARTS. Reuse existing connection metadata when adding only a color.
CAD import
- Check the official LDraw complete archive, cached at the platform temp path
lego-ldraw-complete.zip. A quick Python zipfile scan of ldraw/parts/*.dat headers finds design aliases without downloading individual files. Check aliases and decorated variants before declaring a model absent. Do not use a similarly named standard LEGO animal in place of a DUPLO animal.
- Extend
scripts/fetch-ldraw.py's selected IDs from the pinned source snapshot, then run it with the archive path. It recursively extracts type-1 subfile references, retains license headers, and builds the local file map. Keep its path-traversal guard and licensing files.
- Compile only added/changed IDs with
npx tsx scripts/compile-cad.ts --parts=id1,id2. This merges into the existing bundle and updates both dimension files. A full rebuild is unnecessary for additions and can churn unrelated models.
- The compiler uses
0.025 scene units/LDU for DUPLO, 0.05 for standard LEGO. Do not put DUPLO IDs in manifest.legoParts. DUPLO layers are 0.6 scene units; standard LEGO plates are 0.4.
- Models missing from the licensed library need original, clearly marked approximate meshes. Use instruction/part photographs as shape references; give each distinct animal or utility item recognizable geometry. A generic rectangular fallback is not a finished specialty model. Do not claim approximations are imported CAD.
Connections, orientation, and clearance
For every unique design, record top studs, bottom sockets, their heights, non-stud fittings, hollow clearances, evidence, and remaining uncertainty. All color variants inherit the design rules.
- Use
topStudAreas / bottomStudAreas for discrete regions and y for raised sockets or lower shelves. A roof's slope, pot rim, animal head, and pane bars are not studs.
- Run
npx tsx scripts/audit-duplo.ts --farm --write for the 10416 precedent (extend the selector for a new set). It recursively transforms actual stud7.dat references into the rendered coordinate system and compares positions and heights, not only counts. For standard LEGO use the LEGO audit scripts.
- The renderer normalizes CAD bounds, auto-rotates long axes, centers X/Z, then applies
cadOffset. Asymmetrical features can move the visual center away from the stud grid. The two door frames need cadOffset.x = 0.075; do not infer their alignment from bounding-box dimensions alone.
- Use local CAD primitive transforms to derive mating positions. Example: 10416's tall frame sockets are at different heights than the short frame's. The correct fit has a fractional layer offset even though ordinary DUPLO bricks use integer layers.
fits offsets describe the child's entire footprint at host rotation zero; fittingCandidates() rotates that footprint and the child's orientation. requiresFit prevents a hinge insert from being accepted as a ground brick. Named slot values prevent two children occupying one hand or hinge fitting.
- Do not impose integer-only schema checks before the host is known. The assembly validator accepts exact registered fits and aligned centered sockets, while rejecting arbitrary off-grid placement.
- Use
collisionVolumes to preserve arch openings, furniture legs, basins, and space below hanging parts. A single bounding box can prevent valid connections. Conservative envelopes are acceptable when identified; a blanket collision exemption is only for an exact mating transform.
- Model resting separately from clutch connections. The farm grooming tile supports animals without acquiring fictitious studs.
- Engine support and viewport snapping must agree. A connection reachable only through the API is incomplete UI support. Check all quarter-turn orientations and reject wrong hosts, shifted fits, occupied slots, and removal of needed supports.
Verify and finish
Run focused assembly tests, the independent CAD stud audit, then npm test and npm run build. Include tests for total inventory, shared-color deduplication, print identity, required fittings, clearances, and save/load behavior. Check actual rendered specialty models and representative clicks in a browser. Use a separate PORT and temporary DUPLO_DATA_DIR for destructive fixtures; supply the current expectedRevision on HTTP commands. Preserve user data and unrelated dirty changes.
Document a complete per-design checklist and specific approximations in docs/. Report separately: imported CAD count, original fallback models, implemented connection behavior, verification, and any remaining motion/pose limitations.
1---2name: import-brick-set3description: Import a LEGO or DUPLO set into this playground, deduplicate its inventory and CAD models, and audit how every specialty part connects and renders.4---56# Import a brick set78Work from the repository root. The useful precedent is `sources/10416-1.json`, `src/farmInventory.ts`, `docs/farm-10416.md`, and `tests/farm.test.ts`. Read only the relevant files. This workflow changes the catalog and connection engine; importing a set does not authorize replacing the user's live assembly.910## Inventory and identity1112- Start with the exact set number and LEGO's instruction PDF. Its last inventory page is often more reliable than a replacement-parts feed, which can include alternates. Render the assembly pages too: a list of part names does not reveal attachment behavior.13- Cross-check the rows against a parts catalog. Save a compact source snapshot in `sources/` with part/design number, color, quantity, LEGO element ID, source URLs, reviewed date, and any count discrepancy. Count figures, exclude spares unless requested, and assert the total.14- Match existing **design + color + print/mold variant**, not names. DUPLO `40666` is the catalog's `4538`; `76371` maps to `4066`. Keep existing public part IDs and saved anchors. Different printed designs or real mold differences remain distinct even when their base CAD is shared.15- Keep quantities per kit. `collectionInventory()` sums identical IDs across kits; do not pre-sum shared counts or mutate `INVENTORY`. Add the kit to `KITS` and its part entries to `PARTS`. Reuse existing connection metadata when adding only a color.1617## CAD import18191. Check the official LDraw complete archive, cached at the platform temp path `lego-ldraw-complete.zip`. A quick Python `zipfile` scan of `ldraw/parts/*.dat` headers finds design aliases without downloading individual files. Check aliases and decorated variants before declaring a model absent. Do not use a similarly named standard LEGO animal in place of a DUPLO animal.202. Extend `scripts/fetch-ldraw.py`'s selected IDs from the pinned source snapshot, then run it with the archive path. It recursively extracts type-1 subfile references, retains license headers, and builds the local file map. Keep its path-traversal guard and licensing files.213. Compile **only added/changed IDs** with `npx tsx scripts/compile-cad.ts --parts=id1,id2`. This merges into the existing bundle and updates both dimension files. A full rebuild is unnecessary for additions and can churn unrelated models.224. The compiler uses `0.025` scene units/LDU for DUPLO, `0.05` for standard LEGO. Do not put DUPLO IDs in `manifest.legoParts`. DUPLO layers are `0.6` scene units; standard LEGO plates are `0.4`.235. Models missing from the licensed library need original, clearly marked approximate meshes. Use instruction/part photographs as shape references; give each distinct animal or utility item recognizable geometry. A generic rectangular fallback is not a finished specialty model. Do not claim approximations are imported CAD.2425## Connections, orientation, and clearance2627For **every unique design**, record top studs, bottom sockets, their heights, non-stud fittings, hollow clearances, evidence, and remaining uncertainty. All color variants inherit the design rules.2829- Use `topStudAreas` / `bottomStudAreas` for discrete regions and `y` for raised sockets or lower shelves. A roof's slope, pot rim, animal head, and pane bars are not studs.30- Run `npx tsx scripts/audit-duplo.ts --farm --write` for the 10416 precedent (extend the selector for a new set). It recursively transforms actual `stud7.dat` references into the rendered coordinate system and compares **positions and heights**, not only counts. For standard LEGO use the LEGO audit scripts.31- The renderer normalizes CAD bounds, auto-rotates long axes, centers X/Z, then applies `cadOffset`. Asymmetrical features can move the visual center away from the stud grid. The two door frames need `cadOffset.x = 0.075`; do not infer their alignment from bounding-box dimensions alone.32- Use local CAD primitive transforms to derive mating positions. Example: 10416's tall frame sockets are at different heights than the short frame's. The correct fit has a fractional layer offset even though ordinary DUPLO bricks use integer layers.33- `fits` offsets describe the child's entire footprint at host rotation zero; `fittingCandidates()` rotates that footprint and the child's orientation. `requiresFit` prevents a hinge insert from being accepted as a ground brick. Named `slot` values prevent two children occupying one hand or hinge fitting.34- Do not impose integer-only schema checks before the host is known. The assembly validator accepts exact registered fits and aligned centered sockets, while rejecting arbitrary off-grid placement.35- Use `collisionVolumes` to preserve arch openings, furniture legs, basins, and space below hanging parts. A single bounding box can prevent valid connections. Conservative envelopes are acceptable when identified; a blanket collision exemption is only for an exact mating transform.36- Model resting separately from clutch connections. The farm grooming tile supports animals without acquiring fictitious studs.37- Engine support and viewport snapping must agree. A connection reachable only through the API is incomplete UI support. Check all quarter-turn orientations and reject wrong hosts, shifted fits, occupied slots, and removal of needed supports.3839## Verify and finish4041Run focused assembly tests, the independent CAD stud audit, then `npm test` and `npm run build`. Include tests for total inventory, shared-color deduplication, print identity, required fittings, clearances, and save/load behavior. Check actual rendered specialty models and representative clicks in a browser. Use a separate `PORT` and temporary `DUPLO_DATA_DIR` for destructive fixtures; supply the current `expectedRevision` on HTTP commands. Preserve user data and unrelated dirty changes.4243Document a complete per-design checklist and specific approximations in `docs/`. Report separately: imported CAD count, original fallback models, implemented connection behavior, verification, and any remaining motion/pose limitations.