Lightroom has owned photo workflow for two decades, and every attempt to replace it has stumbled on the same wall: the library. Browsers can mimic the develop sliders, but ratings, flags, albums, previews, and the guarantee that your edits survive a crash are what make a photo tool a photo tool. LightCraft, part of the ArtCraft family on getartcraft.com, attacks the whole problem in pure Rust. It is a clean-room reimplementation of Lightroom in the storytold/lightcraft repository, version 0.5.0, MIT OR Apache-2.0 licensed, native on macOS, Windows and Linux with a WebAssembly build in the browser, and with no C dependencies at all: the RAW decoders, the color science, and the develop chain are all written from scratch in this workspace.
The repository reads like a course in media-software architecture. The catalog state changes only through operations; the develop model is pure serializable data; the CPU chain is the reference implementation and a wgpu compute twin must match it within 1/255 per channel; and every menu item, slider, brush stroke, and keystroke is a command with a stable id that the UI, the CLI, a JSON-lines control channel, and an MCP server all dispatch through one entry point, Session::execute. The screenshots in the project README were captured end to end by scripts driving that control channel, which tells you how seriously the agent story is taken.
The overview: every frontend enters through the engine, the catalog and develop model live in the library layer, two pixel backends share the same stage plan, and the MCP server reaches the engine headless or through a live app.
Reading the overview from left to right:
- The desktop app in apps/lightcraft/src, the CLI in apps/lightcraft-cli/src, and the browser build in apps/lightcraft-web are three shells over the same core, and the desktop shell can open a control channel with
lightcraft --control 7980. - The engine facade in crates/engine/src owns the catalog, the library view, the selection, and
RenderJobs that areSend, so frontends render off the UI thread. - The library layer splits into crates/catalog/src, the photo database, and crates/develop/src, the non-destructive edit model.
- The pixel layer pairs the CPU reference chain in the develop-chain crate with wgpu compute kernels in crates/gpu/src, plus the preview cache in crates/preview/src and HDR and panorama merging in crates/merge/src.
- Input decoding lives in crates/raw/src with clean-room decoders for DNG, CR2 and CR3, ARW, NEF, RAF including X-Trans, RW2, PEF, and ORF.
- The agent layer in crates/mcp/src exposes the whole app as MCP tools over stdio.
Why You Need This
First, the library is built to be trusted. The catalog in crates/catalog/src/lib.rs mutates only through Ops, and Catalog::apply returns the inverse operation, which gives undo, determinism, and persistence from one mechanism: ops append to a JSON-lines log in crates/catalog/src/journal.rs and replay after the last snapshot on load. The project calls this a “human-readable log you can diff, back up or replay,” and it is exactly what a proprietary catalog database can never offer you. Newer builds read every older catalog format and upgrade it; older builds refuse a newer library rather than reading half of it.
Second, the develop chain is designed the way color scientists wish all raw editors were. DevelopSettings in crates/develop/src/lib.rs is pure, serializable data, and the chain in the CPU reference crate evaluates it in five documented stages: geometry with one resample at output resolution, scene-linear operations on linear Rec.2020, a filmic tone map, OkLCh color work, and display encoding with gamut mapping instead of clipping. Spatial parameters are relative to the image’s long edge, so a 400-pixel preview and a 60-megapixel export look identical, and a StageCache means dragging one slider re-runs only the stages it affects. The GPU crate in crates/gpu/src/lib.rs ports each stage as a WGSL kernel tested against the CPU chain, with a per-stage hybrid fallback when a kernel is missing and a clean fallback to all-CPU when the device fails.
Third, an agent can actually run your studio. The MCP server in crates/mcp/src/lib.rs is hand-written JSON-RPC 2.0 over stdio with no async runtime, exposing tools for import, query, develop, mask, render, and export; it runs headless against a saved library or attaches to the running desktop app with screenshots, clicks, and gestures. The control channel accepts lines like develop.set with {"light.highlights": -45, "light.shadows": 38} or ui.clickWidget targeting any widget by name, develop.controls lists every slider’s range and default, and even agent actions are one undo step. lightcraft-cli run --import in.dng develop.set control=light.exposure value=0.7 app.export path=out.jpg is a complete raw-to-JPEG chain in one line.
The detail view: command modules, the journaled catalog, the five-stage chain with its GPU twin, the AI crates, and the input format layer, all wired through the engine.
The detail diagram shows how much lives in the engine layer: import with rename templates and duplicate detection in crates/engine/src/export.rs, XMP sidecar handling and reading Lightroom’s crs: develop settings in crates/engine/src/sidecar.rs, and merge commands over the merge crate in crates/engine/src/merge.rs. The merge crate itself is a small marvel: crates/merge/src/lib.rs implements HDR bracket merging with auto-align, exposure normalization, saturation-aware weighting, and deghosting, plus panorama stitching with feature matching, RANSAC, rotation bundle adjustment, multi-band blending, and boundary warp, outputting 16-bit float linear DNGs. Every algorithm is their own implementation from published papers.
The performance layer is equally deliberate. crates/preview/src/lib.rs keys disk thumbnails by content hash, settings hash, size, and renderer version, fronts the disk cache with a cost-bounded memory LRU, and runs a worker pool that prioritizes visible thumbnails over off-screen prefetch and runs jobs inline on wasm. That is why culling feels instant: opening a raw shows its embedded camera preview in about a tenth of a second while the full render follows, and the next and previous photos are prepared in the background. On the AI side, crates/segment/src implements SAM 3 inference in pure Rust on candle with click and text prompts, crates/denoise/src places AI denoise as a cached step between sensor and demosaic that the rest of the chain never sees, and crates/faces/src handles face detection and recognition; the roadmap is honest that AI masks currently use classical heuristics while these crates land.
From Install to First Develop
Clone the repository and build the CLI with cargo build --release -p lightcraft-cli; the workspace needs Rust 1.90 or newer on edition 2024. To register the app with an MCP client: claude mcp add lightcraft -- "$PWD/target/release/lightcraft-cli" mcp ~/Pictures/shoot for headless work, or mcp --connect 127.0.0.1:7980 to attach to a live app. A first headless session: lightcraft-cli run --import in.dng develop.set control=light.exposure value=0.7 app.export path=out.jpg longEdge=2048, then lightcraft-cli render in.dng -o out.jpg --set light.exposure=0.7 --preset ... for one-off renders. For interactive work, run the desktop app and use the control channel or just the UI; every widget is addressable, so anything you learn in the UI transfers to scripts. XMP sidecars round-trip, so your edits also travel to other tools.
Honest limits: the roadmap marks the project at roughly 79 percent of Lightroom by feature count, nearer 60 to 70 percent as a day-to-day replacement, with the biggest gaps in measured camera color calibration for some brands, compressed Olympus and some CR3 variants, HDR editing, video, and the Print, Book, and Map modules; WebGPU is still in progress for the browser build. Model weights for SAM 3 and denoise are downloaded on demand, not bundled. None of that dulls the core achievement: a catalog you can diff, a processing chain you can verify, and a whole photo studio that an agent can drive. Enjoyed this post? Never miss out on future posts by following us