Photo library and raw development; an open-source, clean-room reimplementation of Adobe Lightroom, rebuilt in pure Rust.
Native on macOS, Windows and Linux. In the browser via WebAssembly. Drivable end to end by AI agents over MCP.
Ansel Adams, "The Tetons and the Snake River" (1942). Public domain, U.S. National Archives. Developed in LightCraft.
LightCraft is a complete darkroom in a single native app. Every adjustment is non-destructive, so your originals are never touched. Every slider renders through a scene-referred, wide-gamut, 32-bit float pipeline: highlights roll off like film, shadows open up without halos, and colour stays clean from capture to export.
|
Exposure, Contrast, Highlights, Shadows, Whites, Blacks, with edge-aware local tone mapping (a guided filter on log-luminance). Pulling −100 Highlights recovers a blown sky without the grey halos you'd get from a naive curve. White balance by temperature and tint (Kelvin for raw, relative for JPEG) with presets, Auto and a click-to-neutralise eyedropper. Vibrance that protects skin tones, Saturation, an 8-band Color Mixer (hue / saturation / luminance) and 3-way Color Grading wheels with blending and balance. All of it is computed in OkLCh, a modern perceptual colour space. |
Texture for fine detail, Clarity for mid-tone punch, Dehaze (dark-channel prior with guided refinement; push it negative to add atmosphere), post-crop Vignette with highlight priority, roundness and feather, and resolution-independent film Grain with size and roughness. Parametric region curve with movable splits plus point curves for RGB, Red, Green and Blue. Curves are monotone by construction, so you never get an accidental tone inversion. |
A gentle S on the RGB point curve, right under the Light sliders. Ansel Adams, 1942 (public domain).
Split-tone shadows, midtones and highlights independently with drag-anywhere colour wheels. Below, Dorothea Lange's Migrant Mother gets a warm, print-like tone (highlights at 42°, shadows at 28°) in two drags.
Shadows, midtones and highlights wheels in the Color panel. Dorothea Lange, "Migrant Mother" (1936). Public domain, Library of Congress.
Hold \ to peek at the original, press Y for side by side, or Shift+Y for a split view. Every image below is a real screenshot of LightCraft, captured automatically by an agent through the built-for-agents.
Paint with a Brush (size, feather, flow, density, erase), drop Linear and Radial Gradients with draggable pins, or select by Luminance Range, Color Range, Sky, Subject and Background. Combine components with Add / Subtract / Intersect, invert any of them, and dial in 15 local adjustments per mask (Temp, Tint, Exposure, Contrast, Highlights, Shadows, Whites, Blacks, Texture, Clarity, Dehaze, Hue, Saturation, Sharpness, Noise) plus an overall Amount.
A radial "Sun glow" mask (Temp +40, Exposure +0.50) layered over a linear "Sky" mask. Photo from LightCraft's procedurally generated demo library.
Eighteen hand-built presets ship in the box (Golden Hour, Teal & Orange, Faded Matte, Selenium Tone, Crisp Landscape and more), each with an Amount slider from 0 to 200 %. Save your own from any group of settings, mark favourites, and copy, paste or sync edits across a whole selection with exactly the groups you choose.
The Presets column next to the 8-band Color Mixer. Photo from the demo library.
A library that stays out of your way: All Photos, Recently Added, Picks, By Date, Albums nested in
Folders, and Recently Deleted. Rate with 0–5, flag with P / X /
U, colour-label with 6–9. Search understands fields:
rating:>3 flag:pick iso:>800 camera:x2 date:2026-04 keyword:mountains. Every view sorts by capture date,
import date, edit date, name, rating, size or at random (a stable shuffle; View → Sort → Reshuffle for a new one). The justified Photo Grid and Square Grid views are virtualized,
so they stay smooth whether you have forty photos or forty thousand.
| Platform | Download | Run |
|---|---|---|
| Windows x64 | lightcraft-x64.7z | Run installer → launch lightcraft-x64.7z |
| Linux x64 | lightcraft-Linux-x64.run | chmod +x → run installer |
| macOS Apple Silicon | lightcraft-macOS-arm64.dmg | Open DMG → drag to Applications |
Every menu item, slider, brush stroke, crop handle and keystroke in LightCraft is a command with a stable id and JSON parameters. The UI, the keyboard, the CLI, a JSON-lines control channel and an MCP server all dispatch through the same entry point. An agent can cull a shoot, develop it, mask a sky and export it, and see the result.
lightcraft --control 7980 ~/Pictures/trip-
Command registry.
engine.commandslists the available commands;develop.controlslists every slider's range, default and current value. -
MCP server.
lightcraft-cli mcpexposes the command registry to Claude (or any MCP client), alongside helpers for import, query, develop, mask, render (returned as an image) and export. It runs headless, or attached to the running app with screenshots, clicks and gestures.cargo build --release -p lightcraft-cli claude mcp add lightcraft -- "$PWD/target/release/lightcraft-cli" mcp ~/Pictures/shoot # headless claude mcp add lightcraft-app -- "$PWD/target/release/lightcraft-cli" mcp --connect 127.0.0.1:7980 # live app
-
Scriptable CLI:
lightcraft-cli run --import in.dng develop.set control=light.exposure value=0.7 app.export path=out.jpg longEdge=2048runs any chain of commands (headless, on a saved library, or against the running app) and prints one JSON result per command;lightcraft-cli render in.dng -o out.jpg --set light.exposure=0.7 --preset …. -
Undo for everything, including agent actions: a slider drag (or a scripted burst of updates) is one undo step.
-
Every widget is addressable (
ui.widgets) and clickable by name, so agents operate the real UI, not a side door. -
The screenshots in this README were produced end to end by the
docs/showcase/scripts.
- Pure Rust, no C. Our own RAW decoders (DNG, Canon CR2/CR3, Sony ARW, Nikon NEF, Fujifilm RAF incl. X-Trans,
Panasonic RW2 / Leica RWL, Pentax PEF, Olympus ORF), our own colour science, our own pipeline. JPEG, PNG, TIFF, WebP,
PSD composites and JPEG XL open today; HEIC/HEIF photos too with
--features heif(HEVC is a build-time choice, as in PhotoCraft). - Scene-referred & wide-gamut. Linear Rec.2020 float internally, Bradford-adapted white balance, gamut mapping instead of clipping, a filmic shoulder for raw and pixel-exact pass-through for JPEGs you haven't touched.
- Resolution-independent edits. Radii and brush sizes are relative to the image, so a 400 px preview, your 5K display and a 60 MP export look the same.
- GPU-accelerated, CPU-exact. The whole develop pipeline runs as wgpu compute kernels (Metal / Vulkan / DX12), checked against the CPU pipeline to within 1/255. On a 24 MP raw (Apple M4 Pro): a slider update re-renders in ~4 ms, a cold 2.5 MP loupe in ~30 ms, and a full-size export in ~0.3 s including a parallel JPEG encode. Without a GPU the same pipeline runs on all CPU cores, redoing only the stages a slider affects.
- Instant culling. Opening a raw shows its embedded camera preview or cached render within ~0.1 s while the full render follows (~0.2–0.5 s for 24 MP). The next and previous photos are prepared in the background, so stepping through a shoot takes ~50 ms per photo.
- Background rendering. A worker pool renders the loupe, before/after and every visible thumbnail off the UI thread: drafts during drags, full quality on release.
- Local-first. No account, no cloud, no telemetry, no subscription. Your catalog is an append-only log of human-readable operations you can diff, back up or replay.
LightCraft is young and moving fast. Where we honestly stand:
- By feature count we're at ~79% of Lightroom (core features 98%).
- As a day-to-day Lightroom replacement we're nearer 60–70%. It's great for JPEG/DNG and most Nikon / Sony / older-Canon raws on one machine.
- The biggest gaps:
- camera colour calibration: Sony, Nikon, Panasonic, Fujifilm and Canon CR3 raws have guarded estimates from their camera JPEGs, with built-in ILCE-7M4, X-H2S and X-T4 profiles; measured calibration is missing, and other raws or rejected fits retain a neutral matrix;
- compressed Olympus raws and unsupported CR3 variants: these use embedded JPEG previews when present. Fujifilm lossless/lossy compressed RAF now decodes sensor data; verification and existing-library reload instructions;
- AI masks and denoise: subject and sky selection are classical heuristics;
- HDR, video and the Classic Print / Book / Map modules.
| Area | Status |
|---|---|
| Library: albums, folders, smart albums, stacks (incl. auto-stack), virtual copies, ratings, flags, labels, filter bar, search, sort, grids, filmstrip | ✅ |
| Culling: Compare (synced zoom) and Survey views, auto-advance, instant previews | ✅ |
| Light, Color, Effects (vignette styles), Tone Curve (+ refine saturation, targeted adjustment), Color Mixer (+ targeted), Point Color, Color Grading, Calibration, B&W | ✅ |
| Masking: brush, linear, radial, luminance/colour range, add/subtract/intersect | ✅ (AI subject/sky use classical heuristics for now) |
| Crop, straighten tool + auto straighten, flip, rotate, aspect ratios, overlays | ✅ |
| Profiles (Color, Neutral, Vivid, Landscape, Portrait, Monochrome: our own looks), presets, versions, history, copy/paste/sync settings | ✅ |
| Camera colour: DNG files use their own matrices | ✅ DNG · 🟡 own Sony/Fujifilm profiles; measured calibration database missing |
| Native macOS menu bar (generated from the command registry), control channel + every widget addressable, headless UI snapshots | ✅ |
| RAW: DNG, CR2, CR3 (lossless CRX Bayer and version 0x100/0x200 C-RAW), ARW, NEF (uncompressed + lossless/lossy compressed), Fujifilm RAF (uncompressed + lossless/lossy compressed, Bayer + X-Trans), Panasonic RW2 / Leica RWL / Panasonic RAW (every raw format, DMC-LX1 to DC-S1RM2), Pentax PEF, Olympus ORF (uncompressed); embedded previews for every format incl. CR3 | 🟡 · CR3, compressed ORF decode ⬜ |
| Detail: sharpening, luminance + colour noise reduction | ✅ · AI Denoise, Super Resolution ⬜ |
| Remove / Heal / Clone spots (auto source), Visualize Spots, Red Eye and Pet Eye (auto pupil detection, catchlight) | ✅ · content-aware fill, spot pin editing 🚧 |
| Export: JPEG / PNG / TIFF / WebP / AVIF / DNG / original, sizing, file-size limit, output sharpening, naming templates, batch, metadata policy, text or image watermark | ✅ · HDR export ⬜ |
| Library persistence (crash-safe op log + snapshots, background compaction, failed saves reported), disk thumbnail cache | ✅ |
| Import: Add in place / Copy / Move, rename and folder templates, devices, duplicate detection, watched folders; Local folder browsing | ✅ |
| MCP server (headless or live app, persistent libraries), CLI, control channel | ✅ |
XMP sidecars (read/write, auto-write), reading crs: develop settings, preset files (.lcpreset, XMP presets) |
✅ |
| Optics (distortion, vignetting, auto + manual CA, defringe, lens corrections embedded in DNG files and Panasonic / Leica RW2 / RWL distortion data), Geometry (transforms, Constrain Crop), Upright (Auto/Level/Vertical/Full/Guided) | ✅ · camera lens profiles (our own) ⬜ |
| Photo Merge: HDR (auto-align, deghost), Panorama (spherical/cylindrical/perspective, boundary warp, auto crop), HDR Panorama → DNG | ✅ |
| GPU pipeline (wgpu compute, CPU-exact within 1/255), CPU fallback on device limits / errors | ✅ · WebGPU in the browser 🚧 |
| AI: segmentation masks, AI denoise, super resolution, faces; HDR editing; video | ⬜ |
| Web build (same UI in the browser via WASM): persistent library in OPFS/IndexedDB, Web Worker rendering, export downloads | ✅ · WebGPU, Safari/Firefox testing 🚧 |
✅ works today · 🚧 in progress · ⬜ not started
LightCraft is dual-licensed under MIT or Apache-2.0, at your option. Copyright (c) 2026 ArtCraft Team and the LightCraft contributors.









{"method": "engine.execute", "params": {"command": "photo.flag", "params": {"flag": "pick"}}} {"method": "engine.execute", "params": {"command": "develop.set", "params": {"values": {"light.highlights": -45, "light.shadows": 38}}}} {"method": "engine.execute", "params": {"command": "mask.add", "params": {"kind": "radial", "center": [0.62, 0.4], "rx": 0.2, "ry": 0.14}}} {"method": "ui.clickWidget", "params": {"id": "slider:effects.clarity"}} // drive any widget by name {"method": "ui.pointer", "params": {"events": [{"kind":"down","x":0.2,"y":0.3}, {"kind":"up","x":0.4,"y":0.3}]}} {"method": "ui.screenshot", "params": {"path": "after.png"}}