- pipeline: StageCache + render_cached: resampled source, white-balanced/retouched/denoised image
and each spatial plane (log L, guided base, clarity, texture, dark channel + airlight) are keyed
by exactly their inputs; keeps a draft-size and a full-size entry warm.
- Exposure moved after the spatial filters (applied per pixel; planes shifted by EV): identical up
to rounding (test: <= 2 LSB vs. exposing the source), so exposure drags hit the cache too.
- engine: RenderJob::draft / with_stages; ui: loupe and before views own a StageCache, loupe
renders at Draft quality while interacting.
- engine example render_bench (min-of-N wall + process CPU time).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apps/lightcraft-web runs the egui UI in the browser (eframe web, glow/WebGL2):
procedural demo library on load; in-memory imports via file picker
(Cmd+Shift+I) and drag-and-drop (MemStore + bytes-based engine hooks);
export goes through app.export and downloads in the browser; `?bench` logs
first-frame and slider latency. `cargo xtask web [--serve [port]] [--dev]`
builds with the matching wasm-bindgen CLI into <target>/web/; the web app is
part of the CI wasm check. Wasm fixes: lazy profiling Instant in pipeline,
web-time clocks in ui-egui (render timings were 0 on wasm). Docs: docs/web.md.
No persistence on web yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- new crate lightcraft-preview (L3): 128-bit content hashing (SipHash-1-3),
cost-bounded Lru, DiskCache (JPEG q90 files keyed by content hash +
settings hash + size + RENDER_CACHE_VERSION; temp+rename writes; LRU prune
by mtime to 80% of budget; corrupt files dropped), PreviewCache (memory
LRU over disk), JobPool (per-slot dedupe, priorities, reprioritize/drop,
inline mode for wasm).
- engine: Session::thumb_job buckets thumbnails to 128/256/384/512 and serves
them from the cache without decoding the source; decoded thumbnail
sources now in a 384 MB LRU (was unbounded); library attaches
<library>/thumbs; library.info cache stats; library.clearPreviews.
- ui-egui: Renderer runs on JobPool; thumbnails scrolled out of the
prefetch area are dropped from the queue; on-screen thumbnails get
re-prioritized; ui.inspect reports in-flight renders + thumb textures.
- Demo library (24 photos): grid fully drawn 4.4 s cold -> 0.21 s warm
(24/24 disk hits, no source decoded).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- catalog: Store trait (FsStore: temp+fsync+rename+dir fsync; MemStore),
Journal: CRC-checked JSON-lines op log with sequence numbers + atomic
snapshots; torn final record dropped and truncated, stale records after a
snapshot skipped, mid-log damage preserved as catalog.log.damaged-N.
- PushHistory op so each edit logs one history step (not the full history).
- engine: Session::open_library/persist/close_library; every top-level
command is fsynced before returning; presets.json + view.json;
library.info / library.compact commands.
- app: default library ~/Pictures/LightCraft Library (LIGHTCRAFT_LIBRARY or
--library DIR override), --memory for throwaway sessions, snapshot on quit.
- tests: proptest replay(log)==state with random snapshots/reopens, every
truncation of the last record, stale log, mid-log damage, FsStore, engine
restart without close.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decoders (JPEG via zune-jpeg + jpeg-decoder for DCT scaling/CMYK, PNG,
TIFF, WebP, GIF, BMP, PSD composite, JPEG XL via jxl-oxide) produce linear
Rgb32f in source primaries with SourceSpace; ICC matrix/TRC applied exactly,
LUT/CMYK profiles through moxcms; to_working() to linear Rec.2020 D65.
Encoders: JPEG, PNG 8/16, TIFF 8/16/32f, lossless WebP, AVIF (native).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>