The library page was a flat wall of thumbnails. It now reads like the admin
pictures tab: a folder tree on the left, the picked node's frame on the stage,
that node's frames in the strip below, and a chip pair to swap the stage for a
wall of every thumbnail in the node.
Folders are walked recursively (dot/@-prefixed names skipped, an unreadable
subfolder is dropped rather than failing the scan), so a roll with a dated
subfolder keeps both levels. Node counts include the subfolders underneath.
A RAW studio that cannot see a folder is one photo at a time. /library
now takes a folder through Chromium's directory picker, keeps the handle
in IndexedDB so the folder is there on the next visit, and walks it into
a grid: one thumbnail per frame, the frame's own date, and the recipe it
was last graded with. Nothing is uploaded and nothing is read twice —
the RAW itself is opened only when a tile is clicked, at which point the
studio develops it and the recipe comes back on top. The studio files
every change back against the frame, debounced, so reopening a RAW is
not doing the grade again.
Thumbnails come off LibRaw's unpack_thumb for a RAW, which is a seek and
a copy where a develop is a full decode of every pixel, and off
createImageBitmap for anything else. A RAW with no preview inside it
gets a placeholder tile rather than a minute of decoding per file.
node scripts/library-check.mjs
ok both frames indexed as tiles — 2 tiles from P1010256.JPG + P1010256.RW2
ok thumbnail for P1010256.JPG — 40400 bytes, jpeg=true
ok thumbnail for P1010256.RW2 — 39895 bytes, jpeg=true (LibRaw preview)
ok studio developed the frame from its handle
ok the address was handed back — url=/app (no ?lib= left behind)
ok the look was filed back against the frame — baseFilter=none, 19 knobs
ok the tile says the frame is edited