5 Commits

Author SHA1 Message Date
Samuel Prevost
6dc5454d46 refactor(crop): tighten architecture + fix zoom-after-crop
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
Architectural debt addressed in one pass:

- CropViewer drops its five local refs (rotationDeg, cropLeft/Top/Right
  /Bottom) in favour of computed views over `store.cropRotate`. Drag and
  rotation handlers write straight to the store via thin setters; the
  store is now the canonical source of truth. localStorage is flushed on
  commit boundaries (drag end, rotation change, unmount, Next), not on
  every pointermove.
- `ImagePreTransform` deleted from `src/types/index.ts`. CorrectedImage-
  Viewer now takes `crop?: { state: CropRotateState; srcW; srcH }` and
  derives the pixel-space affine internally via a memoised `computed`.
  Cuts the second reactive ref in MeasureViewer and removes the
  redundant "type that exists only to ferry derived numbers across a
  prop boundary."
- `crop-transform.ts` is now pure geometry. The DOM-bound
  `renderRotatedCropped` moved to a new `src/lib/crop-render.ts`. The
  pure module is now safe to import from a worker / test without a
  canvas mock.

Bug fix shipped in the same commit because it fell out of the same
analysis:

- Zoom (wheel + pinch) anchored on a measurement-space point returned
  by `screenToImg`, but `viewOffset = screen - bitmap * scale` expects a
  bitmap-space point. With identity crop the two were equal, so the bug
  was invisible until the user cropped — at that point each zoom step
  shifted the image far off-screen ("canvas goes blank/black"). Pan was
  fine because it never converted screen↔image. Fix: a tiny
  `screenToBitmap` helper used by `onWheel` and the pinch branch of
  `onTouchMove`. Measurement placement / drag still go through the
  full `screenToImg` so coords stay in the canonical frame.
2026-05-01 00:29:24 +02:00
Samuel Prevost
565baddfbf feat(crop): rotate + crop step between deskew and measure
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
2026-05-01 00:12:11 +02:00
Samuel Prevost
9032af426e feat(upload): recent-uploads gallery + per-image zoom restore
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
Past uploads now persist to IndexedDB (originalBlob, exif, and — once
deskew has run — the corrected blob, diagnostics, and output scale).
The upload page renders a tile grid for any entry that completed a
deskew; clicking one rehydrates the store from the cached artefacts
and drops the user straight back into Measure with their datums and
measurements intact. The section is hidden entirely when there are no
completed entries, and each tile has a hover-only delete affordance.

Canvas zoom + pan are now per-image, persisted to localStorage with a
short debounce. Re-running the deskew at a different scale clears the
saved zoom (the stale offsets would point off-image at the new
dimensions).

Other tweaks bundled here:
  • Start Over collapses the previous "Start over | New Image" group
    into a single dashed/transparent button.
  • The Measure header gets md:pl-5 so the title clears the fork-me
    ribbon on desktop.
  • Example images on the landing page swap to the IMG_8324 set, with
    a third "Measured" tile spanning the combined width that shows the
    annotation-baked output.
  • Clearing the cache now also wipes the upload + zoom caches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:05:18 +02:00
Samuel Prevost
a5f4bf650c feat(measure): split toolbar into back · downloads · start-over zones
Back collapses to a leading arrow icon, downloads stay in the middle,
and "New Image" moves to the far right behind a labeled "Start over"
separator. The reset button now uses a dashed transparent outline so
it reads as a deliberate, low-frequency action and is harder to hit
while reaching for a download.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:54:00 +02:00
Samuel Prevost
1118de74da feat(pipeline): split Deskew + Measure into separate steps
Step 4 (was "Result") now only runs the perspective correction and shows
diagnostics + a small preview at the standard column width. Step 5
("Measure") is a new full-bleed view dedicated to annotation, with the
download buttons promoted to the top of the page.

Re-running the deskew at a different output px/mm now rescales any
measurements already saved for the image (cached by file hash) so they
stay anchored to the same physical features instead of drifting.

Theme tweaks: card surfaces are now visibly distinct from the page
background in light mode, and dark mode is a touch lighter than the
previous near-black. The "Made by" footer is pinned to the bottom of
the viewport via fixed positioning, with corresponding pb on <main>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:46:19 +02:00