Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e9c241b
Research laser and fold output, with a headless sheet prototype
somebox Oct 27, 2026
a40e145
Add a clickable Cut and Fold mockup to the app behind ?sheet
somebox Oct 28, 2026
e6bdf73
Keep three.js inside viewer.js: the sheet mockup hands it plain data
somebox Oct 28, 2026
80db3e5
Fix what interactive testing of the sheet mockup turned up
somebox Oct 28, 2026
2135a9f
Round the clips that show through openings, and add printed clips
somebox Oct 28, 2026
db1fa0d
One rule for joints and openings, finger joints, clip options, weldin…
somebox Oct 29, 2026
63f95e2
Sew felt with seams: allowances on both pieces, darts, valley seams
somebox Oct 30, 2026
500409d
sheet: split net growth and seam rules out of fold, break the import …
somebox Oct 31, 2026
e3c0d6c
Add the production layer, one CLI, and a mockup that only draws the p…
somebox Oct 31, 2026
d78d52f
docs: separate research from the spec, and write down the production …
somebox Oct 31, 2026
7ac2489
cards: add the release epic and stories, move the 2D output story to …
somebox Oct 31, 2026
8fb909a
Fix what an independent review of the production layer found
somebox Oct 31, 2026
c466700
cards: record the review fixes
somebox Oct 31, 2026
7b70605
Accept the release decisions, and clear out leftovers
somebox Nov 1, 2026
17c0aa0
sheet: stop rounding noise from choosing the layout
somebox Nov 1, 2026
82722ab
docs: choose the four-tab panel and plan its rebuild
somebox Nov 1, 2026
e6d0518
panel: move the rows into four tabs
somebox Nov 1, 2026
f671818
panel: replace the three-column row with one field
somebox Nov 1, 2026
e54584d
panel: put status beside the rows and files in one list
somebox Nov 1, 2026
6f434b4
panel: lay the tabs out for phones and sideways
somebox Nov 1, 2026
73288dc
docs: describe the four-tab panel
somebox Nov 1, 2026
67d553b
cards: record the panel stages
somebox Nov 1, 2026
028dee8
cards: link the panel story to its pull request
somebox Nov 1, 2026
51a1214
panel: fix the review's touch, status and split download issues
somebox Nov 1, 2026
1a1c3cc
sheet: fix the review's Undo, stitch, thumbnail and keyboard issues
somebox Nov 1, 2026
8d9a554
Merge sheet-output-research into panel-tabs
somebox Nov 1, 2026
c023aa2
sheet: fix the review's history, strip, picture and loading issues
somebox Nov 2, 2026
1292715
Merge sheet-output-research into panel-tabs
somebox Nov 2, 2026
8d43e37
panel: fix the review's touch, header and weld status issues
somebox Nov 2, 2026
0ee1422
sheet: fix the review's plate name, save and print bed issues
somebox Nov 2, 2026
b9fd028
Merge sheet-output-research into panel-tabs
somebox Nov 2, 2026
7e53f1b
Merge main into panel-tabs
somebox Nov 2, 2026
c8975b7
panel: fix the review's stale files, tab scroll, mark and edit warnin…
somebox Nov 2, 2026
0aac1dc
panel: hide the last good model's measurements while a build fails
somebox Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions .cards/backlog.jsonl

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ __pycache__/
# Generated files.
!prototype/icosidodecahedron_100mm_TPU.stl
test/out/
out/
.claude/scheduled_tasks.lock
.pi-subagents/artifacts/*
.pi-subagents/
54 changes: 46 additions & 8 deletions DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,37 @@ node scripts/export-stl.mjs out.stl --wall=2.0 --border=4 --fillet=4.5
node scripts/export-stl.mjs out.stl --base=dodecahedron --depth=solid --openings=false
```

Cut sides (`openingAxis: "through"`) run on the manifold-3d WebAssembly
### Command line

`scripts/shapemaker.mjs` runs any process on any design, by the same path as
the app:

```bash
node scripts/shapemaker.mjs plan docs/examples/cut-cube-fingers.shapemaker.json
node scripts/shapemaker.mjs build --base=cube --diameter=140 --process=cut --join=ties --out=out/cube
node scripts/shapemaker.mjs build design.shapemaker.json --process=fold --join=sew --fix --pictures
node scripts/shapemaker.mjs settings --process=cut # every setting and its range
node scripts/build-examples.mjs # docs/examples → test/out/examples/index.html
```

`plan` writes nothing and takes `--json`. `build` also writes `manifest.json`.
Exit codes: 0 done, 1 the design doesn't build, 2 usage.

### Production and the sheet engine

`compile()` makes the shape and printed shell; `src/production/` turns a shape
and a job into files; `src/sheet/` is the laser and fold engine under it. In
the app, Cut and Fold run only as a mockup: add `?sheet` to the URL to get the
Build switch, the Flat view and their files in the Files tab
(`src/sheet-mockup.js`). The
design, the layer rules and the decisions for the first release are in
[docs/PRODUCTION.md](docs/PRODUCTION.md). To add a setting, add a row to
`JOB_DEFS` in `src/production/job.js`: the panel, flags and file format follow.

Through sides (`openingAxis: "through"`) run on the manifold-3d WebAssembly
library, which loads on demand. Scripts that call `compile()` on such a state
`await loadCsg()` from `src/solid/csg.js` first; `export-stl.mjs` does this
when the flags ask for Cut.
when the flags ask for Through.

## Canonical state

Expand All @@ -81,12 +108,12 @@ files, the URL hash, and dirty tracking.
|---|---|---|
| `base` | `icosidodeca` | shape family id (`BASES` in `src/bases.js`) |
| `circumdiameterMm` | 100 | outer diameter across opposite vertices |
| `borderFraction` | 0.36 | frame width ÷ face apothem (Form %); legacy `borderMm` via `--border=` |
| `borderFraction` | 0.36 | frame width ÷ face apothem (Openings %); legacy `borderMm` via `--border=` |
| `wallMm` | 1.4 | minimum wall thickness |
| `wallMode` | `even` | Inner wall: `even` (face planes offset by the wall) or `scaled` (uniform scale about the origin); absent in a link or project → `scaled` |
| `openingStyle` | `polygon` | `polygon` (inset + fillet) or `ellipse` (inscribed oval) |
| `openingAxis` | `center` | Sides: `center` Tapered (origin ray), `normal` Straight (along the face normal; tilts only beside a tight inner edge) or `through` Cut (straight cut by mesh boolean; holes may merge) |
| `breakOut` | `false` | Cut only: holes may cut through neighbouring faces' outsides; loose pieces are dropped |
| `openingAxis` | `center` | Sides: `center` Tapered (origin ray), `normal` Straight (along the face normal; tilts only beside a tight inner edge) or `through` Through (straight cut by mesh boolean; holes may merge) |
| `breakOut` | `false` | Through only: holes may cut through neighbouring faces' outsides; loose pieces are dropped |
| `filletMm` | 4.5 | requested opening corner radius; clamped per face; inert under `ellipse` |
| `jitter` | 0 | distort amount |
| `dual` | false | polar dual (faces ↔ vertices, re-hull with merge) |
Expand Down Expand Up @@ -137,10 +164,14 @@ src/
solid/spike.js face pyramids / dimples (origin-star-convex)
export/stl.js binary STL writer
export/svg.js camera-projected SVG
sheet/ laser and fold engine: panels, cut, fold, unfold, seams, layout, svg, assembly
production/ shape + job → files: job schema, produce(), listArtifacts(), summarize()
sheet-mockup.js Cut and Fold panel behind ?sheet; flat-view.js draws the boards
viewer.js only module that imports Three.js
prototype/ Python reference (meshcheck, original generator)
test/ node --test + fixtures
scripts/ export-stl.mjs, acceptance.sh
test/ node --test + fixtures; mini-dom.js runs the real panel
scripts/ shapemaker.mjs (CLI), export-stl.mjs, acceptance.sh, build-examples.mjs (+ lib/)
docs/ spec, roadmap, production design, examples/, research/
```

`solid/shell.js` learns the polyhedron only through `skeleton.js` and
Expand Down Expand Up @@ -171,13 +202,20 @@ from a branch" — `docs/` is documentation, not the site root.

- Geometry modules must not import Three.js; the pipeline runs under
`node --test`.
- `compile(state)` is the only regeneration API.
- `compile(state)` is the only regeneration API; `compileShape(state)` is the
same path without the shell.
- `src/production/` and `src/sheet/` must not touch the DOM or a viewer, and the
shape pipeline must not import them (`test/production.test.js` checks).
- What a design makes is `listArtifacts()`, for the app and the CLI alike.
- Product razor: a change should improve physical design, fabrication handoff,
or the experience of creating interesting forms; otherwise it waits.

## Further docs

- [`docs/SPEC.md`](docs/SPEC.md) — product behavior and architecture
- [`docs/PROJECT_FORMAT.md`](docs/PROJECT_FORMAT.md) — portable projects
- [`docs/PRODUCTION.md`](docs/PRODUCTION.md) — shape vs production, and first-release decisions
- [`docs/examples/`](docs/examples/) — designs for each output, and test cuts
- [`docs/research/`](docs/research/sheet-output.md) — research notes, not binding
- [`docs/ROADMAP.md`](docs/ROADMAP.md) — future work
- [`docs/CHANGELOG.md`](docs/CHANGELOG.md) — releases
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Open the [live app](https://somebox.github.io/shapemaker/). No install is
required. On first visit, a short tip walks through the loop:

1. **Pick a start** — choose a built-in shape from the Start from row.
2. **Adjust** — tune Size, Form (hollow/solid, wall, border, fillet), and
optional distort (jitter, dual, truncate, spike, subdivide, smooth).
2. **Adjust** — the tabs hold Shape (size, jitter, dual, truncate, spike,
subdivide, smooth), Openings (border, fillet) and Build (hollow/solid, wall).
3. **Click a face** — set which side rests on the print bed.
4. **Export** — download STL for the slicer, or SVG for a clean outline.
4. **Export** — the Files tab has the STL for the slicer and an SVG outline.

Share a design with the **Share** control (copies a link that restores the
same settings). **Export** / **Load** under JSON Model File save and reopen
Expand All @@ -30,9 +30,9 @@ a `.shapemaker.json` project on your machine.
|---|---|---|
| [![Hidden-line SVG export](media/example-export.png)](media/example-export.svg) | [![Rendered STL export](media/example-stl-render.png)](media/example-export.stl) | [![Prusaslicer screenshot](media/prusa-slicer-screenshot-thumb.png)](media/prusa-slicer-screenshot.png) |

- **Export STL** — binary mesh in millimetres, already oriented to the resting
- **STL** — binary mesh in millimetres, already oriented to the resting
face. Filenames include size (and seed / point count when those matter).
- **Export SVG** — camera-matched hidden-line drawing (silhouette and crease
- **SVG** — camera-matched hidden-line drawing (silhouette and crease
edges), editable in vector tools.

Optional **Print risk** and **Section** tools sit on the viewport: overhang /
Expand All @@ -42,13 +42,14 @@ flat-bridge overlays, and a height clip to inspect cavities.

| Area | Controls |
|---|---|
| Start | Platonic solids, icosidodecahedron, cuboctahedron, rhombicosidodecahedron, rhombic 12/30/90, globe, twisted globe, sphere, random hull; named star and ring-ball presets |
| Size | Overall diameter; Edge length on regular shapes |
| Form | Hollow or solid, wall, rounding; openings: open or closed faces, polygon or ellipse outline, border, fillet, tapered / straight / cut sides; advanced: inner wall (even or scaled about the centre), break out |
| Distort | Jitter (amount, direction, seed), dual, truncate, spike, subdivide, smooth |
| Make | Resting face, mesh quality (Draft / Normal / Fine), material / mass estimate |

**Ring balls.** Turn **Dual** on and set **Opening** to Ellipse: Dual swaps
| Shape: start | Platonic solids, icosidodecahedron, cuboctahedron, rhombicosidodecahedron, rhombic 12/30/90, globe, twisted globe, sphere, random hull; named star and ring-ball presets |
| Shape: size | Overall diameter; Edge length on regular shapes |
| Shape: distort | Jitter (amount, direction, seed), dual, truncate, spike, subdivide, smooth |
| Openings | Open or closed faces, polygon or ellipse outline, border, fillet |
| Build | Hollow or solid, wall, rounding, tapered / straight / through sides, mesh quality (Draft / Normal / Fine), resting face, material / mass estimate; advanced: inner wall (even or scaled about the centre), break out |
| Files | STL, SVG and project files, geometry detail, share link |

**Ring balls.** Turn **Dual** on and set **Outline** to Ellipse: Dual swaps
faces for vertices, so a triangulated sphere becomes pentagon and hexagon
cells, and each cell opens with its largest inscribed oval. Neighbouring rings
meet along a short neck. The *Ring ball* and *Ring lantern* presets start
Expand Down Expand Up @@ -82,6 +83,7 @@ MIT — see [`LICENSE`](LICENSE).
| [`DEV.md`](DEV.md) | Developing, testing, CI, and project layout |
| [`docs/SPEC.md`](docs/SPEC.md) | Product behavior and architecture |
| [`docs/PROJECT_FORMAT.md`](docs/PROJECT_FORMAT.md) | `.shapemaker.json` files |
| [`docs/PRODUCTION.md`](docs/PRODUCTION.md) | Laser-cut, folded and sewn output: design and plans |
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Future ideas and backlog |
| [`docs/CHANGELOG.md`](docs/CHANGELOG.md) | Released versions |

Expand Down
27 changes: 27 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@ surface is still moving, and git history is the detailed record. From **1.0**
onward every release gets a full entry here, and breaking changes to the
[project format](PROJECT_FORMAT.md) get a migration note.

## Unreleased

### Changed

- Sides option **Cut** is now **Through**, to leave the word Cut for laser
cutting. Saved designs and links are unaffected: the stored value was
already `through`.
- **The panel is four tabs**: Shape, Openings, Build and Files, replacing
Shape, Form and Make. Each tab's caption shows its current value. Everything
only a printed shell reads is in Build, and the project's name and Undo move
to the header. Saved designs and links are unaffected.
- **Fields are more compact**: label and value sit over the slider, two to a
row. No tab scrolls on a 1280 × 720 laptop.
- **Status says the result first**, with the warning and its fix under it, and
marks the tab that holds the cause. The geometry detail moves to Files.
- **Files replaces Export STL and Export SVG**, listing every file, with
Download all. Share, Save and Open are there too, and it stays live under
Split, where it lists the two halves.
- **Phones work.** The panel no longer covers the model: the model, status,
rows and tabs stack, with the tabs under the thumb, and sideways the tabs are
a rail. Touch targets are at least 44 px.

### Fixed

- A failed rebuild now says so on the status line, even with the last good
model on screen. The status used to keep showing the old dimensions.

## [0.16.1] — 2026-10-11

### Fixed
Expand Down
Loading
Loading