.preview was width:100% inside max-height:50vh container — tall photos
were clipped. Now: max-width:100%, max-height:50vh, width/height auto,
object-fit:contain, flex-centered in the wrap.
Added e2e regression test: loads a photo, verifies the canvas bounding
box fits the viewport, preserves aspect ratio, and is not clipped by
the container.
The gate check ran during SSR where navigator is undefined,
rendering the 'Unsupported browser' div into the initial HTML.
Now gated on browser (client-only) so SSR renders the app
and the gate evaluates in the browser.
1. drawOverlay: checkerboard mask overlay now drawn in axis + measure
states (mask carry-forward — slab is isolated)
2. Removed the separate red axis line + arrowhead — the rect's long
side IS the axis
3. Rect rotates: uses axisState.rect.angle (from UAT-8a)
4. Replace three rotate buttons with slider (-180..180, step 1) +
minus/plus nudge buttons (same pattern as Sensitivity slider)
587 lines, 109/109 tests, build OK.
reduceAxisState 'rotate' now changes state.rect.angle and re-derives
state.axis via axisFromRect(newRect). The rectangle rotates as a whole;
the axis for Measure is derived from the rotated rect's long side.
2 new regression tests: rect.angle changes on rotate, axis is
re-derived from rotated rect. 109/109 tests green.
Spec CAPTURE.md §Browsers: Phone iOS Safari / Android Chrome, PC
Chrome / Edge / Firefox, others hard stop.
- browserGate.js: UA detection + allowlist (pure, DOM-free)
- +layout.svelte: renders hard-stop panel when unsupported
- iPadOS 13+ reports as Macintosh — added Safari rule (Version/ +
Safari/ without Chrome/) so iPad Safari is not blocked
- 27 unit tests incl. iPad Safari regression
- 107/107 full suite green
Root cause: auto selected the key with MORE kept pixels, which always
picked the green key (it keeps 100% of dark non-green backgrounds).
The black key correctly isolates the slab on dark surfaces.
Fix:
- auto now prefers the key with FEWER kept pixels (removed more bg)
when both are non-empty
- green key has a greenness pre-filter: non-greenish pixels pass
through (kept) so the black key can handle them, instead of the
green key keeping 100% of a dark surface
- added 3 regression tests: dark-bg auto selection, green-sheet auto
selection, green-key passthrough on non-green surfaces
106/106 unit tests green.
Spec CAPTURE.md §Mask lists exactly two controls: Sheet and Sensitivity. Edge offset and feather nudge buttons were extra. Removed from the UI; core params (edgeOffset, feather) remain in maskState.js, still unit-tested.