Feature: Tape-line overlay replaces axis rectangle (calibration length + crop) — post-M3 #99
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Replace the M3 axis-rectangle calibration step with a tape-line overlay: a black line with two rifle-scope-style end ticks that the owner drags to exactly where the tape measure was laid. Aligning the photo to a fixed reference line sets the measurement axis and the crop framing in one action, and the declared length becomes an owner-declared value (distance between the two ticks) instead of a projected guess.
Scope: large, post-M3, managed in a branch — this is a feature, not a basic bug fix. New requirement row + dedicated branch + task breakdown.
Motivation (the point)
The as-built length model is a guess:
maskSpanAlong,geometry/rect.ts:118) — i.e. the full mask span in the axis direction is assumed to be the taped length.The tape-line model removes the guess: the owner rotates the photo until the taped line sits on the fixed reference line, then drags the two ticks to the exact tape start/end. L = the real-world distance between the two ticks, anchored to the owner's actual tape placement.
maskSpanAlongis demoted to an optional sanity check.Requirements
1. Overlay — black tape line + two end ticks
PhotoStage.svelte(lines 56-82).2. Control model — desktop-first, touch-compatible (Pointer Events unified)
Library to use:
sveltedrag(add tofrontend/package.jsondependencies).peerDependencies.svelteincluding Svelte 4.2.20 (this project is Svelte 4, not 5). Branch prerequisite: pin a compatible version, confirmnpm install+tsc --noEmitclean before wiring.useDragon the photo stage (pan/zoom), the rotate handle (rotation), and each end tick (tape marks).3. Fixed reference line = the crop line
composeInventoryFrame.4. Crop % is a global setting
FILL = 0.9(png/inventory.ts:4,png/overlay.ts:489) with one shared constant fed by asettings.crop_fillvalue, default 90%.5. Crop is post-BG-removal, slab-only (existing behavior, preserved)
slabBounds, min/max over kept pixels only).inventory.ts:53).6. Transform scope
role"dimension-overlay",#63).7. Doc fix
capture/types.ts:46comment says "80%-fill PNG crop" — stale. The live constant isFILL = 0.9(90%). Fix the comment.Acceptance criteria (UAT)
tsc --noEmitclean;npm run test,npm run build, backendpytest, and both repo gates (tools/check_requirements.py,tools/check_coverage.py) pass.Implementation notes / impact
PhotoStage.svelte(overlay render),AxisPanel.svelte(controls),session.ts(setAxisAngle→ transform model),geometry/rect.ts(maskSpanAlongdemoted),png/inventory.ts+png/overlay.ts(unifyFILL, read crop_fill), Settings schema + backend (newcrop_fillsetting).issue-<N>-tape-line-overlay.Design proposal — approved by owner 2026-09-24. Wireframe is on branch
issue-99-tape-line-overlay.Artifact:
docs/design/issue-99-tape-line-overlay.html— commit63b8879. Single self-contained HTML file, no build: open it in a browser and drive it.What the design settles
(1 − fill)/2of the long axis in from the top and the bottom. At 90% the ends sit 5% in from the top and 5% in from the bottom. It does not change the aspect ratio: the 3:4 rectangle is unchanged.Before this reaches the production workflow — scrub the dev items
The core idea is there. These are wireframe scaffolding and none of them belong in the shipped UI:
window.__wfdebug hookHow it was checked
Driven live with Playwright at 390 / 412 / 1440 rather than read off the source: the line's x stays 240 under tilt, pan and zoom; changing crop 90 → 60 moves the ends while the rectangle keeps its 3:4 aspect; the tick grab target measures 50×50 px; the operator's alignment task completes end-to-end; and all five screens show 0 px overflow, 0 clipped text, 0 overlapping text and no console errors. A vision pass on fresh captures confirmed the middle-line model and the crop bands.
Scope note: the production implementation of this design is not in this commit — the commit contains only the artifact.
As-built annotation — SHIPPED & UAT signed off (2026-09-25)
The issue body above describes the mechanic that was prototyped and then rejected. The line is NOT an owner input. Recording the as-built here so this issue resolves against what actually shipped. Owner sign-off: Ty, 2026-09-25.
The mechanic as built
A fixed black centre line with two rifle-scope end ticks, drawn on the stage fixture. It is never draggable, never focusable, never keyboard-nudgeable, and is not part of the published pose. The source photo/slab is the only thing that moves — drag to pan, wheel/pinch to zoom, the ↻ handle or arrow keys (Shift = fine step) to tilt. The owner pans/zooms/tilts the slab until it lines up with the fixed line at the exact place the tape measurement was taken. The hint on the page says so; the old "Drag the ticks" copy is gone.
maskSpanAlongis not the scale source.crop_fill=90⇒ each end sits 5% from its corresponding edge. Ends are a pure function ofcrop_fill(capture/tapeLine.tscropEnds(fillPercent)).Acceptance criteria — verified
crop_fill; live crop-fill changes move the ends1882fa3; 0°/20° produce differing clean PNG + overlay bytes; sibling isolation testslabBounds; opaque bounds 280×529 @50%, 504×954 @90% in an 800×1067 frameTicks draggable desktop+touch, ≥44×44, arrow nudgemeasure()always receives the tape span on the shipped path; themaskSpanAlongbranch is legacy fallback for a tape-less call and is unreachable in calibrationcrop_fillis non-retro; applies to captures going forwardtsc --noEmit,npm run test,npm run build, backendpytest, both repo gates pass80%-fillcomment from §7 corrected inf725e04.http://192.168.1.202:10883/?noload=1, imagedeploy-frontend:m4-a756cf5, real FastAPI ondeploy_default.10881is the oldmainstack, not this.Superseded from the body above — do not restore
sveltedrag— 404s on npm, never added as a dependency.TapePrototype.svelte+ the?tape-prototypesandbox — deleted.frontend/src/png/crop.ts— removed in6000ac2; crop geometry lives incapture/tapeLine.ts.docs/design/issue-99-tape-line-overlay.htmllives on branchissue-99-tape-line-overlay(63b8879), notm4.CREATEnamespace — there is noCREATEnamespace; the as-built rows are CAPTURE-170 / CAPTURE-175 / CAPTURE-75.Commits (branch
m4)7908a99one-page tape calibration ·1882fa3calibration tilt → PNG/overlay only ·a756cf5fixed line + drop stale tick-nudge hint ·8673ae0as-built docs + stale-ref sweep ·f725e04§7 comment fix.Evidence & known limits
Requirements are normative in
docs/REQUIREMENTS.md; as-built narrative in.planning/milestones/v0.5/M4/tasks.md(T2); deploy record indeploy/INVENTORY.md. The regression guard was proven to fail against the pre-fix build, not merely pass post-fix. Ty's visual acceptance was on the real deployed preview.Known limits:
svelte-checkstill reports its known 42-error baseline (none introduced here).Calculate(42px) andFit(41px) sit marginally under the 44px touch reference — pre-existing, deliberately deferred to its own decision.