Skip to content

Rebuild the panel as four tabs - #2

Merged
somebox merged 34 commits into
mainfrom
panel-tabs
Nov 2, 2026
Merged

somebox merged 34 commits into
mainfrom
panel-tabs

Conversation

@somebox

@somebox somebox commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Stacked on #1, so this diff shows only the panel. Merge #1 first; GitHub then retargets this to main.

Replaces the Shape, Form and Make panel with four tabs: Shape, Openings, Build, Files. It ships for Print alone, with Cut and Fold still behind ?sheet. Saved designs and links don't change. The decisions are 10, 11, 18 and 25–30 in docs/PRODUCTION.md.

What changed

  • Tabs: each shows its current value as a caption. Everything only a printed shell reads is in Build, and the project's name and Undo move to the header.
  • Fields: label and value sit over the slider, two to a row. A choice too long for half the panel takes the whole row.
  • Status: it says the result first, with the warning and its fix under it, and marks the tab that holds the cause. Print's status now stays beside the rows rather than under the model.
  • Files: replaces Export STL, Export SVG and the Export dialog. Print's files now come from listArtifacts(), as the CLI's do. Under Split, Files stays live and lists the two halves, and the other tabs lock.
  • Phones: the model, status, rows and tabs stack, with the tabs under the thumb. Sideways, the tabs are a rail. Touch targets are at least 44 px.
  • Viewer: it now follows its container, because a warning can change the model's height without a window resize.

Fixed

A failed rebuild now shows on the status line. It used to keep showing the old dimensions, with the error only on its control, which may now be on another tab.

Measured on the app

With clusters open, across Print, Cut and Fold:

Screen Model visible Most scrolling
Phone, 375 × 667 34% 2.28 screens
Sideways, 667 × 375 41% 1.95
Tablet, 768 × 1024 38% 1.36
Laptop, 1280 × 720 70% none

There's no page overflow, and no control is under 44 px on the three smaller sizes. The phone's 2.28 is Cut's Build tab with a warning showing; Print's most is 2.03. The §4 limit moved from 2.2 to 2.3 screens, because 2.2 would have pushed the model close to its one-third minimum.

Tests

  • 855 pass on Node 26. CI covers Node 20, 22 and 24.
  • The project takes no dependencies, so test/mini-dom.js is a small DOM stand-in that runs the real createPanel under Node. test/panel.test.js covers what each tab holds, tab behaviour, status, Files and the Split lock.
  • Checked in the app: file names, Split's two halves in order, a failing link naming Wall with a fix, and Cut's files and notes. Download clicks were captured, so no downloaded file was opened.

Not verified

  • Phone sizes were emulated, so touch hasn't been tried on a real phone.
  • main.js and sheet-mockup.js have no tests of their own, and layout can't be tested this way.
  • STL mesh acceptance wasn't rerun, because mesh generation didn't change.
  • Nobody but its author has used this layout. The new-user test, finding Wall and Border without help, is still to do and is on the board.

🤖 Generated with Claude Code

somebox and others added 23 commits October 27, 2026 08:33
docs/LASER_RESEARCH.md collects the research for cutting designs from
sheet stock instead of printing them: what the skeleton already gives,
the dihedral angles real designs need, thickness geometry (square-cut
inset t·cot(θ/2), tab-and-slot play t·|cot θ|), joint options by angle,
size rules, prior art from homelib and the web, a measured commercial
hub-and-strut kit, and why connectors cut square to the faces (edge
clips) hold any angle. §8 plans Cut and Fold modes behind one Build
switch; §9 shows every joint in pictures. docs/laser/ adds two
interactive pages: the joint options by angle and thickness, and the
panel mockup.

src/sheet/ turns a skeleton into flat parts, not wired into the app:
- panels.js: one panel per face (coplanar sub-faces merged), joints
  with dihedral and valley flags
- cut.js: rigid sheet with edge clips, zip-tie holes or tabs (tabs
  only near 90°, else clips), kerf and clearance, engraved edge
  numbers, a fit-test coupon, and the border openings need
- fold.js: nets grown compactly from the largest face, valley and
  mountain fold layers, glue flaps, tape or sewing holes, a score test
- layout.js: board profiles (Falcon A1, xTool, Glowforge, paper) and a
  shelf packer that nests parts along each row
- svg.js: layered cut file in mm, one colour per operation
- assembly.js: the parts put back together in 3D for pictures

scripts/sheet-samples.mjs writes 16 samples and three test cuts (A4
paper, 2 mm plywood) with boards, previews and rendered pictures
(scripts/lib/render3d.mjs, a headless z-buffer PNG renderer).
test/sheet.test.js covers the invariants. 752 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With ?sheet in the URL, src/sheet/mockup.js mounts over the real panel:
a Build switch (Print · Cut · Fold) heads Form, each mode swaps in its own
rows (Sheet, Join, Fold lines, Board, Labels, Kerf and Fit), the viewer
shows the cut parts put together, a Flat toggle shows the boards (click a
part to light it up on the model), and Export cut file writes the layered
SVGs. Without the flag the app is unchanged.

The viewer gains setAltModel for the stand-in model; buildFold takes a
rootFace to centre the first net and lists each net's panels and faces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's "Geometry stays free of Three.js" rule allows only viewer.js to import
three. The mockup now passes the assembly as typed arrays and colours to
viewer.setAltModel, which builds the meshes, and lights parts up through
viewer.highlightAlt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mockup:
- Leaving Print switches Print risk, Section and Split off through their
  own checkboxes (Split had kept the panel locked and its halves on
  screen); returning turns Print risk and Section back on.
- The viewport HUD hides Print's toggles by class, not by touching the
  app's hidden attributes.
- Custom board sizes snap into 50–2000 mm; saved settings are validated.
- Cut files use the app's export stem and download path.
- Tidier part tips in the Flat view.

Engine:
- Cut edges too short for a joint (under 2·w + 2·t) are glued and
  counted, instead of carrying clips on 0.7 mm edges.
- The openings warning comes first, says "crowd the edges", and asks to
  close the faces when no Border up to the app's 90% would do.
- Fold flaps are fitted to the board together, not one at a time, so a
  net with flaps no longer spills off the sheet.
- Fold labels start nearer the edge and go down to 2 mm, so they fit
  beside openings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With open faces the clip arms show through the openings. Laser clips now
get a quarter round on each arm end's back corner and a small cove at the
heel (geom2 filletCorners); the corners against the panels and the slot
tabs stay square, so seating and fit are unchanged.

Clips: Cut · Print (clipsBy) takes the clips off the laser boards and
makes them as 3D-printed solids: the same outline without kerf, as thick
as the sheet, with a 45° chamfer round both faces. Each clip shape gets
its own plates and STL, since printed clips carry no letter
(printclips.js: PRINT_BEDS, chamferedPrism, clipPlates, plateMesh). The
plates are closed solids, checked in the tests and with trimesh.

The mockup gains the Clips row, a print bed under Advanced, plate tabs in
Flat, and STLs from Export cut file. The doc pictures are regenerated
with the rounded clips, plus a cut-vs-printed comparison.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g, Export dialog

Clips showed through some openings: the clash check stopped at the slot,
but the clip's arm runs further along the panel. Every joint now has a
footprint (slot and arm, tie hole, finger band, plus a bridge), and a face
whose opening would cross one is cut closed, whole. The Border offered to
open it comes from the same test, so the fix always works.

Tab-and-slot grew one panel 2·t past the edge (faces 20–70% too big, spikes
at sharp corners). It is replaced by finger joints: alternating fingers,
flush, odd count, near-90° edges only, faces keep their size.

Clip options: size (Auto picks the largest that clears the openings),
count per edge, middle or corner placement, and a free width for printed
clips (slots and the fit strip follow). Printed corner clips that touch are
welded with manifold into one piece per corner (csg.js weldTouching),
turned to print with the least overhang, and put on their own plates.

The mockup gains the Clips group and one Export button that opens a
dialog listing every file (boards, clip plates, corner pieces; the STL and
drawing in Print mode). Notes in docs/LASER_RESEARCH.md §8.7; pictures
regenerated, tab pictures replaced with finger joints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sewn edges are now seams, as in clothing: both faces get a seam
allowance past the edge (6 mm by default, Allowance 3-15 mm), the edge is
a dashed stitch line on the inside, and the two allowances are sewn face
to face from the inside and stand in as a fin. Allowance ends are cut at
half the corner angle, the same on both layers, so seams that meet at a
corner don't pile up.

- Notches too narrow for two allowances (dodecahedron, geodesic corners,
  globe gores a slit apart) keep their gap as a dart.
- Valleys are always seams, so stars come apart into one cone per point;
  every star tried now sews with no whip-stitched edges.
- Felt edges whose sides nearly meet round a flat corner stay folds.
- Holes: On punches holes on the stitch line for leather or thick felt.
- Numbers go on the allowance. Nets leave room for the allowances.
- Whip-stitch holes remain only where no allowance fits.

The mockup gets Allowance and Holes rows under Sew, and the status line
counts seams, darts and whip-stitched edges. Pictures show the fins;
docs §8.8 covers the rules and measured counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cycles

unfold.js holds net growth, seams.js the seam and dart rules, prism.js the
chamfered prism that printclips and assembly both need. Shared polygon
helpers move to geom2. Output is byte-identical across 31 jobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anel

compileShape() builds the skeleton with no shell, so a print-only setting can
neither fail a laser job nor slow it down. src/production/ takes a shape and a
job (plain JSON, defined once in JOB_DEFS) to a finished production, one list
of files, and status lines; the Export dialog and the CLI read the same list.

scripts/shapemaker.mjs builds or plans any design file; scripts/build-examples.mjs
replaces sheet-samples.mjs and builds docs/examples/. Projects carry an optional
production block. The mockup's rows now come from JOB_DEFS and Flat is its own
module.

Three behaviours change, all from reviewing the mockup: the fit strip is its own
file, cut first, and Score gets a test strip; Fit takes the strip's numbers
instead of Snug/Normal/Loose; Sew always marks fold lines, since felt can't be
scored. Download all is staggered. Engine output is byte-identical across 31 jobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…design

docs/PRODUCTION.md holds the shape vs production split, what reviewing the
mockup found, and 24 decisions for the first release with new outputs, with
acceptance and the order of work. Research moves to docs/research/, marked
non-binding, without the plan and mockup narrative it used to carry.
docs/examples/ keeps the best designs as project files the tests build.

SPEC and ROADMAP lose claims that were already stale: booleans out of scope
(Cut sides ship them), a dead BORDER_EVIDENCE link, and Phase 1 module lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Undo no longer loses or swaps a project's production block: it rides in each
history entry. The fit strip is one part, so its key can't be packed onto
another board and land across its own slots. A saved job writes its process in
full, so flipping a default can't change an existing design. A project with no
job opens in Print under ?sheet, and opening one no longer resets the browser's
settings for other processes. Plates aren't listed until they're welded.

The CLI rejects out-of-range --board sizes and prototype-named flags, merges the
two border spellings properly (a fix offered is a fix that works), and reads
no/off. produce() passes on shape warnings. Settings now pass straight to the
engine, adapters reach it only through src/production/, and a test enforces
that. docs/PRODUCTION.md no longer claims what the code doesn't do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Weld now defaults to off, since no printed corner piece has been tried.
Print's Sides option Cut is now Through, so Cut names one thing; its stored
value was already `through`, so files and links don't change.

Remove dead code an audit found: the unused Start expand helpers, unused
geometry helpers and imports, about 80 lines of CSS for markup that no longer
exists, and exports nothing outside their own module used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On symmetric shapes, sorts on measured values mostly compare ties, so the
last bits of a float picked the order, and those bits differ between Node
versions. A net could grow differently on another machine and split into two.
CI caught this on the paper test cut: 2 nets on Node 20 to 24, 1 on Node 26.

Sorts on measures now count values within a micrometre as equal and break
ties on ids. 83 outputs are byte-identical across Node 20, 22 and 26, and a
pinned hash of the examples guards it on CI. Without the luck of the old
order the paper test cut no longer fits one A4 net at 106 mm, so it is 96 mm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stations replaces decisions 1, 2, 10, 11 and 18 and adds 25 to 30. The
panel becomes its own step that doesn't wait for test cuts and ships for
Print alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shape, Openings, Build and Files replace Shape, Form and Make. Every row
only a printed shell reads is in Build, the project's name and Undo move
to the header, and each tab captions its value. Errors mark the tab that
holds them. ?sheet still swaps its rows in Build.

test/mini-dom.js runs the real panel under node with no dependency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Label and value sit over the slider, two fields to a row, and a choice
too long for half the panel takes the whole row. Every tab now fits a
1024 × 768 screen with its clusters open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Status now says the result first, with the warning and its fix under it,
and a failed build says so even with an old model on screen. The tab that
holds the cause is marked. The geometry detail, Share and every file move
to the Files tab, which replaces Export STL, Export SVG and the Export
dialog, and which stays live under Split to list the two halves. Print's
files now come from listArtifacts().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under 900 px the model comes first, then status, the rows, and the tabs
under the thumb. Phone sideways, the tabs are a rail between the model and
the rows. Touch targets reach 44 px wherever the pointer is a finger, and
the viewer follows its container, since a warning now resizes it. Cut's
status gets a short headline; the full line moves to Files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The spec, README and onboarding change with the panel, because it changes
what ships today. Decisions 10, 11, 18 and 25 to 30 are built; §4 takes the
numbers measured on the app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Split downloads can mix cuts or fail, and validation, mobile usability, and keyboard-focus issues remain unresolved.

7 open issues
What changed in this PR

Rebuilds Shapemaker’s panel around Shape, Openings, Build and Files, using the shared production layer for Print downloads while keeping Cut and Fold behind ?sheet.

Changes:

  • Reorganizes controls into captioned tabs, with project name and Undo in the header.
  • Consolidates status, warnings and downloads, including Split’s two halves.
  • Adds responsive layouts, container-based viewer resizing and panel tests.
File Description
test/​wall-mode.test.js Updates the expected Inner wall tab.
test/​production.test.js Tests production status headlines.
test/​panel.test.js Covers tabs, status, downloads and Split locking.
test/​opening-axis.test.js Updates the expected Sides tab.
test/​mini-dom.js Adds a dependency-free panel DOM stand-in.
test/​ellipse-opening.test.js Updates the expected Outline tab.
test/​controls.test.js Updates cluster persistence expectations.
src/​viewer.js Observes container size changes.
src/​ui.js Implements tabs, status, Files and locking.
src/​sheet-mockup.js Integrates sheet controls and files into tabs.
src/​schema.js Assigns controls to their new tabs.
src/​production/​summary.js Adds concise production headlines.
src/​production/​job.js Regroups board and label settings.
src/​production/​index.js Exports the headline helper.
src/​panel-model.js Defines tabs, captions and status helpers.
src/​onboarding.js Updates guidance for the tabbed panel.
src/​main.js Connects Print artifacts and Split to Files.
src/​controls.js Determines full-width fields.
README.md Documents the new panel workflow.
index.html Adds responsive tab, field and status layouts.
docs/​SPEC.md Updates panel and Split behavior specifications.
docs/​PRODUCTION.md Records implemented decisions and layout measurements.
docs/​CHANGELOG.md Summarizes panel changes and the status fix.
DEV.md Updates panel integration and test documentation.
.cards/​backlog.jsonl Records progress and remaining verification work.

Review effort: Balanced

Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread src/main.js Resolved
Comment thread src/ui.js Resolved
Comment thread src/ui.js Resolved
Comment thread src/ui.js Resolved
somebox and others added 3 commits November 2, 2026 00:50
Split's Download all keeps to one model and cut, and the list follows the
plane and orientation. Marks come from the job on screen, with keyed
problems from produce. Files lists a lone warning, Export hands focus to
the Files tab, the status line scrolls past 30vh, and the remaining small
targets reach 44 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Undo across an Open restores that project's job. Whip-stitch holes close
faces whose openings they would fall in, by the rule Cut uses, with the
Border fix on offer. Fold thumbnails draw open outlines, flat parts work
from the keyboard, and a second pick no longer strands the first's tint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@somebox
somebox requested a balanced review from Copilot November 2, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread src/sheet-mockup.js Resolved
somebox and others added 5 commits November 2, 2026 01:10
An Open that changes only the job gets its own Undo step. The fit strip
takes a printed clip's tab, which replaces the key, and the score strip
gets a scrap when the board can't hold it. plan --pictures lists what build
writes, big assemblies no longer overflow Math.max, and a saved board or
bed that isn't a name falls back instead of throwing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Segments, Flat's board tabs and file downloads reach 44 px, and segments
wrap rather than shrink. Flat starts below the floating header, edge
controls keep clear of safe-area insets, and a failed weld warns on the
status line and marks Build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plates number with a hyphen, so clipsA's second plate can't overwrite
class A2's. Saving in Print keeps the other processes' settings, and a
file's settings now beat the browser's on Open. Parts too big for the
print bed warn, welded corner pieces included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from sheet-output-research to main November 2, 2026 08:42
PR #1 landed on main as a squash of sheet-output-research, whose tree
panel-tabs already contains, so every conflict keeps the panel-tabs side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/main.js Resolved
Comment thread src/ui.js Resolved
Comment thread src/ui.js Resolved
Comment thread src/ui.js Resolved
…g issues

A failed rebuild in Cut or Fold drops the last layout's files and any
build or weld still on its way. Reselecting the open tab keeps its
place. Marked tabs say so to screen readers. The settings a reshape
reduced mark their tabs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 09:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

After a failed rebuild, Files displays measurements from the previous successful model without identifying them as stale.

1 open issue
4 resolved since last review

Review effort: Balanced

Comment thread src/ui.js Resolved
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 09:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Interactions among draft validation, warning visibility, and UI state across workflows warrant human assessment.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@somebox
somebox merged commit 1aeda74 into main Nov 2, 2026
15 checks passed
@somebox
somebox deleted the panel-tabs branch November 2, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants