The photo pans, zooms, and tilts under a line that stays in the middle
of the frame. Scale is the source-pixel distance between the ticks
divided by the declared length, not the mask span.
Add buildPhotosReadyLineup (clean cal → overlay → batch inventory PNGs
in capture order, plus empty-mask/floor error slots). MeasurePanel
switches to a Photos ready end screen with Milestone 1 numbers and the
inventory PNG lineup; Back still returns to Length axis.
Product call for the WooCommerce redo. Calculate accepts
sources whose post-crop shorter side is at least 800px.
Warn copy and CAPTURE.md match. No upscale still holds.
Replace MeasurePanel steppers with number inputs. Commit on blur, change,
and Calculate snaps inches to nearest 1/8 via inToEighths. Calculate
enables when both drafts parse to > 0. Axis, mask, and scale math unchanged.
Length axis keeps the approved mask, replaces Flip 180 with a ± angle
slider, and sets scale from wood span along the approved direction rather
than bbox.longSidePx. Widths still sample every 6 in perpendicular to that
axis.
Why
Phone and PC need a single capture flow that ends at inventory PNG and
board-foot numbers with no backend, inference, or Woo create.
Scope
Add frontend/ Vite+Svelte capture UI with Resume, Add photo, Mask,
Length axis, and Measure. Mask runs in a worker with Auto/Green/Black
and a 2.0s sensitivity debounce. Measure computes scale, widths, sqft,
bdft, and a 3:4 alpha inventory PNG. Persist one device draft in
IndexedDB. Serve the static build from frontend/Dockerfile via nginx
(deploy/nginx-m1.conf). No FastAPI.
Verification
sudo docker build -f frontend/Dockerfile -t slabuploader-m1 .
sudo docker run -d --name slabuploader-m1 -p 0.0.0.0:18080:80 slabuploader-m1
curl http://127.0.0.1:18080/ returns 200
Playwright: synthetic green-sheet photo through Calculate shows sqft/bdft