Progress docs: target-app parity, RAW coverage vs Adobe, gaps, alpha gate, readiness by audience (#788)

Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, model-by-model RAW coverage against Adobe's camera list (docs/raw/), and format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Brandon ThomasandClaude Opus 5.5 authored and GitHub committed 2026-10-10 14:25:15 -04:00
1 parent b70ae1741e
commit 964d9338ba
27 files changed
+4837 -396

No files matched your search

+12 -6
View File
@@ -5,12 +5,18 @@ LightCraft is a clean-room, open-source, pure-Rust photo library + non-destructi
## Start every session here
1. Read `plan/STATUS.md` (current milestone, next unchecked task, blockers).
2. Read the task in `plan/execution-plan.md` §3, the relevant section of `plan/architecture.md`, and the README/docs of the crate you touch. Behaviour/visual reference: `plan/lightroom/` (incl. `10-observed-ui.md` + screenshots).
3. **Know where we stand:** read [`ROADMAP.md`](ROADMAP.md) → *Where we stand* (honest assessment by dimension and
by kind of user) and *Where we're going* (ordered priorities). The checklist counts features that *exist*; the real
gaps are quality and coverage: camera colour calibration, CR3 / compressed raws, per-model verification, render
fidelity against Lightroom, AI models, HDR / video / Classic modules. A ✅ row is not proof of parity — if you find a
✅ feature that is wrong or incomplete, downgrade it to 🟡 with a note.
4. **Pick work** from [`docs/parity.md`](docs/parity.md) → *Top gaps* (ordered by user impact; the tracker has one row per feature, menu item and shortcut). When you land a feature, update its row(s) and the gap list in the same commit, and the *Where we stand* / *Where we're going* sections of `ROADMAP.md` when a listed gap closes; `cargo xtask parity` (part of `ci`) checks that every `cmd:`/`ctl:` id and path the tracker cites still exists, and `cargo xtask parity --write` refreshes its summary.
3. **Know where we stand:** read [`ROADMAP.md`](ROADMAP.md) (stage, headline numbers, every dimension) and, for
method and evidence, [`docs/target-app-parity.md`](docs/target-app-parity.md). The checklist counts features that
*exist*; the real gaps are quality and coverage: camera colour calibration, CR3 / compressed raws, per-model
verification, render fidelity against Lightroom, AI models, HDR / video / Classic modules (raw detail:
[`docs/raw-parity.md`](docs/raw-parity.md)). A ✅ row is not proof of parity — if you find a ✅ feature that is
wrong or incomplete, downgrade it to 🟡 with a note.
4. **Pick work** from [`docs/gaps.md`](docs/gaps.md) (ranked by user impact; `B` marks beta blockers). The row-by-row
tracker is [`docs/parity-checklist.md`](docs/parity-checklist.md) (one row per feature, menu item and shortcut).
When you land a feature, update its row(s) and the gap entry in the same commit, and the numbers in `ROADMAP.md` /
`docs/target-app-parity.md` when a listed gap closes (bump each doc's *Last updated* line and revision history, per
craftrules `standards/progress-docs.md`); `cargo xtask parity` (part of `ci`) checks that every `cmd:`/`ctl:` id and
path the tracker cites still exists, and `cargo xtask parity --write` refreshes its summary.
5. Follow the autonomous operation protocol (`plan/execution-plan.md` §7). Don't stop to ask unless §7 lists the decision as the user's.
`plan/` is gitignored (local-only).
+12 -6
View File
@@ -5,12 +5,18 @@ LightCraft is a clean-room, open-source, pure-Rust photo library + non-destructi
## Start every session here
1. Read `plan/STATUS.md` (current milestone, next unchecked task, blockers).
2. Read the task in `plan/execution-plan.md` §3, the relevant section of `plan/architecture.md`, and the README/docs of the crate you touch. Behaviour/visual reference: `plan/lightroom/` (incl. `10-observed-ui.md` + screenshots).
3. **Know where we stand:** read [`ROADMAP.md`](ROADMAP.md) → *Where we stand* (honest assessment by dimension and
by kind of user) and *Where we're going* (ordered priorities). The checklist counts features that *exist*; the real
gaps are quality and coverage: camera colour calibration, CR3 / compressed raws, per-model verification, render
fidelity against Lightroom, AI models, HDR / video / Classic modules. A ✅ row is not proof of parity — if you find a
✅ feature that is wrong or incomplete, downgrade it to 🟡 with a note.
4. **Pick work** from [`docs/parity.md`](docs/parity.md) → *Top gaps* (ordered by user impact; the tracker has one row per feature, menu item and shortcut). When you land a feature, update its row(s) and the gap list in the same commit, and the *Where we stand* / *Where we're going* sections of `ROADMAP.md` when a listed gap closes; `cargo xtask parity` (part of `ci`) checks that every `cmd:`/`ctl:` id and path the tracker cites still exists, and `cargo xtask parity --write` refreshes its summary.
3. **Know where we stand:** read [`ROADMAP.md`](ROADMAP.md) (stage, headline numbers, every dimension) and, for
method and evidence, [`docs/target-app-parity.md`](docs/target-app-parity.md). The checklist counts features that
*exist*; the real gaps are quality and coverage: camera colour calibration, CR3 / compressed raws, per-model
verification, render fidelity against Lightroom, AI models, HDR / video / Classic modules (raw detail:
[`docs/raw-parity.md`](docs/raw-parity.md)). A ✅ row is not proof of parity — if you find a ✅ feature that is
wrong or incomplete, downgrade it to 🟡 with a note.
4. **Pick work** from [`docs/gaps.md`](docs/gaps.md) (ranked by user impact; `B` marks beta blockers). The row-by-row
tracker is [`docs/parity-checklist.md`](docs/parity-checklist.md) (one row per feature, menu item and shortcut).
When you land a feature, update its row(s) and the gap entry in the same commit, and the numbers in `ROADMAP.md` /
`docs/target-app-parity.md` when a listed gap closes (bump each doc's *Last updated* line and revision history, per
craftrules `standards/progress-docs.md`); `cargo xtask parity` (part of `ci`) checks that every `cmd:`/`ctl:` id and
path the tracker cites still exists, and `cargo xtask parity --write` refreshes its summary.
5. Follow the autonomous operation protocol (`plan/execution-plan.md` §7). Don't stop to ask unless §7 lists the decision as the user's.
`plan/` is gitignored (local-only).
+12 -10
View File
@@ -297,18 +297,20 @@ lightcraft --control 7980 ~/Pictures/trip
## Feature status
LightCraft is young and moving fast. **Where we honestly stand** (details in the [roadmap](ROADMAP.md#where-we-stand)):
LightCraft is young and moving fast: **alpha**. **Where we honestly stand** (details in the [roadmap](ROADMAP.md) and
[docs/target-app-parity.md](docs/target-app-parity.md)):
- **By feature count we're at ~79%** of Lightroom (core features 98%), tracked row by row in
[docs/parity.md](docs/parity.md).
- **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.
- **By feature count we're at ~81%** of Lightroom (core features 98%), tracked row by row in
[docs/parity-checklist.md](docs/parity-checklist.md).
- **As a day-to-day Lightroom replacement we're nearer 61% for the whole product, ~49% for a typical working photographer and ~64% for
casual use.** It's great for JPEG/DNG and most Sony / Panasonic /
Fujifilm / Nikon / older-Canon raws on one machine; see [docs/raw-parity.md](docs/raw-parity.md) for your camera.
- **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-7CR, 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](docs/raf-compression.md);
- **AI masks and denoise:** subject and sky selection are classical heuristics;
- **on-screen HDR display, video and the Classic Print / Book / Map modules.**
- **What's next:** see [where we're going](ROADMAP.md#where-were-going).
- **What's next:** see [the ranked gaps](docs/gaps.md) and [the roadmap](docs/roadmap.md).
| Area | Status |
|---|---|
@@ -318,10 +320,10 @@ LightCraft is young and moving fast. **Where we honestly stand** (details in the
| 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 |
| 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), Samsung SRW (uncompressed); embedded previews for every format incl. CR3 | 🟡 · CR3, compressed ORF and compressed SRW decode ⬜ |
| Detail: sharpening, luminance + colour noise reduction | ✅ · AI Denoise, Super Resolution ⬜ |
| RAW: DNG, CR2, CR3 (lossless CRX Bayer and version 0x100/0x200 C-RAW), ARW, NEF (uncompressed + lossless/lossy compressed, incl. lossy after split), 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, 12.8 bpp), Samsung SRW (uncompressed); embedded previews for every format incl. CR3 | 🚧 · other CR3 variants, compressed ORF / SRW and Nikon HE NEF decode ⬜ ([raw parity](docs/raw-parity.md)) |
| Detail: sharpening, luminance + colour noise reduction | ✅ · AI Denoise 🚧 (Bayer, user-installed weights), 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: HDR editing with a headroom limit, SDR rendition, Visualize HDR; export as ISO 21496-1 gain map JPEG, PQ AVIF or 32-bit float TIFF | ✅ · HDR display ⬜ |
@@ -332,7 +334,7 @@ LightCraft is young and moving fast. **Where we honestly stand** (details in the
| 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; video | ⬜ (see [roadmap](ROADMAP.md#where-were-going)) |
| AI: segmentation masks, AI denoise, super resolution, faces; video | 🚧 (see [gaps](docs/gaps.md)) |
| Web build (same UI in the browser via WASM): persistent library in OPFS/IndexedDB, Web Worker rendering, export downloads | ✅ · WebGPU, Safari/Firefox testing 🚧 |
<sub>✅ works today · 🚧 in progress · ⬜ not started</sub>
+138 -214
View File
@@ -1,242 +1,166 @@
# LightCraft roadmap
Milestones toward full Adobe Lightroom parity (cloud Lightroom first, then every Lightroom Classic module), with wall-clock
estimates for continuous (24/7) agent-driven development with 4–6 parallel agents. Estimates are calibrated on the sibling
projects (DrawCraft reached its first four milestones in ≈ 4½ h) and are revised as milestones land.
**Stage: alpha** · next: beta, ~14 points and ~340–600 h away
## Where we stand
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (full re-measure against Lightroom Classic 15.5 and the installed Lightroom 9.6; restructured to the progress-docs standard) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
*Honest assessment, 2026-10-08. Agents: read this before picking work. The checklist in
[`docs/parity.md`](docs/parity.md) counts features that **exist**; this section is about whether a photographer can
**switch** from Lightroom. Update it when a gap below closes.*
One-page summary of how close LightCraft is to Adobe Lightroom. Agents: read this, then pick work
from [docs/gaps.md](docs/gaps.md). The full assessment, method and evidence are in
[docs/target-app-parity.md](docs/target-app-parity.md).
**In one line:** the checklist says **79.7%** (P0 98.2%, P1 95.6%, P2 41.6%), but measured by whether a working
photographer could replace Lightroom without noticing, we are at roughly **60–70%**. The remaining gap is mostly
**quality of results and camera coverage**, not missing buttons.
## Headline numbers
Caveat on the checklist: ✅ is set by whoever lands a feature, and nobody has systematically checked rows against
Lightroom's behaviour or output. Bugs keep turning up in ✅ areas (CR2 colour-filter phase on some Canon models #85,
duplicate Local entries #22, black GPU exports on an Intel iGPU #78).
### By dimension
| Dimension | Estimate | What's true today | Biggest gaps |
|---|---:|---|---|
| **Feature checklist** | 79.7% | P0 core and P1 nearly complete: import (Add / Copy / Move, templates, devices), library, grid/loupe/compare/survey, every Edit slider, curves, colour grading, masking tools, crop/Upright, heal/clone, presets/profiles, versions/history, sync, export, menus, shortcuts | P0: full-resolution zoom detail; P1: lens-profile database, content-aware fill (patch synthesis), video playback/trim |
| **RAW coverage** (formats people shoot) | ~55% | DNG (all kinds), CR2, CR3 lossless Bayer and version 0x100/0x200 C-RAW (M50/R100/R8 pixel-exact corpus), ARW, NEF (uncompressed + Huffman lossless/lossy), RAF (uncompressed, lossless/lossy compressed Bayer and X-Trans), uncompressed ORF, uncompressed Samsung SRW (NX5 to NX1100, EX1, WB2000), RW2 / RWL / Panasonic RAW (every raw format, checked on 178 files from 118 Panasonic and Leica bodies), PEF; every container's embedded preview (incl. CR3) | **CR3** (every Canon since ~2018), compressed ORF, compressed Samsung SRW (NX1, NX30, NX300, NX500, NX2000, NX3000, NX3300, NX mini), Nikon lossy-after-split, Canon sRAW, HEIC/AVIF. NEFs labelled compressed but stored uncompressed (Z 6 packed 14-bit, D850 12-bit uncompressed). Nikon High Efficiency NEF (HE / HE★: Z 8, Z 9, Z 6III, Z f; JPEG XS-based, preview only, #193). Per-model verification is thin (~55 corpus files vs >1,000 models) |
| **Colour & image quality** | ~55–65% | Pipeline is complete and fast; GPU path CPU-exact within 1/255 | **No measured camera calibration database**: ARW, NEF, RW2, RAF, CR3, CR2 and PEF have guarded camera-JPEG colour estimates, with bundled ILCE-7CR, ILCE-7M4, X-H2S and X-T4 profiles (docs/camera-preview-colour.md); 52 models whose JPEG fit is rejected start from matrices fitted to measured spectral sensitivities; other non-DNG raws and rejected estimates use a neutral matrix. Colour fidelity remains incomplete. No lens-profile database. No measured fidelity against Lightroom (tone, highlights, texture/clarity, NR, sharpening are tuned by eye) |
| **AI & computational** | ~15–20% | Assisted culling (focus, bursts), auto tone, HDR/panorama merge; subject/sky/background masks as classical heuristics, or the photo's own segmentation mattes when it ships them (DNG semantic masks, e.g. iPhone ProRAW's sky matte); non-destructive Bayer RAW denoise with opt-in weights on pure-Rust CPU/GPU; **faces (MVP, [docs/faces.md](docs/faces.md))**: a pure-Rust detector (a 232 KB opt-in download), opt-in recognition models (one-click download or add a file; they run on the shared pure-Rust CPU interpreter; pinned SFace/AuraFace embeddings agree with an independent reference runtime on 40 public crops; one-thread medians 34–36 / 233–252 ms (AuraFace remains expensive)), a background scan that finds and embeds faces, name suggestions, a person's page with look-alike faces to confirm, an Unnamed faces section (look-alikes together, select a group and name it at once) | Real segmentation masks (subject, sky, people, objects, landscape, depth), denoise model policy / linear RGB / quality verification, super resolution, lens blur, generative remove, natural-language search; for faces: clusters with separators between groups, small faces in large photos (the detector looks at 640 px), thresholds calibrated on live faces, writing face regions back to XMP. **Blocked on a model strategy** (licensable weights or our own training; pure-Rust inference is feasible) |
| **Workflow & library** | ~85% (single machine) | Robust catalog (journal + snapshots, background compaction, crash-tested), 85k-photo libraries stay responsive, Local browsing with automatic cleanup, XMP interop, keywords, smart albums, Move import | Opening an 85k library takes 1.7–4.7 s; no cloud sync (out of scope), no tablet companion (#74, roadmap), shared albums, publish services, tethering |
| **Classic modules** | ~30% | Geotagging from GPX track logs, soft proofing (partial), slideshow (basic), paginated contact-sheet PDF export (A4/Letter, layout/captions, current edits, 150 dpi sRGB) | **Map view, Book, full Print module, Slideshow module, Web, publish services**: contact sheets work, custom print packages and printer colour management remain missing |
| **HDR & video** | ~25% | HDR editing (headroom limit, SDR rendition, Visualize HDR); gain map JPEG, PQ AVIF and float TIFF export | On-screen HDR display, HLG, HDR settings from crs XMP; video play/trim/edit/export |
| **Platform & robustness** | ~70% | macOS native; Windows/Linux builds; web via WASM; no-panic lints workspace-wide, `unsafe` confined to `crates/sysmem`; failed saves are reported; GPU errors fall back to CPU | Windows installer UI unverified on Windows (PR #79); GPU path proven only on Apple + user reports; English, Simplified/Traditional Chinese, Japanese, Brazilian Portuguese, Spanish, German, Russian and Ukrainian UI (see docs/localization.md); remaining technical errors; Traditional Chinese uses the Simplified Chinese font until craft-fonts has a TC face; accessibility partial; headless UI tests time out under machine load |
### By kind of user
| User | Readiness | What blocks them |
| | Value | Kind |
|---|---:|---|
| JPEG / DNG shooter, single machine | ~85% | Fidelity polish, AI masks |
| Nikon / Sony / Panasonic / older-Canon raw shooter | ~65% | Camera colour fidelity and coverage (ARW, NEF and RW2 preview estimates are only a starting point); embedded distortion is supported for Panasonic / Leica RW2 and the Sony ILCE-7RM4A (Bayer ARW, 24–105 / 200–600 tested); other lens metadata needs coverage and validation |
| Fujifilm raw shooter | ~65% | Uncompressed and lossless/lossy compressed RAF decoded; camera colour calibration remains missing. Verified on 13 bodies, including 14/16-bit GFX; see `docs/raf-compression.md` |
| Canon CR3 / Olympus compressed-raw shooter | ~45% | CR3 lossless Bayer and version 0x100/0x200 C-RAW develop from sensor data (M50, R100, R8 verified pixel for pixel); other CRX variants and compressed ORF open as embedded JPEG previews. Camera colour and broader model verification remain |
| Lightroom Classic power user | ~45% | Print, Book, Map, publish, tethering |
| Relies on AI (masks, denoise) | ~25% | Object / Describe masks via optional SAM 3 (download not yet hosted); Bayer AI denoise needs separately installed weights; X-Trans/linear RGB, model policy and quality parity remain open |
| **Feature breadth** (checklist) | **81.1%** of 517 rows (P0 98.0%, P1 95.1%, P2 46.9%) | measured: [parity-checklist.md](docs/parity-checklist.md) recount |
| **Feature breadth** (weighted by use) | **~77%** | estimated |
| **Ready for real work** (full target) | **~61%** (56–66%) | estimated: weighted sum over the dimensions |
| **Mainstream practitioner** | **~49%** (44–54%) | estimated |
| **Essentials user** | **~64%** (59–69%) | estimated |
| Remaining to **beta** | **~340–600 h** (Opus 5.5 agent hours, ~60% parallel) | estimated |
| Remaining to **full parity** | **~1,000–1,800 h** (~70% parallel) | estimated |
## Where we're going
Each audience with its own hours (Opus 5.5 agent wall-clock hours to ~95%):
Priorities, in order. Each points at tracker rows in [`docs/parity.md`](docs/parity.md) → *Top gaps*.
| Audience | Ready | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates |
|---|---:|---:|---|
| Full target (ready for real work) | **~61%** | **1,000–1,800 h** (~70% parallelizes) | raw colour, lens and camera data; AI models; Classic output modules; localization; plug-in ecosystem |
| Mainstream practitioner | **~49%** | **450–840 h** (~60% parallelizes) | camera colour and render fidelity; CR3 / ORF / HE NEF; lens database; subject / sky masks; Lightroom XMP exchange; stability |
| Essentials user | **~64%** | **160–300 h** (~50% parallelizes) | default raw look for popular cameras; launch stability; basic-slider feel; opening CR3 / HEIC files people send |
1. **Camera colour calibration of our own** (LR-PROF-CAMERACOLOR, P0): fit each camera to its own embedded JPEG, use
matrices the files carry themselves, then chart shots. Sony ARW, Nikon NEF, Panasonic RW2, Fujifilm RAF, Canon CR3/CR2,
Pentax PEF, Samsung SRW and Olympus ORF have the file-local fit (matrix + tone curve from their own JPEG; CR2 and PEF
since issue #310, not yet checked on the corpus); 52 models whose fit is rejected fall back to matrices fitted to
measured spectral sensitivities (rawtoaces-data); then validate fidelity.
2. **Raw formats, clean-room** (LR-IMP-FORMATS, P0): Remaining **unverified CR3 CRX** variants, compressed ORF, NEF
lossy-after-split, sRAW. Decided 2026-10-05: write our own decoders from prose descriptions (never decoder source,
no LGPL dependency); compressed NEF (#86) is the template.
3. **Verified camera coverage** (LR-IMP-CAMERA-COVERAGE, P0): a CC0 sample per model in the corpus, each decoded and
checked for plausible colour; fix per-model bugs (#85).
4. **Render fidelity suite** (LR-BEHAV-RENDER-FIDELITY, P1): measure our output against Lightroom on the same CC0 raws
(references stay in the local `plan/`), then tune against the numbers.
5. **Lens profiles of our own** (LR-EDIT-OPTICS-PROFILE, P1): DNG, Panasonic / Leica RW2 and Sony ILCE-7RM4A Bayer ARW
embedded distortion are supported; broaden validation and decode remaining vignetting / lateral CA metadata.
6. **AI model strategy** (maintainer decision): which permissively licensed models (or our own training) for
segmentation masks and denoise. Bayer denoise inference is implemented in pure Rust with an opt-in GPL model; release policy and independently licensed weights remain open. Unblocks M12 and Enhance. Face detection and recognition run on our own checked Rust engine. Object / Describe masks now
run Meta's SAM 3 in pure Rust (optional, user-consented download under the non-OSI SAM License; CDN mirrors still
to be set up, docs/ai-masks.md); Subject / Sky / People, Raw Details and Super Resolution are still open.
7. **Then:** HDR (Q), the Classic output modules (expand contact-sheet PDF export into full Print, then Map view, Book, Slideshow), video (R), localisation
and accessibility.
The gap between breadth and readiness is quality and coverage, not missing buttons: camera colour is
estimated rather than measured, CR3 decodes on three verified Canon bodies, compressed ORF and HE NEF
open as previews, rendering is tuned by eye, AI masks are heuristics, there is no lens database, and
tests run in CI on FreeBSD only. **Why alpha:** core workflows run end to end, but readiness is below
the ~75% beta bar (it is above the ~40% alpha bar) and Lightroom's main inputs, raw files, still have blocking gaps (Canon, ~30% of
raw users, decodes CR3 on three verified bodies). It passes the alpha gate: all six core workflows
(import, cull, develop, save and reopen, batch looks, export) work end to end on macOS
([docs/roadmap.md](docs/roadmap.md#alpha-gate)). The three readiness numbers and their weights and discounts are in
[target-app-parity.md](docs/target-app-parity.md#ready-for-real-work-mainstream-practitioner-and-essentials-user).
Hours are calibrated on this repo's PR history; see
[target-app-parity.md](docs/target-app-parity.md#how-hours-are-calibrated).
Already closed in the week of 2026-10-03: compressed NEF (#10), Move import (#29), per-library smart-preview folder,
Local roots / cleanup, grid and catalog performance at 85k photos (#35, #37), failed-save reporting, GPU export
hardening (#78), copyright metadata (#51), GPX geotagging (#60), import tag help and folder templates (#31, #32).
## By dimension
Library folders now have records of their own in the catalog (`Catalog.folder_records`, keyed by folder path; colour
labels first). Photos still store full paths, so moving a whole disk or folder relinks each photo. If that becomes a
problem (an "Update Folder Location" for a renamed or replaced drive, journal growth on large moves), the next step is
the Classic model: photos point to a folder id (root + relative path), and the records keyed by path become those rows.
| Dimension | Ready | Breadth | Remaining | Doc |
|---|---:|---:|---:|---|
| Features | ~61% | ~77% (checklist 81.1%) | 600–1,100 h | [target-app-parity](docs/target-app-parity.md#features) |
| ↳ RAW cameras, colour, lens profiles | ~56% | 81% of 1,446 Adobe models decode, 16% verified | 255–480 h | [raw-parity](docs/raw-parity.md) |
| UI/UX fidelity | ~70% | ~85% | 40–70 h | [ui-parity](docs/ui-parity.md) |
| File formats (non-raw) | ~70% | ~85% | 30–55 h | [file-format-parity](docs/file-format-parity.md) |
| Hardware | ~40% | ~50% | 40–80 h | [hardware-parity](docs/hardware-parity.md) |
| Localization | ~52% of the 12 key languages | 7 of 12 present | 130–210 h (+145–255 h new scripts) | [localization-parity](docs/localization-parity.md) |
| Performance | ~70% | ~80% | 30–50 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
| Stability | ~60% | — | 30–60 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
| Platforms | ~60% | macOS, Windows, Linux, FreeBSD, web | 25–45 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
| Ecosystem / plug-ins | ~15% | ~25% | 40–80 h | [target-app-parity](docs/target-app-parity.md#by-dimension) |
| AI features | ~20% | ~30% | 120–220 h (overlaps features) | [target-app-parity](docs/target-app-parity.md#ai) |
Image navigation now supports native pinch zoom and two-finger pan in Detail, Compare and Reference views.
The whole-image preview still has a configurable size cap (2,560 px default), so 100% on larger photos does not
yet guarantee original-pixel detail; visible-region rendering remains a gap (LR-VIEW-ZOOM).
## Features
## Milestones
**Status legend:** ✅ done · 🚧 in progress · ⬜ not started
| # | Milestone | Scope (summary) | Estimate (h) | Status |
|---|---|---|---|---|
| M0 | Skeleton + visual shell | workspace, xtask CI + layering, geom/color/raster, develop model, pipeline v0, catalog v0, engine commands, Lightroom-look UI (grid, loupe, filmstrip, Edit panel), control channel, MCP, web build | 3–5 | ✅ |
| M1 | Library core | import (JPEG/PNG/TIFF/WebP), EXIF/XMP, persistent catalog (op log + snapshots), albums, ratings/flags/labels, filter/search/sort, thumbnail cache, 100k-photo grid | 6–10 | ✅ (100k-photo grid scale test pending) |
| M2 | Pipeline v1 (quality) | WB temp/tint, profiles, local tone mapping (highlights/shadows), curves, HSL, point colour, colour grading, texture/clarity/dehaze, vignette, grain, B&W, auto tone/WB, histogram, before/after | 10–15 | ✅ (look tuning vs our references ongoing) |
| M3 | RAW I | TIFF/DNG (LJ92, deflate, tiles, opcodes), demosaic (AHD/PPG/bilinear), highlight recovery, DNG colour model, CR2, NEF, ARW, embedded previews | 10–15 | 🚧 (DNG, CR2, ARW, NEF uncompressed + Huffman lossless/lossy, embedded previews ✅; NEF lossy-after-split ⬜) |
| M4 | Crop, geometry, optics | crop tool + overlays, straighten, Upright (auto/level/vertical/full/guided), manual transforms, CA, defringe, manual lens corrections | 6–10 | ✅ |
| M5 | Performance | source pyramids, wgpu compute pipeline (CPU oracle), draft/full renders, prefetch, budgets (16 ms slider updates on 24 MP) | 10–15 | 🚧 (stage cache, source pyramid, wgpu pipeline, prefetch, memory budget ✅; colour NR at half resolution, GPU histogram ⬜) |
| M6 | Masking | brush, linear/radial gradients, colour/luminance/depth range, add/subtract/intersect/invert, all local adjustments, masks panel | 8–12 | 🚧 (brush/linear/radial/colour/luminance range, add/subtract/intersect, masks panel ✅; depth range, AI masks ⬜) |
| M7 | Detail | sharpening + masking preview, luminance/colour NR, Denoise, Raw Details, Super Resolution | 6–10 | 🚧 (sharpening, luminance/colour NR ✅; AI Denoise 🟡 (Bayer, optional weights; policy/fidelity open); Raw Details, Super Resolution ⬜) |
| M8 | Heal / Remove | content-aware remove (PatchMatch), heal, clone, brush spots, visualize spots, red/pet eye | 6–10 | 🚧 (heal, clone, auto source, visualize spots, red/pet eye ✅; PatchMatch remove ⬜) |
| M9 | Presets, profiles, versions, sync | preset browser + amount, create/import presets, profile browser, versions, history, copy/paste/sync settings | 5–8 | ✅ |
| M10 | Export & share | export dialog (JPEG/PNG/TIFF/DNG/AVIF/JXL/original), sizing, sharpening, metadata, watermark, naming, batch jobs, XMP sidecars, HDR export | 6–10 | 🚧 (all formats incl. DNG/original, sizing, presets, background jobs, HDR gain map JPEG / PQ AVIF ✅; JXL encode ⬜) |
| M11 | RAW II | CR3, RAF (X-Trans), ORF, RW2, PEF, SRW, 3FR, IIQ + long tail; camera calibration DB; HEIC/AVIF/JXL import | 20–35 | 🚧 (CR3 lossless CRX and C-RAW, RAF uncompressed and lossless/lossy compressed, RW2 (every raw format), PEF, ORF uncompressed ✅; **camera colour calibration** 🚧 (guarded ARW, NEF, RW2 and RAF preview fitting; measured database still missing), CR3, compressed ORF ⬜) |
| M12 | AI & smart features | subject/sky/background/people/object masks, semantic search, faces/People (permissively licensed models, pure-Rust inference) | 20–40 | ⬜ |
| M13 | Merge | HDR merge (deghost), panorama (projections, boundary warp, fill edges), HDR panorama | 10–15 | ✅ |
| M14 | Video | import/playback/trim via FilmCraft crates, global edits + presets on video, video export | 6–10 | ⬜ |
| M15 | Classic modules | Map, Book, Slideshow, Print, Web; smart collections, stacks, virtual copies, publish services, tethering | 25–40 | 🚧 (smart albums, stacks, virtual copies, compare/survey ✅; Map/Book/Slideshow/Print/Web ⬜) |
| M16 | 1.0 polish | preferences, shortcut editor, accessibility, localization, packaging (dmg/msi/AppImage/web), hardening | 10–20 | 🚧 (settings, keyboard shortcuts sheet, packaging basics ✅; English/Chinese (Simplified, Traditional)/Japanese/Brazilian Portuguese/Spanish/German/Russian/Ukrainian localisation 🟡; accessibility and further locales ⬜) |
## Parity estimate (feature count updated 2026-10-08; effort estimate from 2026-10-02)
**By feature count** — from `docs/parity.md` (one row per Lightroom feature, menu item and shortcut; `cargo xtask
parity` prints this line on every run, so it stays current):
| Scope | Weighted completion | Rows | 2026-10-02 |
| Area | Ready | Breadth | Remaining |
|---|---:|---:|---:|
| P0 (core) | **98.2%** | 200 | 98.7% |
| P1 (important parity) | **95.6%** | 149 | 94.4% |
| P2 (later / AI / niche, incl. Classic modules) | **41.6%** | 160 | 29.4% |
| **All in-scope rows** | **79.7%** | 509 | 75.6% |
| Import and library | 80% | 90% | 25–45 h |
| RAW decoding and camera coverage | 76% | 81% | 120–220 h |
| Colour, camera profiles, render fidelity | 35% | 65% | 80–150 h |
| Global develop adjustments | 70% | 93% | 30–60 h |
| Optics, lens profiles, crop and geometry | 50% | 80% | 40–80 h |
| Masking | 45% | 67% | 60–110 h |
| Remove, heal, Enhance | 30% | 45% | 70–130 h |
| Presets, profiles, versions, sync | 85% | 95% | 8–15 h |
| Export | 75% | 89% | 15–30 h |
| Merge and HDR | 60% | 85% | 20–35 h |
| Views, compare, zoom, culling | 70% | 90% | 15–30 h |
| Classic output modules (Map, Book, Slideshow, Print, publish, tethering) | 10% | 15% | 90–150 h |
| Video | 0% | 0% | 25–45 h |
The 2026-10-05 count includes three new 🟡 rows that make quality gaps visible (camera colour calibration, verified
camera coverage, render fidelity), which is why P0 dipped slightly.
Weights and evidence: [target-app-parity.md](docs/target-app-parity.md#features).
✅ counts 1, 🟡 ½, ⬜ 0; out-of-scope rows (cloud sharing, Adobe accounts…) are left out.
## Languages
**By remaining effort** — rows are not equal: a shortcut and the whole Book module are one row each, and what is
left is the heavy part (AI, video, Classic output modules, undocumented raw codecs). Remaining work in **Opus agent-hours**
(one agent working continuously; calibrated on this project — a single lead agent closed ≈ 45 tracker rows of
UI/feature work in ≈ 5 h on 2026-10-01, and ≈ 60 more (preset import incl. `.lrtemplate` / DNG / zip and masks, smart-album
rule editor, auto sync, keyword and label sets, import options and DNG conversion, smart previews, external-editor round
trip, slideshow, auto import…) in ≈ 12 h on 2026-10-02; four to six parallel agents built M0–M13 in ≈ 25 active hours):
Measured from `crates/ui-egui/locales` (share of 2,304 catalog messages translated); none is `full`
while lower-layer errors stay English. Detail: [localization-parity.md](docs/localization-parity.md).
| Work package | Tracker rows | Agent-hours | Risk |
| Language | Code | Translated | Status |
|---|---|---:|---|
| Remaining P0/P1 UI and library features (folder rename/move, keyword painter, people view…) | ≈ 8 | 5–10 | low |
| Raw codecs: CR3 (CRX), compressed ORF, NEF lossy-after-split, HEIC/AVIF decode | LR-IMP-FORMATS | 40–80 | **high** — clean-room black-box analysis, no permissive specs |
| Lens-profile database of our own (calibration targets, fitting, data) | LR-EDIT-OPTICS-PROFILE | 15–30 | data collection |
| Video: playback, trim, edits, export (pure-Rust decode, ideally shared with FilmCraft) | R. Video | 20–40 | medium |
| AI: subject / sky / background / people / object masks, object-aware remove, AI denoise, super resolution, lens blur, people & faces, natural-language search, culling | ≈ 30 | 80–150 | **high** — permissively licensed weights, pure-Rust inference, maybe training |
| HDR editing, display, visualisation and export | Q. HDR, LR-EXP-HDR | 15–25 | medium |
| Classic modules: Map, Book, Slideshow module, Print, publish services, tethering, soft proofing | ≈ 50 | 60–100 | medium (large, well-understood) |
| Smaller P2 items: Enhance dialog, export to Photos, help / what's new, accessibility, localisation, sidecar variants | ≈ 15 | 12–25 | low |
| Look tuning, performance budgets (colour NR at half resolution on CPU + GPU, 100k-photo library), packaging, hardening | — | 25–45 | medium |
| **Total remaining** | | **≈ 270–505** | |
| English | en | 100% | full (source) |
| Simplified Chinese | zh-hans | 87% | partial |
| Spanish | es | 86% | partial |
| Hindi | hi | 0% | none (no Devanagari shaping) |
| Arabic | ar | 0% | none (no RTL / shaping) |
| French | fr | 88% | partial |
| Portuguese (Brazil) | pt-br | 85% | partial |
| Indonesian | id | 0% | none |
| Japanese | ja | 87% | partial |
| German | de | 91% | partial |
| Korean | ko | 0% | none (no Hangul face) |
| Vietnamese | vi | 0% | none |
Spent so far ≈ 105–145 agent-hours, so **by effort the project is ≈ 20–35% of the way to complete Lightroom + Classic
parity**, and ≈ 45–60% of the way for cloud-Lightroom parity without AI and the Classic modules (remaining ≈ 130–255 h,
most of it the raw codecs, lens data, video and HDR).
Also shipped: Traditional Chinese (87%), Russian (74%), Ukrainian (99%).
**Wall clock:** ≈ 270–505 h for one agent working alone; with 4–6 parallel agents (≈ 70% parallel efficiency, merges and
CI under load cost the rest) **≈ 65–125 h of continuous work**. The AI package and the raw codecs carry most of the
uncertainty: they can finish faster if suitable permissive models / documentation turn up, or stall on licensing.
## Upcoming
## Totals
Ranked toward beta; detail in [docs/roadmap.md](docs/roadmap.md), gaps in [docs/gaps.md](docs/gaps.md).
Remaining from 2026-10-02 evening (see *Parity estimate* above for the breakdown):
1. Camera colour of our own: measured calibration for the popular models (50–90 h)
2. CR3 for every Canon body (25–45 h)
3. Render-fidelity suite against Lightroom, then tuning (30–60 h)
4. Full-resolution zoom (8–15 h)
5. AI masks: Subject / Sky / People (40–70 h + model decision)
6. Compressed ORF and HE NEF (28–55 h)
7. Lens profile database of our own (40–80 h)
8. Tests in CI on macOS, Windows and Linux (6–12 h)
9. Per-model raw verification (20–35 h)
| Target | Remaining agent-hours | Wall clock, 4–6 parallel agents |
|---|---:|---:|
| Cloud-Lightroom parity without AI or Classic modules | ≈ 130–255 h | ≈ 35–65 h |
| Full parity incl. AI, video and the Classic modules | ≈ 270–505 h | ≈ 65–125 h |
## Progress log
The milestone estimates in the table above were made before work started and are kept for calibration (M0–M13 took
≈ 25 active hours with parallel agents against an estimate of ≈ 110–170 h for those milestones).
- 2026-10-10 (RAW): RAW measured model by model against Adobe's 1,446-model list (234 verified, 943
unverified, 233 preview-only, 36 unsupported; ~84% of photographers' cameras decode, ~40% on a
verified body). Full ~61%, mainstream ~49%, essentials ~64%; beta ~14 points away.
- 2026-10-10 (final): full ready is a weighted sum over the dimensions (~59%; method aligned with
the standard); mainstream practitioner ~51% (450–840 h), essentials user ~63% (160–300 h);
alpha gate passes.
- 2026-10-10: full re-measure for the progress-docs standard: stage alpha, ready ~55%, checklist
81.1%; new docs (target-app-parity, gaps, roadmap, architecture, raw / file-format / hardware / UI
/ localization parity); `docs/parity.md` renamed `docs/parity-checklist.md`. Landed today: Nikon
lossy-after-split NEF (#633), ORF 12.8 bpp (#651), HDR gain map JPEG / PQ AVIF / float TIFF export
(#646), Lightroom-like Auto (#628), activity stack.
- 2026-10-09: Sony ILCE-7CR camera colour: bundled profile from 125 photos; on 26 withheld photos mean
ΔE vs the camera JPEG 4.07 → 3.29. HEIC in release builds (#609), Samsung uncompressed SRW,
contact-sheet PDF export, Ukrainian and French UI, release v0.5.0.
- 2026-10-08: independent Rust CR3 lossless and version 0x100/0x200 C-RAW decoding, six exact
full-sensor regressions on M50 / R100 / R8; guarded CR3 camera-JPEG colour fitting
([cr3.md](docs/cr3.md)).
- 2026-10-08: Fujifilm lossless / lossy compressed RAF: pure-Rust striped decoder, full sensor arrays
verified on 17 CC0 and 7 supplied files (13 bodies). Fujifilm camera colour: bundled X-H2S / X-T4
profiles from 201 / 545 photos; on 150 withheld files mean ΔE X-H2S 1.70 → 1.62, X-T4 2.43 → 2.34.
AI RAW denoise (#384), Lightroom catalog import, German, Spanish and Russian UI.
- 2026-10-07: Panasonic RW2 / Leica RWL / Panasonic RAW decode in every raw format, established on
178 CC0 files from 118 bodies; RW2 file-local camera look (140 of 174 files). Faces: recognition in
pure Rust and People view.
- 2026-10-03 – 10-05: community PRs (#42–#51, #60) and 25+ issues: compressed NEF, Move import,
folder templates, Local roots and cleanup, 85k-photo grid and catalog performance, background
compaction, failed-save errors, GPU export hardening. Added the honest *Where we stand* assessment
and tracker rows for camera colour, camera coverage and render fidelity.
- 2026-10-02: parity estimate added (`cargo xtask parity` prints weighted completion); milestones
refreshed.
- 2026-10-01: RAW II formats: RAF (uncompressed Bayer + X-Trans), RW2 (packed), PEF (incl. Huffman),
ORF (uncompressed); embedded previews for every container incl. CR3; raw corpus test with 37 CC0
samples.
- 2026-09-30 (later): app running with the full Lightroom-style UI; pipeline v0; DNG / CR2 / ARW;
README showcase. ≈ 8 h elapsed.
- 2026-09-30: roadmap created; M0 in progress; research docs (Lightroom reference, Rust imaging
ecosystem) complete.
## Risks that coding hours alone don't retire
## Revision history
- **AI features** (subject/sky/people masks, generative remove) need model weights with licences we can ship; classical
fallbacks first. No permissively licensed sky-segmentation or raw-denoise model was found — we may need to train our own.
- **Camera colour and lens data** is a data problem: we never use Adobe's matrices, DCPs or LCPs. DNG-embedded data first,
then our own calibration; long-tail camera/lens coverage grows over time.
- **Raw-format sources:** decided 2026-10-05: decoders are written from *prose* format descriptions (even ones
published alongside GPL code); decoder source is never read. Still open: freedom-to-operate review for local
Laplacian filters, PatchMatch and HEVC (HEIC).
- **Look parity** with Adobe's default rendering is tuned by eye today; the planned fidelity suite (LR-BEHAV-RENDER-FIDELITY)
turns it into measured comparisons against local-only Lightroom references. Retuning changes existing edits, so it
ships as a new process version (`docs/process-versions.md`): photos keep their look until they are updated.
## Raw format coverage and known gaps
Sony ILCE-7M4 downsized lossless ARW (subsampled YCbCr 4:2:0 / 4:2:2 tiles) now decodes to linear RGB;
private 3:2 & 4:3 examples verified through native rendering & full-resolution 16-bit export.
CR3 lossless Bayer and version 0x100/0x200 C-RAW sensor decoding is verified pixel-exactly on Canon M50, R100 and R8; any other CR3, or one that fails to decode, opens from its embedded JPEG as before. See [`docs/cr3.md`](docs/cr3.md) for coding limits, reference provenance and colour limitations.
Decoded (CC0 corpus from raw.pixls.us, `cargo xtask corpus --download`, `crates/raw/tests/corpus.rs`): DNG (uncompressed,
LJ92, lossy JPEG / Smart Previews, Deflate, float, linear, DNG 1.7 JPEG XL tiles: lossless ones bit-exact on synthetic files,
lossy ones unclipped in the declared linear primaries, checked on one real file), CR2, ARW (uncompressed, ARW2, LJ92; as-shot white balance and black level of pre-2017 bodies from the encrypted
`SR2SubIFD`, decrypted with a keystream recovered by black-box analysis, `crates/raw/src/vendor/sr2.rs`, `crates/raw/src/vendor/arw.rs`), NEF/NRW uncompressed and Huffman-compressed (lossless, lossy type 1/2, 12/14-bit), RAF uncompressed and lossless/lossy compressed (Bayer and
X-Trans, 14/16-bit real-file verification), RW2 / Leica RWL / Panasonic RAW in every raw format (compressed formats 4 and 6, the prefix-coded strips of format 8,
packed formats 2, 5 and 7, the 16-bit words of the 2005–2007 bodies; all recovered by black-box analysis of 178 CC0 files from
118 bodies, `crates/raw/src/vendor/rw2.rs`), PEF (uncompressed and Huffman), ORF uncompressed (16-bit and 12-bit packed). Supported containers yield their embedded JPEG preview when present (including CR3). The engine uses it for RAW variants it cannot decode yet; HEVC-only CR3 previews are not decoded.
Not decoded yet — preview only (no permissively licensed description; black-box analysis incomplete):
- **Olympus compressed ORF**, **Canon CR3 unverified CRX variants** (M11.1), **Canon sRAW/mRAW**.
**Camera colour matrices:** ARW, NEF, RW2, RAF, CR3, CR2, PEF, Samsung SRW and Olympus ORF files can use guarded, separate chromaticity and tone estimates from their own embedded JPEG (see `docs/camera-preview-colour.md`); this is a per-file camera-look estimate with relative WB, not measured calibration or absolute-Kelvin WB. 52 models whose fit is rejected (or that have no usable JPEG) start from matrices fitted to their measured spectral sensitivities instead (rawtoaces-data, Apache-2.0; `crates/raw/src/spectral.rs`). Other non-DNG raws and rejected fits use the documented neutral fallback (camera RGB ≈ linear sRGB, flagged
`matrix_is_fallback`) with the file's as-shot white-balance multipliers. Clean sources to evaluate next: manufacturer
matrices stored in the files themselves (Olympus ImageProcessing `ColorMatrix`, Pentax equivalents; Panasonic RW2 files carry none) and our
own chart-based calibration (M11.4). Adobe matrices are never used.
## Lightroom Classic catalog migration
File → Import Lightroom Catalog… reads `.lrcat` plus committed WAL pages directly through a pure-Rust
SQLite reader. Originals stay in place; ratings, flags, labels, XMP metadata, hierarchical keywords,
collections/sets, virtual copies and supported develop settings migrate into LightCraft. Existing edits
are preserved by default, reimport identities are persistent, and source settings/history/snapshots are
archived before catalog mutation. Missing originals remain available for relinking.
Rendering is approximate: unsupported Adobe profiles/AI/process settings are reported and archived;
history/snapshots remain source data, and smart collections import current membership. The Lightroom
database is read-only; LightCraft owns subsequent edits. See `docs/lightroom-catalog-import.md`.
## Log
- 2026-09-30: roadmap created; M0 in progress; research docs (Lightroom reference, Rust imaging ecosystem) complete.
- 2026-09-30 (later): app running with the full Lightroom-style UI; pipeline v0; DNG/CR2/ARW; README showcase. ≈ 8 h elapsed.
- 2026-10-02: parity estimate added (xtask parity prints weighted completion); milestone statuses refreshed.
- 2026-10-08: Fujifilm camera colour: guarded JPEG matching and relative WB, plus bundled X-H2S/X-T4 profiles from 201/545 photos. On 150 withheld files the pooled profiles improve mean ΔE slightly over per-file fitting (X-H2S 1.70 → 1.62, X-T4 2.43 → 2.34); dark X-H2S samples 8.74 → 2.25. Measured calibration remains open.
- 2026-10-08: Fujifilm lossless/lossy compressed RAF: pure-Rust striped decoder; full sensor arrays verified against a black-box reference on 17 CC0 files and 7 supplied X-H2S / X-T4 files (13 camera bodies, 14/16-bit Bayer and X-Trans). Camera colour calibration remains a separate gap.
- 2026-10-01: RAW II formats: RAF (uncompressed Bayer + X-Trans), RW2 (packed), PEF (incl. Huffman), ORF (uncompressed); embedded previews for every container incl. CR3; raw corpus test with 37 CC0 samples.
- 2026-10-03 – 10-05: community PRs (#42–#51, #60) and 25+ issues landed: compressed NEF, Move import, folder templates,
Local roots and cleanup, 85k-photo grid and catalog performance, background compaction, failed-save errors, GPU
export hardening, clippy 1.99. Added the honest *Where we stand* assessment and *Where we're going* priorities; added
tracker rows for camera colour, camera coverage and render fidelity.
- 2026-10-07: Panasonic RW2 / Leica RWL / Panasonic RAW decode in every raw format (compressed 4/6/8, packed 2/5/7,
16-bit words), black levels, in-camera aspect crops and mapped-out defects established on 178 CC0 files from 118
bodies; RW2 gets the file-local camera look (accepted on 140 of 174 files with a preview).
- 2026-10-08: independent Rust CR3 lossless and version 0x100/0x200 C-RAW decoding, six exact full-sensor regressions on M50/R100/R8; any CR3 decode error falls back to the embedded JPEG; guarded CR3 camera-JPEG colour fitting with independent framing validation (`docs/cr3.md`). Unverified CRX variants and broader model verification remain.
- 2026-10-09: Sony ILCE-7CR camera colour: bundled profile from 125 photos. On 26 withheld photos mean ΔE vs the camera JPEG 4.07 → 3.29; all 131 photos accepted, where 8 fell back to the neutral matrix without it. Measured calibration remains open.
## Chinese and Japanese interfaces, and text watermarks
English, Simplified Chinese, Traditional Chinese (Taiwan) and Japanese interface languages are persisted in UI state, and the
language table (`crates/ui-egui/src/i18n.rs`) drives the menus, settings and fonts, so another
language is a table entry plus two catalogs (docs/localization.md). Core menus and panels are
translated; untranslated text retains English. Ukrainian covers all existing catalog keys, command/control/rule labels
and format messages, with count-neutral labels and numeric dates; technical errors from lower layers remain English.
CJK glyphs (Chinese: Noto Sans CJK SC; Japanese UI:
BIZ UDPGothic; watermarks: BIZ UDMincho) come from storytold/craft-fonts, embedded by builds made
with the optional `CRAFT_FONTS_DIR` input (all releases), so no system fonts are needed. Text watermarks now accept
`vertical: true` in export JSON/presets and expose an orientation selector. Japanese
characters stay upright in top-to-bottom columns, with newlines starting columns to the
left. This is basic lettering, without tate-chu-yoko, ruby, kinsoku, or general vertical
OpenType shaping. The same coverage renderer serves 8/16/32-bit exports.
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | minor | RAW measured model by model; RAW decode and colour as explicit rows: full 59% → 61%, mainstream 51% → 49%, essentials 63% → 64%; beta ~14 points |
| 2026-10-10 | minor | Full ready restored to the additive weighted sum (~59%; method aligned with the standard, no new evidence); hours per audience; beta ~16 points away |
| 2026-10-10 | minor | Mainstream practitioner and essentials user numbers; full ready 55% → 46% (method written down); beta 340–600 h |
| 2026-10-10 | minor | Alpha gate added (core-workflow check): passes, stays alpha |
| 2026-10-10 | major | Restructured to the progress-docs standard; re-measured; *Where we stand*, *Parity estimate* and *Totals* moved to docs/target-app-parity.md, milestones and risks to docs/roadmap.md, raw coverage to docs/raw-parity.md, catalog migration to docs/file-format-parity.md, CJK notes to docs/localization-parity.md |
| 2026-10-08 | minor | *Where we stand* by dimension and by kind of user |
| 2026-10-02 | major | Parity estimate and effort table |
| 2026-09-30 | major | Created |
+1 -1
View File
@@ -418,7 +418,7 @@ fn parse_one_region(item: &XmpValue, px_dims: Option<(f64, f64)>) -> Option<Regi
// frame and writes the orientation as the region's `mwg-rs:Rotation` (π for 3, −π/2 for 6, +π/2 for
// 8; 0 for 1) while `AppliedToDimensions` names the upright size. Turn it into the upright frame.
// MWG has no way to say "mirrored", so orientations 2/4/5/7 can't be told apart from their unmirrored
// twins here; boxes on mirrored photos are taken as written (see LR-LIB-PEOPLE in docs/parity.md).
// twins here; boxes on mirrored photos are taken as written (see LR-LIB-PEOPLE in docs/parity-checklist.md).
let rotation = item.field("mwg-rs:Rotation").and_then(XmpValue::text).and_then(parse_number).filter(|r| r.is_finite());
let (quarter, half) = (std::f64::consts::FRAC_PI_2, std::f64::consts::PI);
let (cx, cy, w, h) = match rotation {
+1 -1
View File
@@ -27,7 +27,7 @@ pub const LANGUAGE_COMMANDS: &[UiCommand] = &[
];
/// Every UI command: the languages, then everything else. `xtask parity` reads both tables from
/// this file, so an id listed in `docs/parity.md` is checked wherever it is declared.
/// this file, so an id listed in `docs/parity-checklist.md` is checked wherever it is declared.
pub fn ui_commands() -> impl Iterator<Item = &'static UiCommand> {
LANGUAGE_COMMANDS.iter().chain(UI_COMMANDS)
}
+1 -1
View File
@@ -192,7 +192,7 @@ pub fn format(m: Modifiers, k: Key) -> Option<String> {
/// Secondary key bindings for commands that already exist: `(shortcut, command id, params JSON)`.
/// They complement the primary shortcut declared on the command (Lightroom-desktop keys that our
/// primary keymap assigns elsewhere, see docs/parity.md → Shortcuts). Shown in Help → Keyboard Shortcuts.
/// primary keymap assigns elsewhere, see docs/ui-parity.md → Shortcuts). Shown in Help → Keyboard Shortcuts.
pub const ALIASES: &[(&str, &str, &str)] = &[
("Cmd+D", "library.selectNone", "{}"),
("Shift+E", "dialog.export", "{}"),
+70
View File
@@ -0,0 +1,70 @@
# Architecture
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created from the code; the full design notes stay in the local `plan/architecture.md`) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
How LightCraft is built today. The longer design document (`plan/architecture.md`) is local-only
(`plan/` is gitignored); this page is the committed, current summary. Sizes are Rust lines counted
on 2026-10-10 (≈ 202,000 tracked lines in 505 files: 24 library crates, 3 apps and `xtask`).
## Layers
`cargo xtask layers` (part of `cargo xtask ci`, `xtask/src/layers.rs`) enforces that nothing below
L5 depends on egui, eframe, winit or rfd, and that each crate only uses lower layers.
| Layer | Crates (lines) | Role |
|---|---|---|
| L0 | `geom` (1.4k), `color` (0.9k), `raster` (0.8k), `tiff` (2.0k), `fetch` (1.4k), `sysmem` (0.1k) | Matrices and warps, colour spaces and transfer functions, float image buffers, TIFF/IFD read and write, pinned HTTPS model downloads, the one `unsafe` FFI call (`malloc_zone_pressure_relief`) |
| L1 | `raw` (22.3k), `codecs` (7.3k), `meta` (4.3k), `develop` (2.5k), `denoise-core` (2.2k), `denoise` (2.7k), `faces` (5.3k), `scenes` (1.0k), `heif` (2.1k, optional) | Raw decoders and demosaic, DNG colour model; standard codecs and encoders; EXIF/XMP/IPTC; the non-destructive edit model and control specs; AI denoise; face detection and recognition; procedural demo photos; HEIC |
| L2 | `pipeline` (9.8k) | The develop pipeline: scene-referred float, resolution independent; the CPU reference (oracle) for everything else |
| L3 | `catalog` (11.0k), `gpu` (5.1k), `preview` (1.3k), `merge` (3.8k), `segment` (2.3k) | Library model and persistence; wgpu compute twin of the pipeline; thumbnail/preview cache and job pool; HDR and panorama merge; SAM 3 segmentation |
| L4 | `engine` (53.2k) | Session, command registry (everything is a command), history, render and export jobs, import, Lightroom catalog and preset import, faces index, view-models |
| L5 | `ui-egui` (46.9k), `mcp` (2.3k) | The Lightroom-style egui interface (swappable); the MCP server |
| L6 | `apps/lightcraft` (2.8k), `apps/lightcraft-cli` (1.5k), `apps/lightcraft-web` (3.4k), `xtask` (2.7k) | Desktop app (eframe + wgpu, native menus, control server), CLI (render, commands, calibrate, snapshot, MCP), WASM build, tooling |
## Data model
- **Photo** records in `catalog` hold the original's path, content hash, metadata, ratings, flags,
labels, keywords, faces and the current `develop::Settings`. Albums, smart albums (rule trees),
stacks, virtual copies, versions and folder records live alongside.
- **Persistence** (`crates/catalog/src/journal.rs`): an append-only journal of human-readable
operations plus periodic snapshots, compacted in the background; torn appends and crashes are
tested (`tests_torn_append.rs`, `tests_journal.rs`). A lock file guards against two writers.
- **Edits** are a `develop::Settings` value (every slider is a control spec with id, range and
default), normalized to image coordinates so previews and exports match. Process versions
(`docs/process-versions.md`) keep old edits rendering the same after a retune.
- **Sidecars**: XMP read and write with Adobe `crs:` interop (`docs/xmp-interop.md`); Lightroom
Classic `.lrcat` import through a pure-Rust SQLite reader (`docs/lightroom-catalog-import.md`).
## Rendering
1. **Decode** (`raw`, `codecs`): raw files to linear camera RGB (demosaic, black/white levels,
opcodes, highlight handling) and a camera-to-XYZ colour model; standard images to linear light
through their ICC profile.
2. **Develop** (`pipeline`): white balance, profile, exposure and tone (local Laplacian
highlights/shadows), curves, HSL / colour mixer, point colour, colour grading, texture, clarity,
dehaze, detail (sharpening, NR, AI denoise result), optics (lens profile, CA, defringe,
vignette), geometry (crop, Upright, transforms), masks with local adjustments, heal/clone, grain,
effects. Stage caching and a source pyramid make slider drags cheap.
3. **GPU** (`gpu`): the same stages in WGSL on Metal / DX12 / Vulkan, checked against the CPU path
(within 1/255); GPU errors fall back to the CPU (`docs/gpu-pipeline.md`).
4. **Display and export**: display-profile conversion (`docs/display-profiles.md`); export through
one encoder for app, CLI, MCP and web (`lightcraft_engine::export`).
## Agent control
Every action is an engine command (id, label, menu path, shortcut, params, enabled, run). The UI,
the CLI, the JSON-lines control channel (`docs/control-protocol.md`) and MCP (`docs/mcp.md`) all
dispatch by id, and headless snapshots render the UI without a window.
## Quality gates
`cargo xtask ci`: fmt, clippy `-D warnings` with the never-crash lints, the HEIF build, tests,
`parity` (every id and path cited in [parity-checklist.md](parity-checklist.md) exists), `layers`,
`assets` (every asset attributed, no Adobe formats) and the WASM build. Other workflows build and
test FreeBSD and Windows ARM64, lint packaging, and build releases.
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created from the code (crate sizes, layers, data model, rendering, control, gates) |
+79
View File
@@ -0,0 +1,79 @@
# File format parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; formats measured from the code and the target's Info.plist) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
Every format Lightroom reads or writes, with our support, fidelity and tests. Camera raw formats are
deep enough to have their own document: [raw-parity.md](raw-parity.md).
**How measured:** the target's document types come from the installed Lightroom 9.6
`Info.plist` (`CFBundleDocumentTypes`: catalog `mcat`, `xmp`, toolkit / module / library bundles, and
the raw-and-image list: jpg, tif, dng, heic and 27 raw extensions) plus Lightroom Classic's documented
import and export formats. Ours come from `crates/codecs/src/sniff.rs`, `crates/codecs/src/encode.rs`,
`crates/engine/src/export.rs`, `crates/engine/src/import.rs` and the tests named below.
## Images (non-raw)
| Format | Target reads | Target writes | LightCraft reads | LightCraft writes | Notes / tests |
|---|---|---|---|---|---|
| JPEG | ✅ | ✅ | ✅ (parallel decoder, ICC, EXIF orientation) | ✅ quality, size limit, ICC, metadata | `crates/codecs/src/jpeg.rs`, export tests |
| TIFF | ✅ 8/16/32-bit | ✅ 8/16-bit, LZW/ZIP | ✅ 1–64-bit integer, 16–64-bit float, bilevel, CCITT fax, WhiteIsZero | ✅ 8/16-bit, 32-bit float linear, none / LZW / ZIP | `crates/tiff`, `crates/codecs/src/tiff_codec.rs` |
| PNG | ✅ | ✅ | ✅ | ✅ | |
| PSD / PSB | ✅ (maximized-compatibility composite) | ✅ (Classic: PSD export, edit-in round trip) | ✅ merged composite | ⬜ (external-editor round trip writes 16-bit TIFF) | `crates/codecs/src/psd.rs` |
| HEIC / HEIF | ✅ | ⬜ (Classic) / HDR only | ✅ in every release build (`crates/heif`, heic-rs) | ⬜ | `heif` feature on by packaging scripts |
| AVIF | ✅ | ✅ (HDR) | ⬜ recognised, not decoded (no permissive pure-Rust AV1 decoder) | ✅ 8/10-bit, PQ HDR | |
| JPEG XL | ✅ | ✅ | ✅ (`jxl-oxide`) incl. DNG 1.7 JXL tiles | ⬜ | |
| WebP | not in its document types | ⬜ | ✅ | ✅ | beyond target |
| GIF, BMP | ⬜ | ⬜ | ✅ | ⬜ | beyond target |
| DNG (from raw) | ✅ | ✅ incl. lossy, embedded original | ✅ | ✅ uncompressed or LJ92; ⬜ lossy DNG, embedded original | `crates/raw/src/dngwrite.rs` |
| Render to DNG (15.5) | — | ✅ | — | ⬜ | new in Classic 15.5 |
| Original + sidecar | — | ✅ | — | ✅ | |
| HDR gain map JPEG (ISO 21496-1) | ✅ | ✅ | ✅ (gain map read) | ✅ | `crates/codecs/src/gainmap.rs` |
| PQ / HLG HDR | ✅ | ✅ AVIF, JXL, TIFF | — | 🟡 PQ AVIF, float TIFF; no HLG | |
| Contact sheet / print PDF | — | ✅ (Print module: PDF / JPEG / printer) | — | 🟡 paginated contact-sheet PDF (A4 / Letter, 150 dpi, sRGB) | `crates/engine/src/contact_sheet.rs` |
| Video (MP4, MOV, AVCHD…) | ✅ playback, trim, edit | ✅ export | 🟡 catalogued (kind, duration) | ⬜ | see video gap |
## Colour spaces and profiles
| Feature | Target | LightCraft |
|---|---|---|
| Export colour spaces | sRGB, Adobe RGB, Display P3, ProPhoto, Rec.2020, custom ICC | ✅ sRGB, Display P3, Adobe RGB-compatible, ProPhoto, Rec.2020 with gamut mapping (CPU and GPU), embedded ICC; ⬜ custom ICC output profiles; AVIF stays sRGB |
| Input ICC (JPEG / TIFF / PNG) | ✅ | ✅ matrix / TRC and LUT profiles (moxcms) |
| Soft proofing with printer profiles | ✅ | 🟡 |
## Metadata, sidecars, presets and catalogs
| Format | Target | LightCraft | Notes |
|---|---|---|---|
| XMP sidecars (`crs:` develop settings, ratings, keywords, regions) | read / write | ✅ read / write, manual (⌘S) and automatic | [xmp-interop.md](xmp-interop.md) |
| EXIF / IPTC / XMP embedded on export | ✅ | ✅ with metadata filters | `crates/meta` |
| Develop presets `.xmp` | ✅ | ✅ import (mapping of supported settings) | |
| Legacy presets `.lrtemplate` | ✅ (converted) | ✅ import | |
| Camera / creative profiles (`.dcp`, `.xmp` profiles) | ✅ | ⬜ deliberately (Adobe profile formats are never used); `.cube` LUT profiles ✅ | |
| Lens profiles `.lcp` | ✅ | ⬜ deliberately | |
| Other apps' presets | — | ✅ Luminar `.lmp` / `.mplumpack`, `.zip` bundles | beyond target |
| Lightroom Classic catalog `.lrcat` | native | 🟡 import (ratings, flags, labels, keywords, collections, virtual copies, supported develop settings; read-only pure-Rust SQLite incl. WAL) | [lightroom-catalog-import.md](lightroom-catalog-import.md) |
| Lightroom (cloud) library `.lrlibrary` | native | ⬜ | cloud library format, local cache only |
| Write back to `.lrcat` | native | ⬜ (one-way migration by design) | |
| Keyword lists (text) | import / export | ✅ | |
| GPX track logs | ✅ | ✅ | `crates/meta/src/gpx.rs` |
| Export presets, metadata presets, filename templates | ✅ (`.lrtemplate`) | ✅ own JSON | not interchangeable |
| Lightroom plug-ins (`.lrplugin`, `.lrdevplugin`) | ✅ | ⬜ | see ecosystem in [target-app-parity.md](target-app-parity.md) |
## Scores
| Part | Weight | Ready for real work | Kind |
|---|---:|---:|---|
| Standard image import / export | 35% | ~85% | estimated (table above; missing: AVIF read, JXL / PSD write, lossy DNG) |
| Sidecars, metadata, presets | 25% | ~85% | estimated |
| Lightroom catalog migration | 25% | ~50% | estimated (one-way, approximate rendering of unsupported settings) |
| HDR, print, video output | 15% | ~35% | estimated |
| **Non-raw file formats** | 100% | **~70%** | estimated; raw is in [raw-parity.md](raw-parity.md) (~50%) |
Remaining: **30–55 h** (AVIF decode 8–15 h if a permissive decoder is written or found; JXL encode
4–8 h; PSD write 4–8 h; lossy DNG and Render to DNG 4–8 h; HLG 3–5 h; catalog import depth 8–12 h).
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created from the code and the installed Lightroom's document types |
+77
View File
@@ -0,0 +1,77 @@
# Gaps: where LightCraft falls short of Lightroom
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; absorbs the checklist's Top gaps and the ROADMAP's honest assessment, re-ranked after a full re-measure) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
Every known shortfall, one entry each, ranked by user impact (how many Lightroom users hit it, and
how hard it blocks them), then by effort. **Agents pick work from the top** (the first entry nobody is
working on). When you close a gap, delete or shrink its entry, update its rows in
[parity-checklist.md](parity-checklist.md), and the numbers in [target-app-parity.md](target-app-parity.md)
and [ROADMAP.md](../ROADMAP.md) if they move.
Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app-parity.md#how-hours-are-calibrated)).
`B` marks a gap that blocks **beta**.
## Ranked
| # | Gap | Evidence | User impact | Hours | Doc |
|---:|---|---|---|---:|---|
| 1 B | **Camera colour is estimated, not measured** (LR-PROF-CAMERACOLOR). Raws start from a per-file fit to the camera JPEG, 4 bundled profiles or 52 spectral matrices; others use a neutral matrix | ΔE vs camera JPEG 2.9–10 after fitting (raw-parity.md); 0 chart-calibrated models vs 1,500 Adobe Standard profiles | every raw shooter sees colour that is close but not Lightroom's; some get neutral-matrix colour | 50–90 | [raw-parity](raw-parity.md#colour) |
| 2 B | **CR3 beyond three verified bodies** (LR-IMP-FORMATS): CRX variants other than those verified on M50 / R100 / R8 fall back to the preview; CR3 sRAW / mRAW and HEIF CR3 too | measured: Canon is the largest bucket (33% of photographers) and its share whose camera fully works is the lowest of the big four, 72%; 17 of 22 popular Canon bodies write CR3, 2 verified (raw-parity.md) | +6.5 points of photographers whose camera works, the biggest single raw gain | 25–45 | [raw-parity](raw-parity.md#remaining-work-ranked-by-photographers-unlocked-per-hour) |
| 3 B | **Render fidelity unmeasured** (LR-BEHAV-RENDER-FIDELITY): tone, highlights, texture / clarity / dehaze, NR and sharpening are tuned by eye | no side-by-side suite; a retune needs a new process version (only V1 exists) | edits imported from Lightroom look different; the look "isn't Lightroom's" | 30–60 | [raw-parity](raw-parity.md), [process-versions](process-versions.md) |
| 4 B | **Original-pixel detail at 100%** (LR-VIEW-ZOOM, P0): the whole-image preview is capped (2,560 px default); compare, overlays and soft proofing lack sharp zoom windows (#323) | checklist row 🟡 | checking focus, the first thing culling needs, isn't reliable on large files | 8–15 | [ui-parity](ui-parity.md) |
| 5 B | **AI masks: Subject, Sky, People, Background, Landscape** are heuristics; Object / Describe run SAM 3 but its download has no mirror configured | `crates/segment`; ai-masks.md; MASK rows 67% | masking is how most Lightroom users edit today | 40–70 + model decision | [target-app-parity](target-app-parity.md#ai) |
| 6 B | **Compressed ORF** (every Olympus / OM body since ~2008) | measured: 66 of 78 Olympus / OM models preview-only; `orf.rs` refuses; OM bucket 3% of photographers, 3% of them fully work | +2.6 points; best gain per hour of any raw gap (~0.2) | 8–15 | [raw-parity](raw-parity.md) |
| 7 | **Nikon High Efficiency NEF** (HE / HE★ on Z 8, Z 9, Z 6III, Z f, Z50II, Z5II when set to HE) | named and preview only (#193); needs a pure-Rust JPEG XS decoder | +1.1 points (only shots taken in HE; lossless works on the same bodies); low gain per hour (~0.04), so not a beta blocker | 20–40 | [raw-parity](raw-parity.md) |
| 8 B | **No lens profile database** (LR-EDIT-OPTICS-PROFILE): only DNG opcodes, RW2 in-file distortion and Sony ILCE-7RM4A distortion | Adobe ships 3,635 lens profiles; we never use them | distortion / vignetting correction is a default step for many | 40–80 + calibration shots | [raw-parity](raw-parity.md#lens-profiles) |
| 9 B | **Tests don't run in CI on macOS, Windows or Linux x64**: only FreeBSD runs `cargo test`; the others build packages | `.github/workflows/` (freebsd, packaging-lint, release, windows-arm64) | regressions reach users on the main platforms; `cargo xtask ci` runs only locally | 6–12 | [target-app-parity](target-app-parity.md#by-dimension) |
| 10 B | **Per-model verification thin, plus cheap per-body decode fixes**: 234 of 1,446 Adobe models verified (16%), ~40% of photographers on a verified body; Nikon 5 bodies verified, Canon 11. Cheap fixes: Z 6II packed 14-bit NEF (#769, PR #671), Sony A100 / F828 regression (#702), DSLR-A200…A390 / A850 12-bit ARW (#535) | measured: [raw/coverage.tsv](raw/coverage.tsv) | per-body bugs (levels, crops, WB) surface only from users | 25–45 | [raw-parity](raw-parity.md#by-maker-measured) |
| 11 | **Enhance: Raw Details, Super Resolution; AI denoise without shippable weights or X-Trans** | ENH rows 0%; denoise Bayer only, RawNIND weights GPL and opt-in | Fujifilm users get no AI denoise; nobody gets it out of the box | 30–60 + model decision | [raw-parity](raw-parity.md#demosaic-levels-crops-and-lens-metadata) |
| 12 | **Content-aware / generative remove, detect distractions, reflections removal** | REM rows 75%; patch synthesis missing | cleanup work goes back to Photoshop | 25–45 (+ generative model) | [target-app-parity](target-app-parity.md#ai) |
| 13 | **Lightroom catalog migration is one-way and approximate**: unsupported Adobe profiles / AI settings archived, history kept as data | lightroom-catalog-import.md | switching users lose some looks | 8–12 | [file-format-parity](file-format-parity.md) |
| 14 | **HDR display** (EDR / Windows HDR); HLG; HDR settings from `crs` XMP | HDR rows 70%; LR-VIEW-HDR-DISPLAY ⬜ | HDR editing works blind on HDR monitors | 12–25 | [hardware-parity](hardware-parity.md) |
| 15 | **Print module**: custom packages, printer colour management (contact-sheet PDF only) | LRC-PRINT rows | Classic users who print | 25–40 | [target-app-parity](target-app-parity.md#features) |
| 16 | **Map view, Book, Slideshow module, publish services** | LRC-MAP / BOOK / SS rows ⬜ | Classic users; publish services matter for Flickr / SmugMug workflows | 60–100 | [target-app-parity](target-app-parity.md#features) |
| 17 | **Tethered capture** | ⬜ | studio photographers | 25–45 + cameras | [hardware-parity](hardware-parity.md) |
| 18 | **Video**: playback, trim, global edits, export | VID rows 0% | users who mix stills and clips | 25–45 | [target-app-parity](target-app-parity.md#features) |
| 19 | **Plug-in ecosystem**: no Lightroom SDK equivalent (export / publish plug-ins, metadata plug-ins) | ⬜ | pro workflows built on plug-ins (LR/Enfuse, Jeffrey's exporters, Negative Lab Pro) | 40–80 + owner decision | [target-app-parity](target-app-parity.md#by-dimension) |
| 20 | **Long-tail raw formats**: compressed SRW, ARQ pixel shift, IIQ, Hasselblad compression, X3F, CRW, MRW, ERF, KDC, DCR, MEF, GPR, old FinePix | raw-parity.md | small user share each | 45–85 | [raw-parity](raw-parity.md) |
| 21 | **Localization**: 9 of 15 shipped languages partial (74–99% of catalog messages), lower-layer errors English; Hindi, Arabic, Indonesian, Korean, Vietnamese absent; no RTL or complex shaping | measured from catalogs | non-English users see mixed English | 55–90 (shipped to full); 145–255 (five new) | [localization-parity](localization-parity.md) |
| 22 | **Pen pressure**, OS monitor profiles, follow-window colour | hardware-parity.md | brush users with tablets; multi-monitor setups | 11–22 | [hardware-parity](hardware-parity.md) |
| 23 | **Accessibility** audit with screen readers; canvas tools keyboard-reachable | LR-BEHAV-ACCESS 🟡 | blind and low-vision users | 10–20 | [ui-parity](ui-parity.md) |
| 24 | **Brush live preview and masking feel** (#517, #518); Feather / Edge mask refinement (15.5) | issues | masking feels slower than Lightroom | 8–12 | [ui-parity](ui-parity.md) |
| 25 | **File writes**: JXL encode, PSD export, lossy DNG, Render to DNG; AVIF import | file-format-parity.md | interchange edge cases | 25–45 | [file-format-parity](file-format-parity.md) |
| 26 | **Performance at scale**: 85k-photo library opens in 1.7–4.7 s; 100k grid test pending; colour NR at half resolution | ROADMAP log, gpu-pipeline.md | large-catalog users | 15–30 | [target-app-parity](target-app-parity.md#by-dimension) |
| 27 | **Windows / Linux runtime coverage**: Windows installer UI unverified on Windows (#79); GPU path proven on Apple only | ROADMAP, issues | non-Mac users find bugs first | 15–30 | [hardware-parity](hardware-parity.md) |
| 28 | **Small Classic shortcuts and keys**: rating `[` `]`, flag cycling, filter-bar keys, F1 help, panel keys (Tab, F5–F8) | [ui-parity](ui-parity.md#shortcuts) | Classic muscle memory | 4–8 | [ui-parity](ui-parity.md) |
Beta-blocking gaps (B) total **~230–430 h**; with the stability and platform work they need around them,
**~340–600 h** to beta (incl. 40–80 h for the ~92 open core-path user issues) (see [target-app-parity.md](target-app-parity.md#stage)).
## Gaps by kind
- **Feature:** 5, 8, 11, 12, 13, 15, 16, 18, 19
- **UI / UX:** 4, 23, 24, 28
- **File format:** 2, 6, 7, 10, 13, 20, 25 (raw ones in [raw-parity.md](raw-parity.md))
- **Hardware:** 14, 17, 22, 27
- **Localization:** 21
- **Quality / fidelity:** 1, 3
- **Stability and platforms:** 9, 26, 27
## Closed recently (kept for calibration)
- 2026-10-10: Nikon lossy-after-split NEF (#633), ORF 12.8 bpp (#651), HDR gain map / PQ AVIF / float
TIFF export (#646), activity stack (#345).
- 2026-10-09: HEIC in release builds (#609), Samsung uncompressed SRW (#459), contact-sheet PDF (#563),
Ukrainian UI (#564), Sony ILCE-7CR profile.
- 2026-10-08: CR3 CRX lossless and C-RAW (#279), Fujifilm compressed RAF (#282), AI RAW denoise (#384),
Lightroom catalog import (#218), German, Spanish, Russian UI.
- 2026-10-07: RW2 every format (#215), faces recognition in pure Rust (#174).
- 2026-10-05: compressed NEF (#86). The older history is in [ROADMAP.md](../ROADMAP.md#progress-log).
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | minor | RAW gaps re-measured model by model (raw-parity.md): CR3, compressed ORF and verification entries carry measured shares; HE NEF no longer a beta blocker (+1.1 points for 20–40 h); verification entry absorbs the cheap per-body fixes (#769, #702, A200 series) |
| 2026-10-10 | minor | Beta total raised to 340–600 h to include the ~92 open core-path user issues |
| 2026-10-10 | major | Created from the checklist's Top gaps (whose items 1–2 had been duplicated by a merge) and ROADMAP's Where we stand; re-ranked; added evidence, impact, hours and beta flags; added platform-CI, lens-database, HE NEF and localization gaps |
+50
View File
@@ -0,0 +1,50 @@
# Hardware parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created from the code, gpu-pipeline.md and the parity checklist) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
What Lightroom does with the machine's hardware, per platform, and what LightCraft does. Sources:
[gpu-pipeline.md](gpu-pipeline.md), [display-profiles.md](display-profiles.md), [denoise.md](denoise.md),
[ai-masks.md](ai-masks.md), `crates/gpu`, `crates/engine/src/devices.rs`, `crates/ui-egui/src/panels/second.rs`.
| Feature | Target | LightCraft: macOS | Windows | Linux / BSD | Web | Status |
|---|---|---|---|---|---|---|
| GPU for display and editing | Metal / DX12, "Use GPU for display / image processing / export" | wgpu Metal: geometry, resize, blur, WB, NR, guided filter, dehaze, masks, finish; CPU fallback per render | DX12 only (Vulkan opt-in, #136) | Vulkan | CPU only (no WebGPU yet) | 🟡 defringe, spot removal, heuristic masks, long brushes and high-bit exports stay on CPU |
| GPU export | ✅ | ✅ (6000 × 4000 in ~0.3 s vs ~1.2 s CPU) | ✅ | ✅ | — | ✅ (black-export fix on an Intel iGPU, #78) |
| AI on GPU / neural engine | Metal / DirectML / Core ML, model per feature | AI denoise on GPU or CPU (setting); SAM 3 on Metal via candle; faces on CPU | CPU / GPU denoise | CPU / GPU denoise | — | 🟡 no Core ML / Neural Engine / DirectML |
| HDR (EDR) display | ✅ (macOS EDR, Windows HDR) | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ (LR-VIEW-HDR-DISPLAY) |
| Monitor profile | automatic per display, follows the window | 🟡 picked by hand | 🟡 | 🟡 | — | 🟡 OS profile not read; no follow across monitors |
| Second window / second monitor | ✅ (Classic) | ✅ (⌘F11) | ✅ | ✅ | — | ✅ (Classic secondary-window keys missing) |
| Pen pressure / tilt (brush masks) | ✅ pressure for size / flow | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
| Trackpad gestures | pinch zoom, pan | ✅ pinch, two-finger pan | 🟡 (winit) | 🟡 | 🟡 | ✅ on macOS |
| Card readers / cameras as import sources | ✅ (devices panel, eject after import) | ✅ mounted volumes with DCIM | ✅ | ✅ | — | 🟡 no eject-after-import check, no MTP / PTP phones |
| Tethered capture | ✅ Classic (Canon, Nikon, Sony, Leica) | ⬜ | ⬜ | ⬜ | — | ⬜ |
| Printers | ✅ Print module, printer colour management | ⬜ (PDF contact sheets only) | ⬜ | ⬜ | — | ⬜ |
| Control surfaces (MIDI / Loupedeck via plug-ins) | via SDK plug-ins | control channel and MCP can drive every command | same | same | — | 🟡 different mechanism; no MIDI mapping |
| Multi-core CPU | ✅ | ✅ worker pools, parallel JPEG decode, parallel import copy | ✅ | ✅ | single thread | ✅ |
| Memory pressure | managed | ✅ memory budget, `crates/sysmem` returns allocator pages on macOS | ✅ budget | ✅ budget | — | ✅ |
## Score
**~40% ready** (estimated): the GPU editing path is real and fast (measured: 24 MP exposure drag
3.9 ms on GPU vs 22–42 ms CPU; NR drag 18 ms vs 301–471 ms), but HDR display, pen pressure,
tethering, printing, automatic monitor profiles and neural-engine inference are missing. GPU
correctness is proven on Apple GPUs; other vendors rely on user reports.
## Remaining (Opus 5.5 agent hours)
| Work | Hours | Needs |
|---|---:|---|
| HDR display (EDR on macOS, Windows HDR, Linux where possible) | 10–20 | an HDR display to verify (human) |
| OS monitor profile, follow window across displays | 5–10 | multi-monitor setup |
| Pen pressure for brush masks (winit tablet events or a pure-Rust tablet layer) | 6–12 | a tablet |
| Remaining stages on GPU (defringe, spot removal, masks) | 10–20 | |
| Tethered capture (PTP over USB in pure Rust, Canon / Nikon / Sony first) | 25–45 | cameras (human) |
| Printing with colour management | 15–25 | printers (human) |
| Neural-engine / DirectML inference for AI features | 10–20 | depends on the AI model decision |
| **Total** | **80–150 h** (the core set for beta, HDR display + monitor profile + pen pressure: 20–40 h) | |
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created |
+92
View File
@@ -0,0 +1,92 @@
# Localization parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (first per-language measurement from the catalogs) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
How far each interface language is from `full`. How to add or maintain a language is in
[localization.md](localization.md); per-language notes are in `localization-<code>.md`
([zh-hans](localization-zh-hans.md), [zh-hant](localization-zh-hant.md), [ja](localization-ja.md),
[pt-br](localization-pt-br.md), [es](localization-es.md), [de](localization-de.md),
[ru](localization-ru.md)).
## The target
Lightroom 9.6 (installed on the owner's Mac) ships 16 interface languages, listed from its bundle's
`.lproj` folder names: English, German, Spanish, French, Italian, Japanese, Korean, Norwegian Bokmål,
Dutch, Polish, Portuguese (Brazil), Russian, Swedish, Thai, Simplified Chinese and Traditional
Chinese. It does **not** ship Hindi, Arabic, Indonesian or Vietnamese, so for those LightCraft would
go beyond the target.
## How the numbers are measured
**Measured** (a Python count over `crates/ui-egui/locales/*.json`, 2026-10-10):
- The denominator is every message any catalog knows: the union of the plain catalogs' keys (2,074
English source strings: menus, commands, controls, panels, dialogs, tooltips, presets, What's New
lines) plus the 230 messages of the formats catalogs (`*-formats.json`: text with runtime values and
date patterns), 2,304 messages in all.
- A message counts as translated when the catalog has a non-empty value that differs from the English
key. Some identical values are correct (`ISO`, `OK` in German), so the figure slightly understates
coverage; on the other hand, strings that never reach a catalog (technical errors raised in lower
crates, some `format!` text outside `tr_format!`) are not in the denominator at all. That is why no
language is `full` even at 99%.
- The UI has 563 distinct `tr("…")` literals and 198 `tr_format!` messages in `crates/ui-egui` and
`apps/`; command, control, menu and preset labels reach the catalogs through `display_label`.
Script support is checked against the code: `language_table!` in `crates/ui-egui/src/i18n.rs` lists
scripts `Latn`, `Cyrl`, `Hans`, `Hant`, `Jpan` only. The UI is egui, which has no bidirectional layout
and no complex-script shaping, so Arabic (RTL, joining) and Devanagari (conjuncts, reordering) cannot
render correctly today.
Native-speaker review: no catalog has had a formal review. Several catalogs have edits from community
contributors whose commits only touch that language (ja, zh-hans, zh-hant, fr, de, ru, uk, pt-br);
that is promising but is not recorded as review, so the column says `no (community edits)`.
## The twelve key languages
| # | Language | Code | UI strings translated | Dialogs / tooltips / help | Script support | Native review | Status | To `full` |
|---|---|---|---:|---|---|---|---|---:|
| 1 | English | `en` | 2,304 / 2,304 (100%, source) | all; Help ▸ What's New and the shortcut sheet; no full user manual | Latin (Inter) | n/a | **full** | 0 h |
| 2 | Simplified Chinese | `zh-hans` | 1,994 / 2,304 (87%) | menus, panels, dialogs, presets, profiles, dates; lower-layer errors English | Hans via craft-fonts (Noto Sans CJK SC); IME through winit; no vertical text in UI (not in target either) | no (community edits) | partial | 6–10 h |
| 3 | Spanish | `es` | 1,972 / 2,304 (86%) | as zh-hans | Latin | no (community edits) | partial | 6–10 h |
| 4 | Hindi | `hi` | 0 (0%) | none | **Devanagari shaping missing** (egui has no complex shaping) | no | none (target: not shipped) | 50–90 h (shaping 25–50 h, shared with Arabic) |
| 5 | Arabic | `ar` | 0 (0%) | none | **RTL layout and Arabic shaping missing** | no | none (target: not shipped) | 60–110 h (RTL mirroring 30–50 h + shaping, shared with Hindi) |
| 6 | French | `fr` | 2,021 / 2,304 (88%) | as zh-hans | Latin | no (community edits) | partial | 5–9 h |
| 7 | Portuguese (Brazil) | `pt-br` | 1,966 / 2,304 (85%) | as zh-hans | Latin | no (community edits) | partial | 6–10 h |
| 8 | Indonesian | `id` | 0 (0%) | none | Latin (Inter covers it) | no | none (target: not shipped) | 10–16 h |
| 9 | Japanese | `ja` | 1,995 / 2,304 (87%) | as zh-hans; vertical export watermarks | Jpan via craft-fonts (BIZ UDPGothic / UDMincho); IME through winit | no (community edits) | partial | 6–10 h |
| 10 | German | `de` | 2,104 / 2,304 (91%) | as zh-hans; What's New translated line by line | Latin | no (community edits) | partial | 4–8 h |
| 11 | Korean | `ko` | 0 (0%) | none | **no Korean (Hangul) face**: needs a non-Adobe OFL face in craft-fonts (Noto CJK is allowed only for Chinese) | no | none | 14–22 h |
| 12 | Vietnamese | `vi` | 0 (0%) | none | Latin with stacked diacritics (Inter covers it; check combining marks) | no | none (target: not shipped) | 10–16 h |
## Other languages LightCraft ships (3)
| Language | Code | UI strings translated | Script | Native review | Status | To `full` |
|---|---|---:|---|---|---|---:|
| Traditional Chinese (Taiwan) | `zh-hant` | 1,993 / 2,304 (87%) | Hant; uses the Simplified Chinese face until craft-fonts has a TC face | no (community edits) | partial | 8–14 h (incl. the font) |
| Russian | `ru` | 1,704 / 2,304 (74%) | Cyrillic (Inter) | no (community edits) | partial | 8–12 h |
| Ukrainian | `uk` | 2,287 / 2,304 (99%) | Cyrillic (Inter) | no (community edits) | partial (lower-layer errors English) | 2–4 h |
Target languages LightCraft lacks: Italian, Korean, Dutch, Polish, Swedish, Norwegian Bokmål, Thai
(Thai needs shaping and line breaking without spaces). Each Latin-script one is ~10–16 h; Thai
~20–35 h on top of the shaping work.
## Shared work before any language is `full` (counted once, ~20–35 h)
- Route lower-layer error messages (catalog, raw, codecs, engine) through translatable message ids
instead of English `format!` strings (~12–20 h).
- A check in `cargo xtask ci` that every user-visible literal reaches a catalog (~4–8 h).
- A user manual / help pages beyond What's New and the shortcut sheet (Lightroom links to online
help; ~4–8 h for a translatable in-app help index).
- Native-speaker review passes (human; cannot be done by agents).
## Totals
- Bring the 9 shipped non-English catalogs to `full`: ~55–90 h (incl. the shared work).
- Add the 5 missing key languages: ~145–255 h, most of it RTL and complex shaping in egui.
- Reach the target's 16 languages: + ~60–100 h (Italian, Dutch, Polish, Swedish, Norwegian, Thai).
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created: per-language counts measured from the catalogs, the twelve key languages, script support, estimates |
+26 -85
View File
@@ -1,7 +1,15 @@
# Lightroom parity tracker
# Lightroom parity checklist
A living checklist of every Lightroom feature LightCraft aims to match, what we have, and what is missing. Agents and
humans pick work from **[Top gaps](#top-gaps)**; whoever lands a feature updates its row in the same commit.
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
The measured, row-by-row checklist: one row per Lightroom feature, menu item and shortcut, what we
have and what is missing. It answers *does the feature exist?* (feature breadth). Whether it is good
enough to replace Lightroom is assessed in [target-app-parity.md](target-app-parity.md), and the work
list is [gaps.md](gaps.md). Whoever lands a feature updates its row in the same commit.
The rows are maintained by hand; the summary block is generated (`cargo xtask parity --write`), and
`cargo xtask parity` (part of `cargo xtask ci`) checks that every command id, control id and path
cited here still exists. Formerly docs/parity.md.
- **Ids** come from the (local, gitignored) reference in `plan/lightroom/`: `LR-…` = feature catalog (03),
`MENU-…` = menu items (04), `KEY-…` / `KEYC-…` = keyboard shortcuts (06, desktop / Classic), `LRC-…` = Classic
@@ -13,9 +21,6 @@ humans pick work from **[Top gaps](#top-gaps)**; whoever lands a feature updates
id (`lightcraft-cli controls`), plus source files. A trailing `*` matches a prefix (`ctl:mixer.*`).
- Feature names and notes are our own words. No Adobe text, screenshots or assets belong here.
`cargo xtask parity` checks that every `cmd:`/`ctl:` id and file path below still exists (part of `cargo xtask ci`)
and prints the summary; `cargo xtask parity --write` refreshes the summary table below.
## Summary
<!-- parity:summary -->
@@ -42,92 +47,21 @@ and prints the summary; `cargo xtask parity --write` refreshes the summary table
| S. Export (EXP) | 15 | 2 | 1 | 0 | 7/7 (100%) | 7/7 (100%) |
| T. Share (SHARE) | 0 | 0 | 0 | 4 | — | — |
| U. Map & location (MAP) | 0 | 1 | 1 | 0 | — | 0/1 (0%) |
| V. Preferences (PREF) | 7 | 1 | 2 | 2 | 1/1 (100%) | 5/5 (100%) |
| V. Preferences (PREF) | 6 | 2 | 2 | 2 | 1/1 (100%) | 4/5 (80%) |
| W. Cloud & AI infrastructure (CLOUD / AI) | 1 | 0 | 1 | 2 | — | — |
| X. Cross-cutting behaviours (BEHAV) | 18 | 6 | 1 | 1 | 8/8 (100%) | 6/9 (67%) |
| Y. Menus | 82 | 0 | 4 | 8 | 47/47 (100%) | 23/23 (100%) |
| Z. Keyboard shortcuts (desktop) | 75 | 3 | 3 | 1 | 49/52 (94%) | 23/24 (96%) |
| Lightroom Classic extras | 32 | 11 | 39 | 9 | — | 22/24 (92%) |
| **Total** | 393 | 39 | 84 | 36 | 192/200 (96%) | 142/152 (93%) |
| Lightroom Classic extras | 33 | 15 | 35 | 9 | — | 23/25 (92%) |
| **Total** | 397 | 49 | 73 | 36 | 192/200 (96%) | 143/155 (92%) |
Weighted completion (✅ = 1, 🟡 = ½, 🚫 left out): **79.9%** of 516 in-scope rows — P0 98.0% of 200 · P1 95.7% of 152 · P2 42.9% of 163.
Weighted completion (✅ = 1, 🟡 = ½, 🚫 left out): **81.2%** of 519 in-scope rows — P0 98.0% of 200 · P1 95.2% of 155 · P2 47.2% of 163.
<!-- /parity:summary -->
## Top gaps
## Top gaps and shortcut notes
Ordered by user impact, then tier, then effort. The checklist above counts features that *exist*; these are the gaps
that decide whether a photographer can switch (see the honest assessment in [ROADMAP.md](../ROADMAP.md#where-we-stand)).
Take the first one nobody is working on.
1. **LR-PROF-CAMERACOLOR** (P0): our own camera colour calibration. Sony ARW, Nikon NEF and Panasonic RW2 now get a guarded file-local fit to their own embedded JPEG (colour matrix + hue/saturation/value table + tone and chroma curves, relative WB; per-model profiles pooled from many photos via `lightcraft-cli calibrate` for ARW and NEF; ARW: 7 of 10 public samples accepted, mean ΔE vs the camera JPEG 17–26 → 3–10; NEF: 13 of 13 decodable samples from 6 bodies accepted, ΔE 13–46 → 3–8, one mixed-light scene 13 → 12; RW2: 140 of 174 public samples accepted, from 93 of the 114 bodies with a preview, median ΔE 5.0); Nikon CropArea and untagged-preview ColorSpace metadata are respected; measured calibration and fidelity remain missing. Other non-DNG raws and rejected fits still use a neutral matrix. Expand validated preview fitting and use matrices the files carry themselves; never Adobe data.
2. **LR-IMP-FORMATS** (P0): **CR3** first (every Canon body since ~2018), then compressed RAF / ORF, Nikon
1. **LR-PROF-CAMERACOLOR** (P0): our own camera colour calibration. Sony ARW, Nikon NEF, Panasonic RW2 and Fujifilm RAF now get a guarded file-local fit to their own embedded JPEG (colour matrix + hue/saturation/value table + tone and chroma curves, relative WB; per-model profiles pooled from many photos via `lightcraft-cli calibrate` for ARW, NEF and RAF; ARW: 7 of 10 public samples accepted, mean ΔE vs the camera JPEG 17–26 → 3–10; NEF: 13 of 13 decodable samples from 6 bodies accepted, ΔE 13–46 → 3–8, one mixed-light scene 13 → 12; RW2: 140 of 174 public samples accepted, from 93 of the 114 bodies with a preview, median ΔE 5.0; RAF: 23 of 24 references accepted with bundled X-H2S/X-T4 profiles; 150 withheld-file tests improve mean ΔE slightly over per-file fitting); measured calibration and fidelity remain missing. Other non-DNG raws and rejected fits still use a neutral matrix. Expand validated preview fitting and use matrices the files carry themselves; never Adobe data.
2. **LR-IMP-FORMATS** (P0): **CR3** first (every Canon body since ~2018), then compressed ORF, Nikon
1. **LR-PROF-CAMERACOLOR** (P0): our own camera colour calibration. Sony ARW, Nikon NEF and Panasonic RW2 now get a guarded file-local fit to their own embedded JPEG (colour matrix + hue/saturation/value table + tone and chroma curves, relative WB; per-model profiles pooled from many photos via `lightcraft-cli calibrate` for ARW and NEF; ARW: 7 of 10 public samples accepted, mean ΔE vs the camera JPEG 17–26 → 3–10; NEF: 13 of 13 decodable samples from 6 bodies accepted, ΔE 13–46 → 3–8, one mixed-light scene 13 → 12; RW2: 140 of 174 public samples accepted, from 93 of the 114 bodies with a preview, median ΔE 5.0); measured calibration and fidelity remain missing. Other non-DNG raws and rejected fits still use a neutral matrix. Expand validated preview fitting and use matrices the files carry themselves; never Adobe data.
2. **LR-IMP-FORMATS** (P0): CR3 lossless Bayer and version 0x100/0x200 C-RAW now decodes (M50/R100/R8 full sensor exact). Remaining unverified CRX variants, compressed RAF / ORF, Nikon
Canon sRAW; AVIF decode (HEIC decodes behind the codecs' non-default `heif` feature:
the optional `lightcraft-heif` crate on heic-rs, the same decoder and policy as PhotoCraft). Clean-room, from prose descriptions only (see
`crates/raw/src/vendor/nefc.rs` for how compressed NEF was done). Until decoded, such photos are `preview_only`.
3. **LR-IMP-CAMERA-COVERAGE** (P0): per-model verification; grow the CC0 corpus and fix per-model bugs (like the CR2
colour-filter layout, fixed in #85 by reading the file's own tag).
4. **LR-BEHAV-RENDER-FIDELITY** (P1): a side-by-side fidelity suite against Lightroom renders (kept local in `plan/`),
then tune tone, highlights, texture/clarity/dehaze, NR and sharpening against it. A retune that changes how existing
settings render ships as a new process version, so existing edits keep their look (`docs/process-versions.md`).
4b. **LR-VIEW-ZOOM** (P0): finish the sharp zoomed views of issue #323: windows for compare, overlays and soft proofing
(Before/After has them); check sharpness and the wide-stage margin on real raw photos (only synthetic scenes so far).
5. **LR-EDIT-OPTICS-PROFILE** (P1): a lens-profile database of our own (corrections embedded in DNG files and the
distortion correction Panasonic / Leica cameras record in RW2 / RWL files work today; issue #256). Sony ILCE-7RM4A Bayer
ARW 16-sample tables in native 3:2 framing now feed the same distortion path; broader coverage and Sony
vignetting / lateral CA remain (see `docs/sony-lens-corrections.md`).
6. **AI masks and Enhance** (LR-MASK-SUBJECT / SKY / PEOPLE / OBJECTS, LR-EDIT-DETAIL-DENOISE, SUPERRES, LENSBLUR):
Object and Describe masks run SAM 3 in pure Rust (`crates/segment`); the weights (SAM License) are never bundled:
the app offers a consented, verified download, but **LightCraft's CDN mirrors are not configured yet** (the
built-in list is empty, so today users need their own mirror or a manual install). Subject / Sky / People could
use the same model with fixed prompts; denoise / super-resolution models remain a maintainer decision.
7. **HDR** (Q. HDR, LR-EXP-HDR), **video** (R. Video), **Classic output modules** (Map view, Book, Slideshow module,
Print, publish): large, well understood, lower priority than 1–5. Contact-sheet PDF export now covers a
basic Print workflow; custom picture packages, printer integration and print colour management remain open.
8. **LR-VIEW-ZOOM** (P0): pinch zoom and two-finger pan now work, with stable image cursors between gesture events.
The whole-image preview is still capped by
Settings → Performance → Preview size (2,560 px by default). Render visible regions at native resolution so
100% can reliably show original-pixel detail on larger photos.
Recognition runtime gap closed (LR-PREF-PEOPLE): the pinned SFace and AuraFace models now run on the shared pure-Rust
CPU engine and agree with an independent reference runtime on public crops. Live-face threshold calibration, small-face
coverage and separated clusters remain open; see [faces.md](faces.md).
## Shortcuts: conflicts and missing bindings
Compared `plan/lightroom/06-shortcuts.md` (desktop part) with our bindings: command specs in `crates/engine/src/cmd/`,
`UI_COMMANDS` in `crates/ui-egui/src/menus.rs` and secondary bindings (`ALIASES`) in `crates/ui-egui/src/shortcuts.rs`.
`no_conflicting_bindings` (same file) fails when one key fires two actions.
**Fixed (M16.1):** added Lightroom-desktop keys as secondary bindings for existing commands — ⌘D Select None, ⇧E
Export dialog, Space Toggle zoom, ⇧M Create Version, ⇧X Reject + advance, ⇧U Unflag + advance. `⇧Y` fired both
Before/After Split and the History panel; History lost the binding. `W` and `⇧⌘I` also fired the engine command
under the UI command that wraps it (a no-op error); the UI command now wins.
**Deliberate differences (our key → Lightroom desktop key)** — each is a conflict with another binding we have:
| Action | Ours | Lightroom desktop | Why |
|---|---|---|---|
| Pick flag | P | Z | Z = toggle zoom (Classic convention); P is the Classic pick key |
| Photos panel (left) | ⌘⇧L | P | P = pick |
| Expand/collapse edit sections | ⌘⌥1–5 | ⌘1–6 | ⌘0 = Zoom to Fit, ⌘1 = Zoom 100 %; Geometry lives in the Crop panel |
| Histogram | ⌘⇧H | ⌘0 | ⌘0 = Zoom to Fit |
| Square Grid | ⇧G | (none; ⇧G = Guided Upright) | Guided Upright is a button in the Crop panel |
| Export dialog | ⌘⇧E (+ ⇧E) | ⇧E | ⌘⇧E is "Edit in Photoshop" there; no external-editor command yet |
| Crop overlay cycle | ⇧O | O | O = mask overlay; ⇧O (mask colour / overlay orientation) unused otherwise |
| Create Version | ⌘⇧S (+ ⇧M) | ⇧M (Windows: Ctrl+⇧S) | — |
| Select None | ⌘⇧A (+ ⌘D) | ⌘D | — |
**Library culling (KEYC-RATING):** `0–5`, `6–9` and `P/X/U` reach egui on macOS even when displayed in the native menu (adapted from PR #261; issue #283). `Shift+0–9` applies and advances once; `Shift+P` picks and advances in Photo Grid / Square Grid and retains Presets elsewhere. See [library shortcuts](library-shortcuts.md) for the verified Classic mapping and regression coverage. Remaining Classic gaps: rating `[` / `]`, flag cycling and filter-bar keys.
**Still missing / broken:**
- No command yet: F1 help (verify the rest of the old list: full screen, settings, stacks,
visualize spots and merges have commands now).
- `H` opens Remove; Lightroom also uses it (Classic) to hide pins — pins toggle from View → Show Mask Pins.
- ⌘M / ⌘H / ⌘Q / ⌘W rely on the platform window defaults (unverified).
Moved on 2026-10-10: the ranked gaps are in [gaps.md](gaps.md); shortcut conflicts, deliberate
differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts).
<!-- Sections below hold one row per id. Keep the column order: Id | Feature | Tier | Status | Evidence | Notes. -->
@@ -644,7 +578,7 @@ visible menu bar yet: the menu model is only exposed through the control channel
## Z. Keyboard shortcuts (desktop)
From `06-shortcuts.md` part 1. Evidence is our binding; conflicts are explained in
[Shortcuts: conflicts and missing bindings](#shortcuts-conflicts-and-missing-bindings).
[UI parity → Shortcuts](ui-parity.md#shortcuts).
| Id | Feature | Tier | Status | Evidence | Missing / notes |
|---|---|---|---|---|---|
@@ -837,3 +771,10 @@ dialog offers Horizontal/Vertical and multiline text. Japanese glyphs fall back
Mincho faces (BIZ UDMincho; on the web build, BIZ UDPGothic) when built with `CRAFT_FONTS_DIR`. Vertical lettering uses upright em cells and right-to-left newline columns;
Latin stays upright. Advanced Japanese composition remains open. Regression coverage:
`export::tests::japanese_watermarks_support_vertical_columns`, `japanese_watermark_options_and_legacy_defaults`, `watermarks_work_without_craft_fonts`.
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | minor | Renamed from `parity.md` (progress-docs standard); Top gaps moved to gaps.md (its duplicated items 1–2 from a bad merge resolved there), shortcut notes moved to ui-parity.md. Rows unchanged; a recount of the rows gives 81.1% of 517 in-scope rows (P0 98.0%, P1 95.1%, P2 46.9%), so the generated summary above is due a `cargo xtask parity --write` |
| 2026-09-30 – 2026-10-10 | — | Rows added and updated with each feature (see `git log -- docs/parity.md docs/parity-checklist.md`) |
+1 -1
View File
@@ -32,7 +32,7 @@ Today there is one process, **V1**: LightCraft's rendering from before process v
passing: settings saved without the field must stay V1, not become the new latest. That is the
field's `#[serde(default = "ProcessVersion::legacy")]`; the struct-level `Default` gives new
settings the latest instead.
4. Render a few procedural scenes on both processes and compare, and update `docs/parity.md`.
4. Render a few procedural scenes on both processes and compare, and update `docs/parity-checklist.md`.
## What gets which process
+253
View File
@@ -0,0 +1,253 @@
# RAW parity: cameras, formats, demosaic, colour and lens profiles
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (model-by-model measurement against Adobe's published camera list; use-weighted coverage; variant matrix; colour and lens sections; ranked next cameras) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 (Camera Raw 18.7)
Raw processing is the deepest single dimension of Lightroom parity: a photographer whose camera
does not decode, or decodes with the wrong colour, cannot switch. This document measures it model by
model. The numbers feed [target-app-parity.md](target-app-parity.md); individual shortfalls are
ranked in [gaps.md](gaps.md). Details per format: [cr3.md](cr3.md),
[raf-compression.md](raf-compression.md), [sony-lens-corrections.md](sony-lens-corrections.md),
[camera-preview-colour.md](camera-preview-colour.md), [denoise.md](denoise.md).
## Headline
| Measure | Value | Kind |
|---|---:|---|
| Adobe-listed camera models | **1,446** | measured: [raw/adobe-cameras.tsv](raw/adobe-cameras.tsv) |
| Decoded from sensor data and **verified** on a real file | **234** (16%) | measured: [raw/evidence.tsv](raw/evidence.tsv) |
| Decoder path should handle it, **unverified** | **943** (65%) | measured from the format rules (632 of them DNG, mostly phones) |
| **Preview-only** (embedded JPEG) | **233** (16%) | measured |
| **Unsupported** (not imported, refused or decodes wrongly) | **36** (2%) | measured |
| Models added since 2017 (Camera Raw 10+): verified / unverified / preview / unsupported | 81 / 641 / 24 / 8 of 754 | measured |
| **Share of photographers whose camera fully works** (decodes from sensor data), use-weighted | **~84%** | estimated: measured classes × written usage weights × per-format confidence |
| …of which on a body we have verified | **~40%** | estimated, same weights |
| Camera colour: Adobe profiles vs ours | 1,500 Adobe Standard profiles, 481 models with Camera Matching profiles vs **4 bundled profiles** + per-file fits + 52 spectral matrices | measured (bundle listing, Adobe list, `assets/camera-profiles`) |
| Lens profiles: Adobe vs ours | **3,635 vs 0** (in-file corrections only) | measured |
| **RAW readiness** (decoding 60%, colour 25%, lens 15%) | **~56%** (range 50–60%) | estimated, see [Scores](#scores) |
Re-measure with `python3 docs/raw/coverage.py` (standard library only): it classifies every Adobe
model from the format rules in the script (which mirror `crates/raw/src`) plus the per-model evidence,
rewrites [raw/coverage.tsv](raw/coverage.tsv) and prints the tables below; `--check` fails when the
committed table is stale.
## How it was measured
- **Adobe's list**: helpx "Camera Raw supported cameras" (the live page refuses scripted requests, so
the Wayback Machine capture of 2026-10-03 was parsed): 1,446 camera rows from 40 makers after
dropping profile-only rows; maker, model, extension(s), Camera Matching profile, minimum Camera Raw
version. The year a model was added is approximated from that Camera Raw major version.
- **What we decode**: the decoders and their refusals in `crates/raw/src` (`lib.rs` routing, `vendor/*.rs`
coding variants, `crx.rs` CRX limits, `orf.rs` / `srw.rs` compressed refusals), the import list
`lightcraft_engine::import::EXTENSIONS`, and `KNOWN_UNSUPPORTED` in `crates/raw/tests/corpus.rs`. Doc
claims were not used.
- **Verified** means a real file from that body decoded from sensor data in: the corpus test over the
`RAW_SAMPLES` manifest (`xtask/src/main.rs`, 101 CC0 files; bodies whose sample is in
`KNOWN_UNSUPPORTED` excluded), `crates/raw/tests/cr3_corpus.rs` (3 bodies, exact), the RAF reference
check ([raf-compression.md](raf-compression.md)), and the raw.pixls.us bulk checks recorded in issue
#535 (all 100 Sony bodies there; 87 decode) and PR #215 (every Panasonic / Leica RW2 / RWL / RAW body
there, 178 files from 118 bodies). Bulk-check body lists were matched to Adobe names through the
raw.pixls.us folder names. Checks without a body list (≈ 60 NEFs, 35 CR2 bodies for the CFA layout)
are not counted as verified.
- **Usage weights** ([raw/usage-weights.tsv](raw/usage-weights.tsv)): maker buckets from 2025 market
data (Nikkei production: Canon ~36%, Sony ~29%, Nikon ~14%, Fujifilm ~12% of mirrorless; BCN retail:
Sony 29.9%, Canon 27.4%, Nikon 15.1%), adjusted for the DSLR installed base and for the makers named
in this repo's 325 user issues (Sony 33, Nikon 31, Canon 26, phones 23, Fujifilm 9, Panasonic / Leica
8, OM / Olympus 6, Pentax / Ricoh 6). Inside each bucket, 80% goes to the popular bodies of the last
~8 years (listed in the file), 20% to the bucket's other Adobe models.
- **Per-format confidence** for unverified bodies (the chance their files decode correctly): DNG, CR2,
RAF, RW2 0.95; NEF, ARW, PEF 0.9; ORF, SRW, SR2 0.8; **CR3 0.6** (the CRX decoder refuses several
coding variants and only three bodies are verified; maintainers report the R7 working).
## By maker (measured)
| Maker | Adobe models | verified | unverified | preview | unsupported | Main reason for preview / unsupported |
|---|---:|---:|---:|---:|---:|---|
| Sony | 149 | 86 | 51 | 9 | 3 | DSLR-A200…A390 and A850 12-bit compressed ARW (preview, #535); A100 and DSC-F828 refused (regression #702); SRF not imported |
| Canon | 134 | 11 | 100 | 21 | 2 | CRW (2000–2004 bodies) preview; EOS-1D / 1Ds TIFF raws not imported |
| Samsung | 128 | 1 | 118 | 9 | 0 | compressed SRW (NX1, NX30, NX300, NX500, NX2000, NX3000, NX3300, NX mini, Galaxy NX) |
| Apple | 113 | 1 | 112 | 0 | 0 | — (DNG / ProRAW) |
| Panasonic | 104 | 93 | 11 | 0 | 0 | — |
| Nikon | 99 | 5 | 94 | 0 | 0 | — (HE / HE★ is a per-shot setting, preview-only) |
| Fujifilm | 97 | 16 | 55 | 26 | 0 | pre-X FinePix RAF without a raw IFD (estimated split) |
| Google | 88 | 1 | 87 | 0 | 0 | — |
| Olympus | 71 | 3 | 9 | 59 | 0 | **compressed ORF** |
| Leica | 61 | 13 | 48 | 0 | 0 | — |
| Xiaomi, Oppo, LG, Huawei, OnePlus, Motorola, Nokia | 139 | 0 | 139 | 0 | 0 | — (DNG) |
| Pentax / Ricoh | 60 | 4 | 56 | 0 | 0 | — |
| Hasselblad | 34 | 0 | 2 | 32 | 0 | Hasselblad-compressed 3FR / FFF |
| Phase One / Leaf / Mamiya | 59 | 0 | 0 | 43 | 16 | IIQ, MOS preview; TIFF raws and MEF not imported |
| Casio | 26 | 0 | 26 | 0 | 0 | — (DNG) |
| DJI | 21 | 0 | 21 | 0 | 0 | — (DNG) |
| OM Digital Solutions | 7 | 0 | 0 | 7 | 0 | **compressed ORF** |
| Kodak, Konica Minolta, Epson, Sigma, GoPro, Contax, others | 56 | 0 | 14 | 27 | 15 | DCR, GPR not imported; KDC, MRW, ERF, X3F preview |
| **All** | **1,446** | **234 (16%)** | **943 (65%)** | **233 (16%)** | **36 (2%)** | |
## By use (estimated)
| Bucket | Weight | Camera fully works | On a verified body | Why |
|---|---:|---:|---:|---|
| Canon | 33% | 72% | 16% | 17 of the 22 popular bodies write CR3; 2 of them verified, the rest at 0.6 |
| Sony | 27% | 98% | 91% | bulk-checked |
| Nikon | 16% | 91% | 12% | decoders cover every NEF coding but HE; few bodies verified |
| Fujifilm | 10% | 91% | 45% | |
| Panasonic | 4% | 100% | 98% | bulk-checked |
| OM / Olympus | 3% | 3% | 1% | compressed ORF |
| Phones | 3% | 93% | 1% | DNG |
| Pentax / Ricoh | 1.5% | 94% | 14% | |
| Leica | 1% | 95% | 5% | |
| DJI | 1% | 95% | 0% | |
| Medium format and others | 0.5% | 23% | 0% | IIQ, 3FR, X3F |
| **Weighted** | 100% | **84%** | **40%** | |
About 5 in 6 raw photographers' cameras decode, but only about 2 in 5 use a body we have actually
checked, and Canon, the largest bucket, is the weakest of the big four.
## Variant matrix (depth per format)
✅ decoded and checked on real files · 🟡 decoded, partial or unverified · ⬜ preview-only or refused.
| Format | Variant | Status | Evidence |
|---|---|---|---|
| CR2 | lossless JPEG slices | ✅ | 8 corpus bodies; CFA phase from `CR2CFAPattern` (#85, 35 bodies); masked-column black level |
| CR2 | sRAW / mRAW (YCbCr) | ✅ | `vendor/cr2/sraw.rs`, 31 samples from 16 models |
| CR3 | CRX lossless, version 0x100 | ✅ | M50, R100, R8 exact against a reference |
| CR3 | C-RAW 0x100 (horizontal tiles), 0x200 (single 14-bit tile, adaptive QP) | ✅ | same 3 bodies exact |
| CR3 | other CRX variants (vertical tiles, partial subbands, other plane flags, 0x200 multi-tile) | ⬜ | refused in `crx.rs`, falls back to the preview; which bodies write them is unmeasured |
| CR3 | sRAW / mRAW | ⬜ | 4-plane Bayer only |
| CR3 | HEIF / HDR PQ | ⬜ | HEVC tracks recognised, not decoded |
| CR3 | dual-pixel raw | ⬜ | never substituted |
| CRW | all | ⬜ | preview |
| NEF | uncompressed, lossless, lossy type 1 / 2, lossy after split | ✅ | D5100, D7000, D7500, Z f corpus; ~60 NEFs by hand; #633 |
| NEF | packed 14-bit stored under a compressed tag (Z 6II uncompressed) | ⬜ | #769; fix in PR #671 (not merged) |
| NEF | High Efficiency / HE★ (JPEG XS) | ⬜ | named, preview (#193); needs a JPEG XS decoder |
| ARW | uncompressed, cRAW (ARW2), lossless LJ92 (L / M / S) | ✅ | 86 bodies (#535); M/S black level 1024 |
| ARW | packed 12-bit (A900) | ✅ | one CC0 file; A850 unmeasured |
| ARW | 12-bit compressed of DSLR-A200…A390 | ⬜ | preview (#535) |
| ARW | A100 ARW; SRF (F828, V3) | ⬜ | refused (#702); SRF not imported |
| ARW | ARQ pixel shift | ⬜ | no code |
| SR2 | DSC-R1 | ✅ | CC0 3221 sample |
| RAF | uncompressed, lossless and lossy compressed; Bayer and X-Trans; GFX 14/16-bit | ✅ | 24 files from 13 bodies exact |
| RAF | pre-X FinePix without a raw IFD | ⬜ | `raf.rs` refuses (26 Adobe models, estimated split) |
| ORF | uncompressed 16-bit, 12-bit packed, two-field 12-bit, 12.8 bpp | ✅ | E-1, E-400, XZ-2 corpus; #651 |
| ORF | **compressed** (every Olympus / OM body since ~2008) | ⬜ | `orf.rs` refuses; the E-M1 and E-M10 III corpus files are `KNOWN_UNSUPPORTED` |
| RW2 / RWL / RAW | formats 2, 4, 5, 6, 7, 8 and 16-bit words | ✅ | 118 bodies (#215) |
| PEF | uncompressed, Huffman, packed 12-bit | ✅ | K10D, K-3, K-5 IIs |
| PEF / DNG | Pentax pixel shift | ⬜ | frames not combined |
| SRW | uncompressed, 12-bit packed | ✅ | EX1 corpus; NX10, NX20 |
| SRW | compressed 32770 / 32772 / 32773 | ⬜ | refused |
| DNG | uncompressed, LJ92, lossy JPEG / Smart Preview, Deflate incl. float, LinearRaw, tiles / strips, row / column interleave | ✅ | 6 corpus DNGs; 4 ILCE-6400 JXL DNGs |
| DNG | JPEG XL (DNG 1.7, lossless and lossy) | ✅ | synthetic bit-exact; real lossless and lossy files |
| DNG | Apple ProRAW (incl. semantic mattes) | ✅ | iPhone 12 Pro corpus; ProfileGainTableMap read but off (ΔE00 19 against Lightroom with it on) |
| DNG | phone DNGs (Pixel, Galaxy, Xiaomi…) | 🟡 | Pixel 2 XL only; white-level pile-up fix #548 |
| DNG | GoPro GPR (VC-5) | ⬜ | refused |
| 3FR / FFF | DNG-like layouts | 🟡 | decoded when uncompressed or LJ92 |
| 3FR / FFF | Hasselblad compression | ⬜ | preview |
| IIQ, MOS, MRW, ERF, KDC, X3F | all | ⬜ | preview |
| DCR, MEF, MFW, DXO, GPR, TIFF raws | all | ⬜ | not imported |
## Demosaic, levels, crops and lens metadata
| Stage | Target | LightCraft | Status |
|---|---|---|---|
| Bayer demosaic | Adobe's own, plus AI "Raw Details" | AHD (default), PPG, bilinear (`crates/raw/src/demosaic`) | 🟡 quality unmeasured against Lightroom; no Raw Details |
| X-Trans demosaic | ✅ | in-house edge-weighted directional | 🟡 unmeasured |
| Foveon | ✅ (older bodies) | — | ⬜ |
| Monochrome / LinearRaw | ✅ | handled, no demosaic | ✅ |
| Pixel shift (Sony ARQ, Pentax, OM high-res, Nikon) | ✅ (Sony, Pentax, Nikon) | — | ⬜ |
| Black and white levels | per model, calibrated | read from each file (masked columns, maker notes, SR2SubIFD, CMP1) | 🟡 per-body bugs keep surfacing: A450–A700 SR2 black level and M/S ARW pedestal (#535, fixed); 5D Mark IV CR2 renders dark (#455, open); white-level pile-up in phone DNGs (#548, fixed) |
| Crop masks and aspect | ✅ | DefaultCrop, Sony recorded size, Canon AspectInfo, Panasonic in-camera crops, Nikon CropArea | 🟡 7RM3 / 7RM4 crop origin 8–32 px off (cosmetic) |
| Lens metadata | ✅ read for profile selection | EXIF lens fields read; used only for the in-file corrections below | 🟡 |
| Highlight reconstruction | ✅ | neutral clip, chromaticity diffusion (`highlight.rs`) | 🟡 tuned by eye |
| AI denoise | ✅ Bayer and X-Trans, model bundled | Bayer only, user-installed weights, pure-Rust CPU / GPU | 🟡 no X-Trans, no shippable weights |
| Super Resolution | ✅ | — | ⬜ |
| HDR / panorama merge to raw DNG | ✅ | linear DNG (float16 HDR) with the source's colour tags | ✅ |
| Convert to DNG | ✅ | uncompressed or LJ92 tiles (`dngwrite.rs`) | ✅ (no lossy DNG) |
## Colour
| Item | Adobe | LightCraft |
|---|---|---|
| Default profile per model | Adobe Standard for every model (1,500 profile names in the bundle) | the DNG's own matrices; else a pooled profile (**4 bundled**: ILCE-7CR, ILCE-7M4, X-H2S, X-T4); else a guarded per-file fit to the camera's embedded JPEG; else spectral matrices (**52 models**, rawtoaces-data); else a neutral matrix |
| Camera Matching looks | 481 models (plus phone-maker looks) | none (the per-file JPEG fit imitates the camera's own look) |
| Creative profiles | Adobe Color, Portrait, Landscape, Vivid, Monochrome… | our own looks (Color, Neutral, Vivid, Landscape, Portrait, Monochrome) |
| DCP / dual-illuminant model | ✅ | dual-illuminant DNG colour (ColorMatrix / ForwardMatrix 1-2, CameraCalibration, AnalogBalance), HueSatMap, LookTable, ProfileToneCurve; external `.dcp` never loaded (clean-room) |
| White balance in Kelvin | ✅ for every model | absolute Kelvin only where matrices exist; per-file fits give relative WB (#296, #730) |
**How far the default rendering is from Adobe's** (CIE ΔE; measured where stated):
- Against the camera JPEG (what the fit targets): the Sony bulk check (#535) accepted fits on 81 of 87
bodies, median ΔE 5.1, ΔL\* +0.2; rejected fits fall back to a neutral matrix at median ΔE 18.5,
ΔL\* −11, chroma ×0.39. RW2 140 of 174 files accepted, median 5.0. NEF 13 of 13, 2.9–7.8. RAF 23 of
24, pooled X-H2S 1.62 / X-T4 2.34. SRW 2.2–7.6.
- Against Lightroom itself (few): Sony DRO median ΔE76 7.5 → 3.3; Olympus E-1 vs Lightroom Classic
ΔE00 11.25 → 8.30; ProRAW with its gain map ΔE00 19 (why the map is off). No measurement against
Adobe Standard across models exists.
- User evidence: 33 open issues about raw colour or rendering (wrong colours, dark, flat, green,
desaturated), the largest group of open core-path issues.
**Colour score ~35%** (estimated): most decoded files start close to the camera's own look (ΔE ~5),
about 10% start far off (ΔE ~18), nothing is calibrated, Kelvin WB is missing for fitted cameras, and
the distance to Adobe Standard is unmeasured. In the readiness numbers this becomes a colour factor
of ×0.85 for a working photographer (they correct colour by hand, at a cost) and ×0.75 for the
essentials user (the default look is what they keep).
## Lens profiles
| Item | Adobe | LightCraft |
|---|---|---|
| Profile database | 3,635 profile files, 56 makers, auto-selected | **0** (Adobe LCPs never used; no database of our own) |
| In-file corrections | ✅ | DNG opcodes (WarpRectilinear, FixVignetteRadial, GainMap…) applied; Panasonic / Leica RW2 distortion (79 photos, 13 bodies, 11 lenses); Sony tag 0x7037 distortion for the ILCE-7RM4A (2 lenses) |
| Vignetting / lateral CA from maker notes | ✅ | ⬜ |
| Manual distortion, vignetting, CA, defringe | ✅ | ✅ |
**Lens score ~10%** (estimated): automatic correction reaches roughly Panasonic / Leica, phone and
drone DNG users (~9% of photographers by the weights above); Adobe reaches nearly everyone.
## Scores
| Part | Weight | Score | Basis |
|---|---:|---:|---|
| Decoding | 60% | **76%** | use-weighted 84% × 0.9 for per-body decode bugs still surfacing (levels, crops, WB: #535, #455, #461, #702) |
| Colour | 25% | **35%** | see [Colour](#colour) |
| Lens profiles | 15% | **10%** | see [Lens profiles](#lens-profiles) |
| **RAW readiness** | 100% | **~56%** (range 50–60%) | 45.6 + 8.75 + 1.5; demosaic and highlight quality unmeasured |
The previous estimate (earlier on 2026-10-10) was ~50%, with decoding at ~78% weighted by maker
from the format list alone. Measured model by model, decoding comes out about the same; the change is
the written decomposition, not new decoding.
## Remaining work, ranked by photographers unlocked per hour
Hours are Opus 5.5 agent hours, calibrated on this repo's raw PRs: RW2 every format 6.5 h (#215),
compressed RAF 8.6 h (#282), CR3 CRX 10 h (#279), NEF lossy after split 4.7 h (#633), ORF 12.8 bpp
1.7 h (#651), HEIC 7 h (#609). "Gain" is the change in the use-weighted share whose camera fully
works, from [raw/usage-weights.tsv](raw/usage-weights.tsv).
| # | Camera / variant | Gain (points of photographers) | Hours | Gain per hour | Needs |
|---:|---|---:|---:|---:|---|
| 1 | Compressed ORF (every Olympus / OM body since ~2008) | +2.6 | 8–15 | ~0.20 | CC0 samples (have 2) |
| 2 | CR3: remaining CRX variants, then verify the 17 popular CR3 bodies | +6.5 | 25–45 | ~0.19 | samples per body (raw.pixls.us has most) |
| 3 | Verify popular Nikon, Fujifilm, Canon CR2 and Pentax bodies (one CC0 file each, fix what breaks) | +2.0 | 8–15 | ~0.17 | public samples |
| 4 | Nikon packed 14-bit under a compressed tag (Z 6II uncompressed, #769) | +0.2 | 1–2 | ~0.13 | PR #671 exists |
| 5 | Sony DSLR-A200…A390 / A850 12-bit compressed ARW | +0.4 | 3–6 | ~0.08 | samples on raw.pixls.us |
| 6 | Pre-X FinePix RAF | +0.6 | 4–8 | ~0.08 | samples |
| 7 | Sony A100 and DSC-F828 regression (#702) | +0.1 | 1–2 | ~0.07 | samples on raw.pixls.us |
| 8 | Canon CRW (2000–2004 bodies) | +1.2 by the uniform tail weight, far less by real use | 6–12 | ≤ 0.1 | samples |
| 9 | Nikon HE / HE★ NEF (Z 8, Z 9, Z 6III, Z f, Z50II, Z5II set to HE) | +1.1 | 20–40 | ~0.04 | a pure-Rust JPEG XS decoder |
| 10 | Compressed SRW, Hasselblad 3FR, IIQ, X3F, MRW, KDC, ERF, DCR, MEF, GPR | +0.6 together | 45–85 | ~0.01 | samples; low use |
Beyond decoding:
| Gap | Hours | Needs |
|---|---:|---|
| Measured colour calibration for the ~60 popular bodies, Kelvin WB, render-fidelity suite against Lightroom | 80–150 | chart shots per camera (a human with cameras) or licensable measured data |
| Lens profile database of our own (fitting tools, data format, top 100 lenses), maker-note vignetting / CA | 40–80 | calibration shots (a human with lenses) |
| Demosaic and highlight quality measured against Lightroom; X-Trans AI denoise | 15–30 | |
| **Total RAW** | **255–480 h** (decoding list above 120–220 h; ~60% parallelizes) | |
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 (later) | major | Model-by-model measurement against Adobe's published list (1,446 models: 234 verified, 943 unverified, 233 preview, 36 unsupported); `docs/raw/` data and re-measure script; use-weighted share 84% (40% on verified bodies); variant matrix; colour and lens sections with scores; ranked next cameras; RAW readiness ~56% from written parts |
| 2026-10-10 | major | Created: formats, makers, demosaic, colour and lens checklists; target counts from the installed Lightroom 9.6 bundle listing |
File diff suppressed because it is too large. Load diff
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""Measure LightCraft's raw camera coverage against Adobe's supported-camera list.
python3 docs/raw/coverage.py # print the summary, rewrite docs/raw/coverage.tsv
python3 docs/raw/coverage.py --check # exit 1 if coverage.tsv is stale
Inputs (all in docs/raw/):
adobe-cameras.tsv Adobe's published list (maker, camera, extensions, ...).
evidence.tsv per-model evidence: verified decodes, known preview-only or refused bodies.
usage-weights.tsv estimated share of photographers per maker bucket and popular bodies.
Every Adobe-listed model gets one class:
verified decoded from sensor data, and a real file from this body was checked (evidence.tsv)
unverified the decoder path for its format and coding should handle it; no sample checked
preview opens as the embedded JPEG (format or coding not decoded)
unsupported not imported, refused, or decodes wrongly
The format rules below mirror the decoders in crates/raw/src (see docs/raw-parity.md). When a decoder
changes, update the rules and evidence, rerun, and commit coverage.tsv with the docs.
Standard library only; no third-party packages.
"""
import csv
import os
import re
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
# Olympus ORF bodies that write uncompressed / packed data (crates/raw/src/vendor/orf.rs). Everything else
# writes compressed ORF, which is preview-only (the E-M5 II / PEN-F high-res mode alone is decoded).
ORF_DECODED = re.compile(r"^(E-1|E-10|E-20|EVOLT E-300|EVOLT E-330|EVOLT E-400|EVOLT E-500|E-300|E-330|E-500|Camedia C-\S+.*|Stylus XZ-2 iHS)$")
# Samsung SRW bodies with compressed raw data (crates/raw/src/vendor/srw.rs refuses 32770 / 32772 / 32773).
SRW_COMPRESSED = re.compile(r"(^|\W)(NX1|NX30|NX300|NX300M|NX500|NX2000|NX3000|NX3300|NX mini|EK-GN\d+|EK-KN\d+)(\W|$)")
# Fujifilm bodies before the X series whose RAF has no raw IFD (crates/raw/src/vendor/raf.rs).
RAF_OLD = re.compile(r"^(FinePix (E|F|S\d|S\d{3,4}|IS)|IS Pro|S5Pro|S3Pro|S2Pro)", re.I)
# Probability that an unverified body of a format decodes correctly, used for the use-weighted share only.
CONFIDENCE = {"DNG": 0.95, "CR2": 0.95, "CR3": 0.6, "NEF": 0.9, "NRW": 0.9, "ARW": 0.9, "SR2": 0.8, "RAF": 0.95,
"RW2": 0.95, "RWL": 0.95, "RAW": 0.95, "PEF": 0.9, "ORF": 0.8, "SRW": 0.8}
def read_tsv(name):
with open(os.path.join(HERE, name), newline="", encoding="utf-8") as f:
lines = [line for line in f if not line.startswith("#")]
return list(csv.DictReader(lines, delimiter="\t"))
def exts(field):
return [e.strip().upper() for e in re.split(r"[,/+]", re.sub(r"\(.*?\)", "", field)) if e.strip()]
def classify(maker, camera, ext_field):
"""(class, format, reason) from the format rules alone."""
es = exts(ext_field)
for e in es:
if e == "DNG":
return "unverified", "DNG", "DNG decoder (uncompressed, LJ92, lossy, Deflate, JPEG XL, LinearRaw)"
if e == "CR2":
return "unverified", "CR2", "CR2 lossless JPEG decoder"
if e == "CR3":
return "unverified", "CR3", "CRX decoder: lossless and C-RAW 0x100 / 0x200 single-tile; other variants fall back to the preview"
if e in ("NEF", "NRW"):
return "unverified", e, "NEF decoder (uncompressed, lossless, lossy, lossy after split); HE / HE* setting preview-only"
if e == "ARW":
return "unverified", "ARW", "ARW decoder (uncompressed, cRAW, packed 12-bit, lossless, downsized YCbCr)"
if e == "SR2":
return "unverified", "SR2", "SR2 decoder"
if e == "RAF":
if RAF_OLD.search(camera):
return "preview", "RAF", "pre-X FinePix RAF without a raw IFD"
return "unverified", "RAF", "RAF decoder (uncompressed, lossless / lossy compressed, Bayer and X-Trans)"
if e in ("RW2", "RWL") or (e == "RAW" and maker in ("Panasonic", "Leica")):
return "unverified", e, "Panasonic decoder, every raw format"
if e == "PEF":
return "unverified", "PEF", "PEF decoder (uncompressed, Huffman, packed 12-bit)"
if e == "ORF":
if ORF_DECODED.match(camera):
return "unverified", "ORF", "uncompressed / packed ORF"
return "preview", "ORF", "compressed ORF is not decoded"
if e == "SRW":
if SRW_COMPRESSED.search(camera):
return "preview", "SRW", "compressed SRW is not decoded"
return "unverified", "SRW", "uncompressed / packed SRW"
e = es[0] if es else ""
if e in ("CRW", "3FR", "FFF", "IIQ", "MOS", "ERF", "KDC", "MRW", "X3F", "RAW", "ORI"):
return "preview", e, f"{e} is opened from its embedded JPEG only"
return "unsupported", e, f"{e or 'unknown'} is not imported"
def main():
adobe = read_tsv("adobe-cameras.tsv")
evidence = {(r["maker"], r["camera"]): r for r in read_tsv("evidence.tsv")}
rows = []
for a in adobe:
cls, fmt, reason = classify(a["maker"], a["camera"], a["extensions"])
ev = evidence.get((a["maker"], a["camera"]))
if ev:
cls, reason = ev["status"], ev["source"]
rows.append({"maker": a["maker"], "camera": a["camera"], "format": fmt, "year_added": a["year_added"], "class": cls, "reason": reason})
out = os.path.join(HERE, "coverage.tsv")
header = ["maker", "camera", "format", "year_added", "class", "reason"]
text = "# Generated by docs/raw/coverage.py; do not edit.\n" + "\t".join(header) + "\n"
text += "".join("\t".join(r[k] for k in header) + "\n" for r in rows)
if "--check" in sys.argv:
with open(out, encoding="utf-8") as f:
if f.read() != text:
print("docs/raw/coverage.tsv is stale: run python3 docs/raw/coverage.py")
return 1
else:
with open(out, "w", encoding="utf-8") as f:
f.write(text)
classes = ["verified", "unverified", "preview", "unsupported"]
by_maker = {}
for r in rows:
by_maker.setdefault(r["maker"], {c: 0 for c in classes})[r["class"]] += 1
print("| Maker | Adobe models | verified | unverified | preview | unsupported |")
print("|---|---:|---:|---:|---:|---:|")
for m, c in sorted(by_maker.items(), key=lambda kv: -sum(kv[1].values())):
print(f"| {m} | {sum(c.values())} | " + " | ".join(str(c[k]) for k in classes) + " |")
tot = {k: sum(c[k] for c in by_maker.values()) for k in classes}
n = sum(tot.values())
print(f"| **All** | **{n}** | " + " | ".join(f"**{tot[k]}** ({100 * tot[k] / n:.0f}%)" for k in classes) + " |")
recent = [r for r in rows if r["year_added"] and int(r["year_added"]) >= 2017]
rc = {k: sum(1 for r in recent if r["class"] == k) for k in classes}
print(f"\nModels added since 2017 (ACR 10+): {len(recent)}: " + ", ".join(f"{k} {rc[k]}" for k in classes))
# Use-weighted share of photographers whose camera fully works (decodes from sensor data).
weights = read_tsv("usage-weights.tsv")
by_cam = {(r["maker"], r["camera"]): r for r in rows}
total = works = verified_share = 0.0
print("\n| Bucket | Weight | Camera fully works | of which verified bodies |")
print("|---|---:|---:|---:|")
for b in [w for w in weights if w["kind"] == "maker"]:
makers = b["makers_or_camera"].split(",")
popular = [w["makers_or_camera"] for w in weights if w["kind"] == "body" and w["bucket"] == b["bucket"]]
members = [r for r in rows if r["maker"] in makers]
pop_rows = [r for m in makers for (mk, cam), r in by_cam.items() if mk == m and cam in popular]
missing = set(popular) - {r["camera"] for r in pop_rows}
if missing:
print(f"usage-weights.tsv: unknown cameras {sorted(missing)}", file=sys.stderr)
return 1
rest = [r for r in members if r["camera"] not in popular]
def score(r):
if r["class"] == "verified":
return 1.0
if r["class"] == "unverified":
return CONFIDENCE.get(r["format"], 0.7)
return 0.0
def mean(rs, f):
return sum(f(r) for r in rs) / len(rs) if rs else 0.0
if pop_rows:
s = 0.8 * mean(pop_rows, score) + 0.2 * mean(rest, score)
v = 0.8 * mean(pop_rows, lambda r: r["class"] == "verified") + 0.2 * mean(rest, lambda r: r["class"] == "verified")
else:
s, v = mean(members, score), mean(members, lambda r: r["class"] == "verified")
w = float(b["weight"])
total += w
works += w * s
verified_share += w * v
print(f"| {b['bucket']} | {w:g}% | {100 * s:.0f}% | {100 * v:.0f}% |")
print(f"| **Weighted** | {total:g}% | **{100 * works / total:.0f}%** | **{100 * verified_share / total:.0f}%** |")
return 0
if __name__ == "__main__":
sys.exit(main())
File diff suppressed because it is too large. Load diff
+249
View File
@@ -0,0 +1,249 @@
# Per-model evidence that overrides the format rules in coverage.py. status: verified | preview | unsupported.
# "verified" means a real file from this body decoded from sensor data in a corpus test or a recorded bulk check (source column).
maker camera status source
Apple iPhone 12 Pro Rear Wide Camera verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 40D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 550D (EOS Digital Rebel T2i, EOS Kiss X4 Digital) verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 5D Mark II verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 5DS R verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 6D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 7D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS 80D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Canon EOS M50 (EOS Kiss M) verified corpus: crates/raw/tests/cr3_corpus.rs (exact sensor hashes, docs/cr3.md)
Canon EOS R100 verified corpus: crates/raw/tests/cr3_corpus.rs (exact sensor hashes, docs/cr3.md)
Canon EOS R8 verified corpus: crates/raw/tests/cr3_corpus.rs (exact sensor hashes, docs/cr3.md)
Canon EOS-5D Mark III verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm GFX 100 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm GFX 100RF (Final Support) verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm GFX 100S verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm GFX 50S verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-A2 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-A5 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-E1 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-E5 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-H2 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-H2S verified docs/raf-compression.md (supplied files, exact sensor arrays)
Fujifilm X-M5 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-T2 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-T20 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-T4** verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-T5 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Fujifilm X-T50 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Google Pixel 2 XL verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Leica C (Typ 112) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica D-Lux (Typ 109) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica D-Lux 3 verified PR #215: raw.pixls.us bulk check of every RW2 / RWL / RAW body
Leica D-Lux 4 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica D-Lux 5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica D-Lux 6 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica D-Lux 7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica Digilux 2 verified PR #215: raw.pixls.us bulk check of every RW2 / RWL / RAW body
Leica Digilux 3 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica V-LUX (Typ 114) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica V-LUX 1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica V-LUX 4 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Leica V-LUX 5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Nikon COOLPIX B700 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Nikon D5100 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Nikon D7000 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Nikon D7500 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Nikon Z f verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Olympus E-1 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Olympus EVOLT E-400 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Olympus Stylus XZ-2 iHS verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Panasonic LUMIX DC - G97 (DC-G99M2) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-FZ1000M2 (DC-FZ10002) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-FZ80 (DC-FZ82, DC-FZ85) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-G100 (DC-G110) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-G100D verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-G9 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-G95D verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-G99 (DC-G90, DC-G91, DC-G95) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GF10 (DC-GF90) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GF9 (DC-GX850, DC-GX800) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GH5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GH5M2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GH5s verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GH6 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GH7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GX880 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-GX9 (DC-GX7MK3) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-LX100 II verified PR #215: raw.pixls.us bulk check of every RW2 / RWL / RAW body
Panasonic LUMIX DC-S1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S1H verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S1M2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S1M2ES (Final Support) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S1R verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S1RM2 (Final Support) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S5M2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S5M2X verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-S9 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-TX2D (DC-TZ200D, DC-TZ202D, DC-TZ220D, DC-ZS200D, DC-ZS220D) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-ZS70 (DC-TZ90, DC-TZ91, DC-TZ92, DC-TZ93) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-ZS80 (DC-TZ95, DC-TZ96, DC-TZ97) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DC-ZS80D (DC-TZ95D, DC-TZ96D) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DCG9M2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-CM1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FX150 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ100 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ1000 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ150 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ18 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ200 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ2500 (DMC-FZ2000, DMC-FZH1) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ28 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ30 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ300 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ330 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ35 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ38 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ40 (DMC-FZ45) verified PR #215: raw.pixls.us bulk check of every RW2 / RWL / RAW body
Panasonic LUMIX DMC-FZ50 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ70 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ72 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-FZ8 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G10 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G3 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G6 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-G8 (DMC-G80, DMC-G81, DMC-G85) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF3 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF6 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GF8 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GH1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GH2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GH3 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GH4 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GM1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GM1S verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GM5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GX1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GX7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GX8 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-GX85 (DMC-GX80, DMC-GX7MK2) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-L1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-L10 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LF1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX1 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX100 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX2 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX3 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX5 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX7 verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-LX9 (DMC-LX10, DMC-LX15) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-ZS100 (DMC-ZS110, DMC-TZ100, DMC-TZ101, DMC-TZ110, DMC-TX1) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-ZS40 (DMC-TZ60, DMC-TZ61) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-ZS50 (DMC-TZ70, DMC-TZ71) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX DMC-ZS60 (DMC-TZ80, DMC-TZ81, DMC-TZ85) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Panasonic LUMIX ZS200 (DC-TX2, DC-TZ200, DC-TZ202, DC-TZ220, DC-ZS220) verified PR #215: 178 raw.pixls.us files from 118 Panasonic / Leica bodies, every RW2 format
Pentax K-3 verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Pentax K-5 IIs verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Pentax K10D verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Ricoh GR III verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Samsung TL500 (EX1) verified corpus: crates/raw/tests/corpus.rs (xtask RAW_SAMPLES)
Sony A100 (DSLR-A100) unsupported issue #702: regression, refused as not a readable photo
Sony A200 (DSLR-A200) preview issue #535: preview-only on the raw.pixls.us sample
Sony A230 (DSLR-A230) preview issue #535: preview-only on the raw.pixls.us sample
Sony A290 (DSLR-A290) preview issue #535: preview-only on the raw.pixls.us sample
Sony A300 (DSLR-A300) preview issue #535: preview-only on the raw.pixls.us sample
Sony A3000 (ILCE-3000) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A33 (SLT-A33) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A330 (DSLR A330) preview issue #535: preview-only on the raw.pixls.us sample
Sony A35 (SLT-A35) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A350 (DSLR-A350) preview issue #535: preview-only on the raw.pixls.us sample
Sony A3500 (ILCE-3500) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A37 (SLT-A37) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A380 (DSLR-A380) preview issue #535: preview-only on the raw.pixls.us sample
Sony A390 (DSLR-A390) preview issue #535: preview-only on the raw.pixls.us sample
Sony A450 (DSLR-A450) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A500 (DSLR-A500) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A5000 (ILCE-5000) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A5100 (ILCE-5100) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A550 (DSLR-A550) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A55V (SLT-A55V) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies
Sony A560 (DSLR-A560) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A57 (SLT-A57) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A58 (SLT-A58) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A580 (DSLR-A580) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6000 (ILCE-6000) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6100 (ILCE-6100) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6300 (ILCE-6300) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6400 (ILCE-6400) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A65 (SLT-A65) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6500 (ILCE-6500) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6600 (ILCE-6600) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A6700 (ILCE-6700) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A68 (ILCA-68) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7 (ILCE-7) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7 II (ILCE-A7M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies
Sony A7 III (ILCE-7M3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7 IV (ILCE-7M4) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A700 (DSLR-A700) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A77 (SLT-A77) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A77 II (ILCA-77M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7C (ILCE-7C) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7C II (ILCE-7CM2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7CR (ILCE-7CR) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R (ILCE-7R) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R II (ILCE-7RM2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R III (ILCE-7RM3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R IIIA (ILCE-7RM3A) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R IV (ILCE-7RM4) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R IVA (ILCE-7RM4A) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7R V (ILCE-7RM5) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7S (ILCE-7S) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7S II (ILCE-7SM2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A7s III (ILCE-7SM3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A850 (DSLR-A850) preview issue #535: preview-only on the raw.pixls.us sample
Sony A9 (ILCE-9) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A9 II (ILCE-9M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A9 III (ILCE-9M3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A900 (DSLR-A900) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony A99 (SLT-A99V) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies
Sony A99 II (ILCA-99M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony Alpha 1 (ILCE-1)* verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony DSC-F828 unsupported issue #702 (SRF refused); SRF not in the import list
Sony DSC-HX95 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony DSC-HX99 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony DSC-V3 unsupported SRF not in the import list
Sony FX3 (ILME-FX3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony FX30 (ILME-FX30) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-3 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-3N verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-5 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-5N verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-5R verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-5T verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-6 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-7 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-C3 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony NEX-F3 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony QX1 (ILCE-QX1) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX0 (DSC-RX0) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX0 II (DSC-RX0M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX1 (DSC-RX1) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX10 (DSC-RX10) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX10 II (DSC-RX10M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX10 III (DSC-RX10M3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX10 IV (DSC-RX10M4) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 (DSC-RX100) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 II (DSC-RX100M2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 III (DSC-RX100M3) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 IV (DSC-RX100M4) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 V (DSC-RX100M5) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 VA (DSC-RX100M5A) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 VI (DSC-RX100M6) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX100 VII (DSC-RX100M7) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX1R (DSC-RX1R) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony RX1R II (DSC-RX1RM2) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony ZV-1 (DCZV1/B) verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony ZV-E1 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Sony ZV-E10 verified issue #535: raw.pixls.us bulk check of all 100 Sony bodies (decodes; BL/WL/crop/WB vs ExifTool)
Can't render this file because it contains an unexpected character in line 2 and column 3.
+114
View File
@@ -0,0 +1,114 @@
# Estimated share of Lightroom raw photographers by camera maker, and the popular bodies of the last ~8 years inside each.
# Sources (2026-10-10): Nikkei 2025 mirrorless production via PhotoRumors (Canon 2.3 M, Sony 1.8 M, Nikon 0.86 M, Fujifilm 0.75 M
# units, i.e. ~36 / 29 / 14 / 12 % of CIPA's 6.31 M); BCN 2025 Japanese retail via PetaPixel (Sony 29.9 %, Canon 27.4 %, Nikon 15.1 %);
# camera makers named in this repo's user issues (325 issues: Sony 33, Nikon 31, Canon 26, phones 23, Fujifilm 9, Panasonic/Leica 8,
# OM/Olympus 6, Pentax/Ricoh 6, Samsung NX 5). Canon and Nikon get extra weight for their installed base of DSLRs.
# Rows "maker" give the maker bucket's weight (percent of photographers); rows "body" give a popular body inside a bucket.
# Inside a bucket, the listed bodies share 80 % equally and every other Adobe-listed model of the bucket's makers shares 20 %.
kind bucket makers_or_camera weight
maker Canon Canon 33
maker Sony Sony 27
maker Nikon Nikon 16
maker Fujifilm Fujifilm 10
maker Panasonic Panasonic 4
maker OM / Olympus Olympus,OM Digital Solutions 3
maker Phones Apple,Google,Samsung,Xiaomi,Huawei,Oppo,OnePlus,LG,Motorola,Nokia 3
maker Pentax / Ricoh Pentax,Ricoh 1.5
maker Leica Leica 1
maker DJI DJI 1
maker Medium format and others Hasselblad,Phase One,Leaf,Mamiya,Sigma,Kodak,Konica Minolta,Epson,Casio,GoPro,Insta360,Zeiss,Pixii,Light,Skydio,Parrot,Yuneec,Contax,DxO 0.5
body Canon EOS R6 Mark II 1
body Canon EOS R5 1
body Canon EOS R6 1
body Canon EOS R7 1
body Canon EOS R8 1
body Canon EOS R10 1
body Canon EOS R50 1
body Canon EOS RP 1
body Canon EOS R (** see note) 1
body Canon EOS R5 Mark II 1
body Canon EOS R6 Mark III 1
body Canon EOS R3 1
body Canon EOS R100 1
body Canon EOS 90D 1
body Canon EOS M50 (EOS Kiss M) 1
body Canon EOS M50 Mark II 1
body Canon EOS M6 Mark II 1
body Canon EOS-5D Mark IV (** see note) 1
body Canon EOS 6D Mark II 1
body Canon EOS 80D 1
body Canon EOS 250D (EOS Rebel SL3, EOS 200D II, EOS Kiss X10) 1
body Canon EOS 1500D (EOS Rebel T7, EOS Kiss X90, EOS 2000D) 1
body Sony A7 IV (ILCE-7M4) 1
body Sony A7 III (ILCE-7M3) 1
body Sony A7R V (ILCE-7RM5) 1
body Sony A7R IV (ILCE-7RM4) 1
body Sony A7C (ILCE-7C) 1
body Sony A7C II (ILCE-7CM2) 1
body Sony A7CR (ILCE-7CR) 1
body Sony A6400 (ILCE-6400) 1
body Sony A6700 (ILCE-6700) 1
body Sony A6600 (ILCE-6600) 1
body Sony A6100 (ILCE-6100) 1
body Sony Alpha 1 (ILCE-1)* 1
body Sony A9 III (ILCE-9M3) 1
body Sony ZV-E10 1
body Sony A7s III (ILCE-7SM3) 1
body Sony RX100 VII (DSC-RX100M7) 1
body Nikon Z 6 II 1
body Nikon Z 6 III 1
body Nikon Z 8 1
body Nikon Z 9 (*See note) 1
body Nikon Z f 1
body Nikon Z 5 1
body Nikon Z 50 1
body Nikon Z 50 II 1
body Nikon Z fc 1
body Nikon Z 7 II 1
body Nikon D850 1
body Nikon D750 1
body Nikon D7500 1
body Nikon D780 1
body Fujifilm X-T5 1
body Fujifilm X-T4** 1
body Fujifilm X-S20 1
body Fujifilm X-S10 1
body Fujifilm X-H2S 1
body Fujifilm X-H2 1
body Fujifilm X100V** 1
body Fujifilm X100VI 1
body Fujifilm X-T30 II 1
body Fujifilm X-E4 1
body Fujifilm X-T50 1
body Fujifilm GFX 100S 1
body Fujifilm X-M5 1
body Panasonic LUMIX DC-S5 1
body Panasonic LUMIX DC-S5M2 1
body Panasonic LUMIX DC-GH6 1
body Panasonic LUMIX DC-GH5M2 1
body Panasonic LUMIX DCG9M2 1
body Panasonic LUMIX DC-G9 1
body Panasonic LUMIX DC-S1 1
body Panasonic LUMIX DC-GX9 (DC-GX7MK3) 1
body Panasonic LUMIX DMC-G8 (DMC-G80, DMC-G81, DMC-G85) 1
body Panasonic LUMIX DC-LX100 II 1
body OM / Olympus OM-D E-M1 Mark III 1
body OM / Olympus OM-D E-M1 Mark II 1
body OM / Olympus OM-D E-M10 Mark IV 1
body OM / Olympus OM-D E-M5 Mark III 1
body OM / Olympus PEN E-P7 1
body OM / Olympus Stylus Tough TG-6 1
body OM / Olympus OM System OM-1 1
body OM / Olympus OM System OM-1 MARK II 1
body OM / Olympus OM System OM-5 1
body Pentax / Ricoh K-1 II (* see note) 1
body Pentax / Ricoh K-3 Mark III 1
body Pentax / Ricoh KF 1
body Pentax / Ricoh K-70 1
body Pentax / Ricoh GR III 1
body Pentax / Ricoh GR IIIx 1
body Leica Q3 1
body Leica Q2 1
body Leica M11 1
body Leica SL2 1
body Leica M10 1
Can't render this file because it contains an unexpected character in line 6 and column 8.
+113
View File
@@ -0,0 +1,113 @@
# Roadmap: milestones, current focus and what's next
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; milestones moved here from ROADMAP.md, focus re-ranked after the 2026-10-10 re-measure) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
Forward-looking plan. The summary with the headline numbers is [ROADMAP.md](../ROADMAP.md); the
ranked shortfalls are [gaps.md](gaps.md); the numbers come from [target-app-parity.md](target-app-parity.md).
LightCraft has no `cargo xtask scorecard`; the measured checklist is
[parity-checklist.md](parity-checklist.md) (`cargo xtask parity`).
## Current focus
Toward **beta** (~340–600 Opus 5.5 agent hours; ranked, each a gap in [gaps.md](gaps.md)):
1. **Camera colour of our own** (gap 1, 50–90 h): chart-based calibration for the most-used models,
building on the per-file JPEG fits and pooled profiles (`lightcraft-cli calibrate`); never Adobe
data.
2. **CR3 for every Canon body** (gap 2, 25–45 h): the remaining CRX variants, sRAW / mRAW, HEIF CR3;
clean-room from prose descriptions (decided 2026-10-05; compressed NEF is the template).
3. **Render-fidelity suite** (gap 3, 30–60 h): score our output against Lightroom's on the same CC0
raws (references local in `plan/`), then tune; a retune ships as a new process version.
4. **Full-resolution zoom** (gap 4, 8–15 h): visible-region rendering so 100% shows original pixels.
5. **AI masks** (gap 5, 40–70 h): Subject / Sky / People on licensable weights; configure the SAM 3
mirror. Needs the maintainer's model decision.
6. **Compressed ORF and HE NEF** (gaps 6–7, 28–55 h).
7. **Lens profiles of our own** (gap 8, 40–80 h).
8. **Tests in CI on macOS, Windows and Linux** (gap 9, 6–12 h).
9. **Per-model verification** (gap 10, 20–35 h).
## Alpha gate
The target's core workflows: what a typical Lightroom user does every day. Alpha requires each to
work end to end on the main platform (macOS) and the work to save and reopen. Checked on 2026-10-10
against the code, tests, issues and [gaps.md](gaps.md).
| Workflow | Works end to end? | Evidence | Hours to pass |
|---|---|---|---:|
| 1. Import a shoot (raw + JPEG) from a card or folder into the library | yes | Add / Copy / Move import with templates, duplicates, devices with DCIM, background import with cancel (`crates/engine/src/import.rs`, `tests_import.rs`, `tests_import_move.rs`); checklist A 83% | 0 |
| 2. Cull: rate, flag, label, compare / survey, filter, check focus | yes (partial: focus check) | ratings / flags / labels with advance, Compare, Survey ≤ 48, filter bar, smart albums (checklist B–D 88–92%); 100% zoom is capped by the preview size (2,560 px default, adjustable in Settings), gap 4 — degrades focus checks on large files but does not block culling | 0 (8–15 h to close gap 4, beta) |
| 3. Develop raws non-destructively (global sliders, crop, masks, heal) | yes for most cameras (partial: Canon CR3 outside the verified variants, compressed ORF, HE NEF open as embedded previews) | Sony, Nikon (except HE), Fujifilm, Panasonic, Pentax, CR2, DNG decode from sensor data (raw-parity.md); every Edit slider, crop / Upright, brush / gradient / range masks, heal / clone (checklist F, H, K); colour estimated per file rather than measured, gaps 1–3 | 0 (coverage and colour gaps are beta blockers 1–3, 6–7) |
| 4. Save, quit and reopen the work | yes | crash-safe journal + snapshots, torn-append and crash tests (`crates/catalog/src/journal.rs`, `tests_journal.rs`, `tests_torn_append.rs`); XMP sidecars read / write; failed saves reported | 0 |
| 5. Batch-apply a look: presets, copy / paste / sync settings | yes | presets (incl. `.xmp` / `.lrtemplate` import), copy / paste / sync, auto sync (checklist L 86%, N 100%) | 0 |
| 6. Export deliverables (JPEG / TIFF, size, sharpening, metadata, watermark, naming) | yes | one encoder for app, CLI and MCP (`crates/engine/src/export.rs`, `tests_export.rs`); checklist S 89% | 0 |
**Result: passes.** Every core workflow runs end to end on macOS and the work survives quit and
reopen; the partial rows degrade fidelity for some cameras and large files but don't stop the
workflow, so LightCraft stays **alpha** (ready for real work ~61%, above the ~40% bar).
## After beta
Enhance (Raw Details, Super Resolution, X-Trans denoise), content-aware remove, HDR display, the
Classic output modules (Print, then Map, Book, Slideshow, publish services), tethering, video,
plug-in ecosystem, localization to `full` and new scripts (RTL, shaping). Estimates in
[gaps.md](gaps.md) entries 11–28; ~500–1,300 h after beta.
## Milestones
Original wall-clock estimates (made before work started, 4–6 parallel agents) are kept for
calibration: M0–M13 took ≈ 25 active hours against an estimate of ≈ 110–170 h.
**Status legend:** ✅ done · 🚧 in progress · ⬜ not started
| # | Milestone | Scope (summary) | Estimate (h) | Status |
|---|---|---|---|---|
| M0 | Skeleton + visual shell | workspace, xtask CI + layering, geom/color/raster, develop model, pipeline v0, catalog v0, engine commands, Lightroom-look UI (grid, loupe, filmstrip, Edit panel), control channel, MCP, web build | 3–5 | ✅ |
| M1 | Library core | import (JPEG/PNG/TIFF/WebP), EXIF/XMP, persistent catalog (op log + snapshots), albums, ratings/flags/labels, filter/search/sort, thumbnail cache, 100k-photo grid | 6–10 | ✅ (100k-photo grid scale test pending) |
| M2 | Pipeline v1 (quality) | WB temp/tint, profiles, local tone mapping (highlights/shadows), curves, HSL, point colour, colour grading, texture/clarity/dehaze, vignette, grain, B&W, auto tone/WB, histogram, before/after | 10–15 | ✅ (look tuning vs our references ongoing) |
| M3 | RAW I | TIFF/DNG (LJ92, deflate, tiles, opcodes), demosaic (AHD/PPG/bilinear), highlight recovery, DNG colour model, CR2, NEF, ARW, embedded previews | 10–15 | ✅ (DNG, CR2 incl. sRAW, ARW, NEF uncompressed / lossless / lossy / lossy after split, embedded previews) |
| M4 | Crop, geometry, optics | crop tool + overlays, straighten, Upright (auto/level/vertical/full/guided), manual transforms, CA, defringe, manual lens corrections | 6–10 | ✅ |
| M5 | Performance | source pyramids, wgpu compute pipeline (CPU oracle), draft/full renders, prefetch, budgets (16 ms slider updates on 24 MP) | 10–15 | 🚧 (stage cache, source pyramid, wgpu pipeline, prefetch, memory budget ✅; colour NR at half resolution, GPU histogram ⬜) |
| M6 | Masking | brush, linear/radial gradients, colour/luminance/depth range, add/subtract/intersect/invert, all local adjustments, masks panel | 8–12 | 🚧 (brush/linear/radial/colour/luminance range, add/subtract/intersect, masks panel ✅; depth range, AI masks ⬜) |
| M7 | Detail | sharpening + masking preview, luminance/colour NR, Denoise, Raw Details, Super Resolution | 6–10 | 🚧 (sharpening, luminance/colour NR ✅; AI Denoise 🟡 (Bayer, optional weights; policy/fidelity open); Raw Details, Super Resolution ⬜) |
| M8 | Heal / Remove | content-aware remove (PatchMatch), heal, clone, brush spots, visualize spots, red/pet eye | 6–10 | 🚧 (heal, clone, auto source, visualize spots, red/pet eye ✅; PatchMatch remove ⬜) |
| M9 | Presets, profiles, versions, sync | preset browser + amount, create/import presets, profile browser, versions, history, copy/paste/sync settings | 5–8 | ✅ |
| M10 | Export & share | export dialog (JPEG/PNG/TIFF/DNG/AVIF/JXL/original), sizing, sharpening, metadata, watermark, naming, batch jobs, XMP sidecars, HDR export | 6–10 | 🚧 (all formats incl. DNG/original, sizing, presets, background jobs, HDR gain map JPEG / PQ AVIF ✅; JXL encode ⬜) |
| M11 | RAW II | CR3, RAF (X-Trans), ORF, RW2, PEF, SRW, 3FR, IIQ + long tail; camera calibration DB; HEIC/AVIF/JXL import | 20–35 | 🚧 (RAF all, RW2 every format, PEF, ORF uncompressed and 12.8 bpp, SRW uncompressed, HEIC ✅; CR3 🟡 (3 bodies verified); **camera colour calibration** 🚧 (per-file JPEG fits, 4 bundled profiles, 52 spectral matrices; measured database missing); compressed ORF / SRW, HE NEF, IIQ, X3F ⬜) |
| M12 | AI & smart features | subject/sky/background/people/object masks, semantic search, faces/People (permissively licensed models, pure-Rust inference) | 20–40 | 🚧 (faces: detection, recognition, People view ✅; Object / Describe masks via SAM 3 🟡; Subject / Sky / People masks, semantic search ⬜) |
| M13 | Merge | HDR merge (deghost), panorama (projections, boundary warp, fill edges), HDR panorama | 10–15 | ✅ |
| M14 | Video | import/playback/trim via FilmCraft crates, global edits + presets on video, video export | 6–10 | ⬜ |
| M15 | Classic modules | Map, Book, Slideshow, Print, Web; smart collections, stacks, virtual copies, publish services, tethering | 25–40 | 🚧 (smart albums, stacks, virtual copies, compare/survey ✅; contact-sheet PDF 🟡; Map/Book/Slideshow/Print/Web ⬜) |
| M16 | 1.0 polish | preferences, shortcut editor, accessibility, localization, packaging (dmg/msi/AppImage/web), hardening | 10–20 | 🚧 (settings, keyboard shortcuts sheet, packaging basics ✅; English/Chinese (Simplified, Traditional)/Japanese/Brazilian Portuguese/Spanish/German/Russian/Ukrainian localisation 🟡; accessibility and further locales ⬜) |
## Risks that coding hours alone don't retire
- **AI features** (subject / sky / people masks, generative remove) need model weights with
licences we can ship; classical fallbacks first. No permissively licensed sky-segmentation or
raw-denoise model was found; we may need to train our own.
- **Camera colour and lens data** is a data problem: we never use Adobe's matrices, DCPs or LCPs.
DNG-embedded data first, then our own calibration; long-tail coverage grows over time and needs
people with cameras, lenses and charts.
- **Raw-format sources:** decoders are written from prose format descriptions (even ones published
alongside GPL code); decoder source is never read (decided 2026-10-05). Still open:
freedom-to-operate review for local Laplacian filters, PatchMatch and HEVC (HEIC).
- **Look parity** with Adobe's default rendering is tuned by eye until the fidelity suite exists.
Retuning changes existing edits, so it ships as a new process version
([process-versions.md](process-versions.md)).
## Design notes kept from the old ROADMAP
- **Folder records:** library folders have records of their own in the catalog
(`Catalog.folder_records`, keyed by folder path; colour labels first). Photos still store full
paths, so moving a whole disk relinks each photo. If that becomes a problem (an "Update Folder
Location" for a renamed drive, journal growth on large moves), the next step is the Classic model:
photos point to a folder id (root + relative path).
- **Zoom:** native pinch zoom and two-finger pan work in Detail, Compare and Reference views; the
whole-image preview still has a configurable cap (2,560 px default), see gap 4.
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | minor | Beta hours 340–600; full ready ~59% in the gate note |
| 2026-10-10 | minor | Added the Alpha gate table (core-workflow gate from the revised standard): passes, stays alpha |
| 2026-10-10 | major | Created: milestones moved from ROADMAP.md (statuses refreshed: M3 ✅, M11 / M12 / M15 detail), current focus re-ranked toward beta, risks and design notes kept |
+304
View File
@@ -0,0 +1,304 @@
# Target-app parity: LightCraft vs Adobe Lightroom
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (full re-measure against Lightroom Classic 15.5 and the installed Lightroom 9.6; merged ROADMAP's parity estimate and honest assessment into this file) · **Target:** Adobe Lightroom Classic 15.5 (August 2026) and Lightroom 9.6 (desktop)
The authoritative assessment of how close LightCraft is to Lightroom. The row-by-row checklist is
[parity-checklist.md](parity-checklist.md); the ranked work list is [gaps.md](gaps.md); deep areas
have their own documents: [raw-parity.md](raw-parity.md), [file-format-parity.md](file-format-parity.md),
[ui-parity.md](ui-parity.md), [hardware-parity.md](hardware-parity.md),
[localization-parity.md](localization-parity.md).
## Headline
| Number | Value | Kind |
|---|---:|---|
| **Feature breadth**, checklist | **81.1%** of 517 in-scope rows (P0 98.0%, P1 95.1%, P2 46.9%) | **measured**: recount of [parity-checklist.md](parity-checklist.md) rows (✅ 1, 🟡 ½, 🚫 left out), the same rule `cargo xtask parity` uses |
| **Feature breadth**, weighted by use | **~77%** | estimated: feature-area table below |
| **Ready for real work** (full target) | **~61%** (range 56–66%) | estimated: weighted sum over the dimensions with written weights, see [below](#ready-for-real-work-mainstream-practitioner-and-essentials-user) |
| **Mainstream practitioner** | **~49%** (range 44–54%) | estimated: weekly areas of a working photographer, depth 71.8% × 0.804 × colour 0.85 |
| **Essentials user** | **~64%** (range 59–69%) | estimated: core features at default settings, depth 77.4% × 0.830 |
| Remaining to **beta** | **~340–600 h** | estimated; ~60% parallelizes |
| Remaining to **full parity** | **~1,000–1,800 h** | estimated; ~70% parallelizes |
| **Stage** | **alpha** | see [Stage](#stage) |
## The target and how it was measured
- **Target:** Lightroom Classic 15.5 (August 2026; latest per Adobe's release notes) for the
library, modules and depth; Lightroom 9.6 (the cloud-library desktop app), installed on the
owner's Mac at `/Applications/Adobe Lightroom CC`, for the interface LightCraft's layout follows.
Both share the Camera Raw engine.
- **Installed bundle, inspected by listing only** (the clean-room rule forbids reading contents):
`Info.plist` document types (31 raw extensions, jpg, tif, heic, xmp, catalog bundles); 16
`.lproj` localizations; `CameraProfiles` (1,500 Adobe Standard and 395 Camera Matching model
names); `LensProfiles` (3,635 files, 56 makers); `ModelZoo` (37 AI model names). The app was not
launched.
- **LightCraft side:** origin/main at `b70ae174` (2026-10-10): code counts (226 engine commands, 143
UI commands, 122 + 10 develop controls, 2,561 tests, ≈ 202,000 Rust lines in 24 crates + 3 apps),
the checklist rows, raw corpus manifests, locale catalogs, CI workflows, docs.
- **Behaviour and output** were not compared against a running Lightroom in this pass; the
measured ΔE figures in [raw-parity.md](raw-parity.md) come from earlier work.
**Presence is not parity.** ✅ rows are set by whoever lands a feature and have not been checked
systematically against Lightroom's behaviour; bugs keep turning up in ✅ areas (CR2 colour-filter
phase #85, duplicate Local entries #22, black GPU exports on an Intel iGPU #78).
## By dimension
| Dimension | Breadth | Ready for real work | Remaining | Doc |
|---|---:|---:|---:|---|
| Features (weighted areas below) | ~77% (checklist 81.1%, measured) | ~61% | 600–1,100 h | [Features](#features) |
| ↳ RAW cameras, colour and lens profiles (part of features) | 81% of Adobe's 1,446 models decode (16% verified), measured | ~56% | 255–480 h | [raw-parity.md](raw-parity.md) |
| UI/UX fidelity | ~85% | ~70% | 40–70 h | [ui-parity.md](ui-parity.md) |
| File formats (non-raw: images, sidecars, presets, catalogs) | ~85% | ~70% | 30–55 h | [file-format-parity.md](file-format-parity.md) |
| Hardware | ~50% | ~40% | 40–80 h (+ tethering and printing, counted under Classic modules) | [hardware-parity.md](hardware-parity.md) |
| Localization (12 key languages) | 7 of 12 present | ~52% (mean of the 12, measured) | 130–210 h for the target's set; +145–255 h for Hindi, Arabic, Indonesian, Vietnamese, Korean | [localization-parity.md](localization-parity.md) |
| Performance | ~80% | ~70% | 30–50 h | 24 MP GPU slider 3.9 ms, export 0.3 s (measured, [gpu-pipeline.md](gpu-pipeline.md)); 85k library opens in 1.7–4.7 s; 100k test pending |
| Stability | — | ~60% | 30–60 h | never-crash lints and guards workspace-wide, crash-tested journal, 2,561 tests; but CI runs tests only on FreeBSD, user reports keep finding bugs in ✅ areas |
| Platforms | macOS, Windows (x64 / x86 / ARM64), Linux (AppImage, deb, rpm, Flatpak, Nix), FreeBSD, web | ~60% | 25–45 h | macOS is where it is tested; Windows installer UI unverified on Windows (#79); web experimental (CPU only) |
| Ecosystem / plug-ins | ~25% | ~15% | 40–80 h + owner decision | no Lightroom SDK equivalent (export, publish, metadata plug-ins); beyond the target: JSON-lines control channel, MCP server with 28 tools + one per command, CLI |
| AI features | ~30% | ~20% | 120–220 h + model decisions | [AI](#ai) (overlaps the masking and Enhance rows; not added twice) |
## Features
Weights are a judgement of what Lightroom users spend their time on (library and develop dominate;
Classic output modules and video are used by few). Breadth and readiness per area are estimated
from the checklist sections and the deep-dive documents.
| Area | Weight | Breadth | Ready | Remaining | Notes |
|---|---:|---:|---:|---:|---|
| Import and library (import, folders, albums, smart albums, keywords, metadata, search, faces) | 15% | 90% | 80% | 25–45 h | checklist A–E 83–92%; robust journal; 85k-photo libraries |
| RAW decoding and camera coverage | 15% | 81% | 76% | 120–220 h | [raw-parity.md](raw-parity.md), measured model by model: 84% of photographers' cameras decode (use-weighted), × 0.9 for per-body bugs; CR3 variants, compressed ORF, HE NEF |
| Colour, camera profiles, render fidelity | 10% | 65% | 35% | 80–150 h | 4 bundled profiles vs Adobe's 1,500; per-file fits median ΔE ~5 vs the camera JPEG, ~10% far off; no fidelity suite ([raw-parity.md](raw-parity.md#colour)) |
| Global develop adjustments (light, colour, curves, grading, effects, detail) | 15% | 93% | 70% | 30–60 h | checklist F 91.7%; character tuned by eye |
| Optics, lens profiles, crop and geometry | 6% | 80% | 50% | 40–80 h | no lens database; crop / Upright complete |
| Masking | 8% | 67% | 45% | 60–110 h | checklist K 67.4%; AI masks heuristic or SAM 3 without mirror |
| Remove, heal, Enhance (denoise, Raw Details, Super Resolution, Lens Blur) | 7% | 45% | 30% | 70–130 h | checklist I 75%, P 0% |
| Presets, profiles, versions, history, sync | 5% | 95% | 85% | 8–15 h | |
| Export | 6% | 89% | 75% | 15–30 h | checklist S 88.9% |
| Merge and HDR | 3% | 85% | 60% | 20–35 h | merge 100%, HDR 70% (no HDR display) |
| Views, compare, zoom, culling | 5% | 90% | 70% | 15–30 h | zoom detail P0 gap |
| Classic output modules (Map, Book, Slideshow, Print, Web, publish, tethering) | 4% | 15% | 10% | 90–150 h | Classic extras 48% counts many small keys; the modules themselves are mostly ⬜ |
| Video | 1% | 0% | 0% | 25–45 h | catalogued only |
| **Weighted** | 100% | **~77%** | **~61%** (60.6%) | **600–1,100 h** | |
## AI
Lightroom 9.6 ships 37 on-device models (names listed from its `ModelZoo`), covering subject, sky,
portrait, skin and object selection with refinement, depth estimation, denoise, dust detection,
reflections removal, distraction / people detection, culling scores (eyes open, blur, aesthetics) and
search embeddings; generative remove runs in Adobe's cloud.
| Feature | LightCraft | Status |
|---|---|---|
| Subject / Sky / Background masks | classical heuristics; the file's own DNG semantic mattes | 🟡 |
| People (faces, body, hair, skin…) and Landscape masks | — | ⬜ |
| Object / Describe masks | SAM 3 in pure Rust (Metal / CPU); opt-in 3.4 GB download, no mirror configured | 🟡 |
| Depth range mask, Lens Blur | — | ⬜ |
| AI Denoise | Bayer only, pure-Rust CPU / GPU, user-installed weights | 🟡 |
| Raw Details, Super Resolution | — | ⬜ |
| Generative remove, distractions, reflections | — (generative is out of scope: cloud) | ⬜ |
| Dust detection | ✅ | ✅ |
| Faces / People | YuNet detection, SFace / AuraFace recognition (opt-in downloads), People view | ✅ (MVP, [faces.md](faces.md)) |
| Assisted culling | focus, bursts | 🟡 (no eyes-open / aesthetics scores) |
| Auto (tone), adaptive presets | Auto calibrated on Lightroom's Auto results (#628); no adaptive presets | 🟡 |
| Natural-language search | — | ⬜ |
**Blocked on a model strategy** (maintainer decision): licensable weights or our own training;
pure-Rust inference is proven (faces, SAM 3, denoise).
## Ready for real work, mainstream practitioner and essentials user
Three readiness numbers (craftrules `standards/progress-docs.md`). The full number is a weighted
sum over the dimensions with written weights. Mainstream and essentials take the weighted depth of
the areas their user touches, then apply written multiplicative discounts for what still stops real
work. Each has its own hours to ~95%, calibrated as in [How hours are calibrated](#how-hours-are-calibrated)
(essentials ⊂ mainstream ⊂ full):
| Audience | Ready | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates |
|---|---:|---:|---|
| Full target (ready for real work) | **~61%** | **1,000–1,800 h** (~70% parallelizes) | raw colour, lens and camera data; AI models; Classic output modules; localization; plug-in ecosystem |
| Mainstream practitioner | **~49%** | **450–840 h** (~60% parallelizes) | camera colour and render fidelity; CR3 / ORF / HE NEF; lens database; subject / sky masks; Lightroom XMP exchange; stability |
| Essentials user | **~64%** | **160–300 h** (~50% parallelizes) | default raw look for popular cameras; launch stability; basic-slider feel; opening CR3 / HEIC files people send |
### Full target (ready for real work): ~61%
Weighted sum over the dimensions of [By dimension](#by-dimension) (AI is left out because it
overlaps the masking and Enhance feature areas). RAW decoding and camera colour are their own rows,
valued from the model-by-model measurement in [raw-parity.md](raw-parity.md):
| Dimension | Weight | Ready |
|---|---:|---:|
| Features: the other 11 areas, weighted depth from [Features](#features) | 45% | 60.9% |
| RAW decoding and camera coverage | 9% | 76% (84% use-weighted × 0.9) |
| Camera colour and default rendering | 6% | 35% |
| UI/UX fidelity | 8% | 70% |
| File formats (non-raw) | 6% | 70% |
| Hardware | 3% | 40% |
| Localization | 3% | 52% |
| Performance | 6% | 70% |
| Stability | 8% | 60% |
| Platforms | 4% | 60% |
| Ecosystem / plug-ins | 2% | 15% |
| **Weighted sum** | 100% | **60.6% ≈ 61%** (range 56–66%) |
Mainstream comes out lower than full: its scope is the raw-develop core, where LightCraft is weakest
(camera colour, CR3 coverage), and its discounts are multiplicative, while the full sum is lifted by
strong library, presets, UI and format dimensions.
**Why the numbers moved with the RAW measurement:** decoding measured model by model against
Adobe's list is better than the earlier 50% estimate (84% of photographers' cameras decode, 76% after
a bug discount), colour is lower (35%, was 40%) and is now its own row. Net: full +2 points.
Mainstream now carries colour as a ×0.85 discount on top of the measured coverage (−2 points);
essentials replaces its guessed 45% raw look with 84% × 0.75 (+1 point).
### Discounts (evidence: open issues from users, 2026-10-10)
| Discount | Mainstream | Essentials | Evidence |
|---|---:|---:|---|
| Interaction fidelity / UI clarity | ×0.95 | ×0.95 | brush live preview gaps and feathering (#517, #518); crop artefacts and limits (#731, #742, #770, #771); Compare white-balance selector (#743–#745); low-res slider previews (#330); dialogs taller than the window (#781); mouse-wheel scroll (#714); 100% zoom capped (gap 4) |
| Stability on real machines | ×0.92 | ×0.92 | launch and quit crashes or silent startup failures (#250 macOS 12 Intel, #315 Windows Intel GPU, #431 Intel Mac, #260, #462, #783 Linux / Nouveau, #790 Windows installer); tests run in CI on FreeBSD only (gap 9) |
| File exchange with Lightroom users (mainstream) / opening files people send (essentials) | ×0.92 | ×0.95 | Adobe XMP sidecars change colours (#290), XMP CameraProfile and Upright ignored (#204, #205), catalog import fails (#599), same Light values render differently (#523, #209), no write-back to `.lrcat`; for casual users: CR3 beyond verified bodies, compressed ORF, HE NEF open as previews (#473, #485, #556), HEIC trouble (#693) |
| **Product** | **×0.804** | **×0.830** | |
### Mainstream practitioner: ~49%
A working photographer (wedding, portrait, events, landscape) shooting raw on one current camera,
weekly: import, cull, develop, a few masks, sync a look, export. Excluded: Classic output modules,
video, generative / cloud AI, plug-ins, tethering and other specialist hardware, languages other
than the user's own.
| Area | Weight | Depth |
|---|---:|---:|
| Import and library | 18% | 80% |
| Cull: views, compare, zoom, ratings | 12% | 70% |
| Raw decoding for their camera | 27% | 84% (measured use-weighted share whose camera fully works, [raw-parity.md](raw-parity.md#by-use-estimated)) |
| Global develop adjustments | 15% | 70% |
| Crop, geometry, lens corrections | 6% | 50% |
| Masking (manual, subject / sky; no generative) | 8% | 45% |
| Heal / remove (no generative), denoise | 5% | 40% |
| Presets, copy / paste / sync | 5% | 85% |
| Export | 4% | 75% |
| **Weighted depth** | 100% | **71.8%** |
Colour fidelity is a written discount, **×0.85**: most raws start near the camera's own look (median
ΔE ~5), about 10% far off (ΔE ~18), none calibrated to Adobe Standard, so a working photographer
corrects colour by hand (33 open colour issues). 71.8% × 0.804 × 0.85 = **~49%** (range 44–54%).
### Essentials user: ~64%
A casual photographer with default settings: import, look through, rate, fix a few photos with the
basic sliders, crop, apply a preset, undo, export JPEGs.
| Feature | Weight | Depth |
|---|---:|---:|
| Import photos | 15% | 80% |
| Browse grid and detail view | 10% | 85% |
| Rate and flag | 5% | 90% |
| Basic sliders (exposure, contrast, highlights, shadows, white balance, vibrance / saturation) | 22% | 70% (slider strength differs from Lightroom, #196, #521) |
| Auto | 5% | 65% (#318) |
| Crop and straighten | 10% | 80% |
| Presets and profiles | 8% | 80% |
| Undo and history | 5% | 90% |
| Their camera's raws: decode × default look | 10% | 63% (84% whose camera fully works × colour factor 0.75) |
| Export JPEG | 10% | 85% |
| **Weighted depth** | 100% | **77.4%** |
77.4% × 0.830 = **~64%** (range 59–69%).
### User evidence (GitHub issues, excluding the four maintainers)
- 324 issues from 159 users; 162 open. 8,719 stars, 2,698 forks (2026-10-10).
- Of the 162 open: **~92 core-path bugs** (33 colour / rendering, 16 decoding, ~36 UI / workflow, 7
launch / stability), ~11 developer / test infrastructure, **~59 feature requests or niche asks**
(plug-ins, mobile, sync servers, tablets, MIDI, geocoding, themes).
- Praise in issue text (love / amazing / great work / awesome): ~14 issues; "thank you" in 27.
**No explicit "switched from Lightroom" report** was found ("switched" matches 6 issues, none a
switch report).
- Reading: strong interest, but most open user issues are core-path, and raw colour dominates them,
so the mainstream number is held down by default rendering rather than missing features.
### Why the full number moved (55% → 46% → 59%)
The first figure (~55%) was the feature depth "pulled down" by an unwritten judgement. A later pass
applied the mainstream discounts to it (~46%). The standard defines the full number as a weighted
sum over the dimensions, so it is now that sum with the weights written above: ~59%. Method aligned
with the standard, no new evidence. The stage stays **alpha**.
## Stage
**Alpha.** Core workflows exist end to end (import, cull, develop, mask, export, catalog migration),
but ready-for-real-work is ~61%, below the ~75% beta bar, and the main file formats have blocking
gaps: Canon CR3 decodes from sensor data on three verified bodies only, compressed ORF and HE NEF
open as previews, and colour on every non-DNG raw is estimated rather than measured.
**Alpha gate:** all six core workflows (import, cull, develop, save and reopen, batch looks, export)
work end to end on macOS; see the table in [roadmap.md](roadmap.md#alpha-gate). The partial rows (CR3
variants, compressed ORF, HE NEF as previews; capped 100% zoom) degrade but don't block a workflow.
**To beta:** ~14 points of readiness, **~340–600 h**: the nine `B` gaps in [gaps.md](gaps.md)
(~230–430 h), plus burning down the ~92 open core-path user issues (40–80 h) and stability work
around them. Beta needs: CR3, ORF and
HE NEF decoding from sensor data; measured colour for the popular models and a fidelity suite with
scores; full-resolution zoom; Subject / Sky / People masks; a lens profile database for the
popular lenses; tests in CI on macOS, Windows and Linux.
## How hours are calibrated
Hours are Opus 5.5 agent wall-clock hours, one session working sequentially, including tests and
verification. Calibrated on this repository's history (git log and GitHub PR open-to-merge times):
- **Project pace:** first commit 2026-09-30; by 2026-10-10, 1,066 non-merge commits and 325 merged
PRs, commits in 159 distinct clock hours, with 4–6 parallel agents plus community contributors.
On 2026-10-02 the ROADMAP recorded ≈ 105–145 agent-hours spent; M0–M13 took ≈ 25 active hours with
parallel agents against an up-front estimate of 110–170 h.
- **UI and library rows:** a lead agent closed ≈ 45 checklist rows in ≈ 5 h (2026-10-01) and ≈ 60 in
≈ 12 h (2026-10-02): 6–12 minutes per small row.
- **Raw decoders:** RW2 in every format 6.5 h (#215), compressed RAF 8.6 h (#282), CR3 CRX 10 h
(#279), NEF lossy after split 4.7 h (#633), ORF 12.8 bpp 1.7 h (#651), HEIC 7 h (#609).
- **Large features:** AI RAW denoise 8.3 h (#384, 12.8k lines), SAM 3 masks 14.9 h (#162),
HDR editing and export 2.3 h (#646, on existing groundwork), contact-sheet PDF (#563), German UI
13.8 h (#265).
- PR open time includes queueing and review, so these are upper bounds per feature; the ranges add
a long-tail factor of 1.3–1.5× for verification against real files.
### Why the estimate went up
The previous estimate (2026-10-02, kept below) was ≈ 270–505 h to full parity. It counted checklist
rows only. New evidence since: the target's own lists (≈ 1,000 dedicated camera models, 3,635 lens
profiles, 37 AI models, 16 languages) measured from the installed bundle; per-maker verification
counts; that CI tests only FreeBSD; and the standard's added dimensions (localization, stability,
platforms, ecosystem). The raw-codec package it estimated at 40–80 h took roughly that and closed
most of its list; what remains is the data-heavy part (colour, lenses, models) it did not count.
## History of the numbers
| Date | Checklist (all / P0 / P1 / P2) | Ready for real work | Remaining to full parity | Source |
|---|---|---|---|---|
| 2026-10-10 (RAW) | 81.1% (unchanged) | ~61% full · ~49% mainstream · ~64% essentials | unchanged | RAW measured model by model against Adobe's list; RAW decode and colour as explicit rows |
| 2026-10-10 (final) | 81.1% (unchanged) | ~59% full (weighted sum) · ~51% mainstream · ~63% essentials | full 1,000–1,800 h · mainstream 450–840 h · essentials 160–300 h | method aligned with the standard |
| 2026-10-10 (later) | 81.1% (unchanged) | ~46% full · ~51% mainstream · ~63% essentials | 1,000–1,800 h | full × discounts (superseded) |
| 2026-10-10 | 81.1% / 98.0% / 95.1% / 46.9% (517 rows) | ~55% | 1,000–1,800 h | this re-measure |
| 2026-10-08 | 79.7% / 98.2% / 95.6% / 41.6% (509 rows) | 60–70% | — | ROADMAP *Where we stand* |
| 2026-10-02 | 75.6% | — | 270–505 h (cloud parity without AI / Classic: 130–255 h) | ROADMAP *Parity estimate* |
The 2026-10-08 assessment by dimension, kept for evidence: feature checklist 79.7%; RAW coverage
~55%; colour and image quality ~55–65%; AI and computational ~15–20%; workflow and library ~85%
(single machine); Classic modules ~30%; HDR and video ~25%; platform and robustness ~70%. By kind of
user: JPEG / DNG shooter ~85%; Nikon / Sony / Panasonic / older-Canon ~65%; Fujifilm ~65%; Canon
CR3 / Olympus compressed ~45%; Classic power user ~45%; relies on AI ~25%. Today's numbers per user:
JPEG / DNG ~75%; Sony, Panasonic, Fujifilm ~60%; Nikon ~55% (HE NEF); Canon CR3 ~40%; OM / Olympus
~30%; Classic power user ~40%; relies on AI ~20%.
The 2026-10-02 effort table, kept for calibration: remaining P0/P1 UI 5–10 h; raw codecs 40–80 h;
lens database 15–30 h; video 20–40 h; AI 80–150 h; HDR 15–25 h; Classic modules 60–100 h; smaller
P2 items 12–25 h; look tuning, performance, packaging, hardening 25–45 h.
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | minor | RAW measured model by model (raw-parity.md): RAW decoding (76%) and colour (35%) are explicit rows of the full sum (59% → 61%); mainstream uses the use-weighted 84% plus a ×0.85 colour discount (51% → 49%); essentials uses 84% × colour 0.75 (63% → 64%); beta ~14 points |
| 2026-10-10 | minor | Full number restored to an additive weighted sum over the dimensions (~59%; method aligned with the standard, no new evidence); hours to ~95% for each of the three audiences; beta distance ~16 points |
| 2026-10-10 | minor | Added mainstream practitioner (~51%) and essentials user (~63%) numbers; full ready re-derived from written weights × discounts (55% → 46%); user-issue evidence; beta hours 340–600 |
| 2026-10-10 | minor | Stage re-checked against the core-workflow alpha gate: passes, stays alpha |
| 2026-10-10 | major | Created per the progress-docs standard: full re-measure (checklist recount, installed Lightroom 9.6 bundle listing, code counts, catalogs, CI), feature areas with weights, dimensions, AI, stage, calibration; merged ROADMAP's *Where we stand* and *Parity estimate* |
+81
View File
@@ -0,0 +1,81 @@
# UI parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; shortcut notes moved here from the checklist) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
How LightCraft's interaction compares with Lightroom's: views, panels, tools and handles, modifier
keys, shortcuts, zoom, context menus and feel. Rows for individual menu items and shortcuts live in
[parity-checklist.md](parity-checklist.md) (sections Y and Z, Classic keys); this page is the
assessment and the notes that don't fit a row. Visual reference for agents: `plan/lightroom/`
(local, gitignored; `10-observed-ui.md` and screenshots).
## Measured counts (2026-10-10)
- 226 engine commands (`crates/engine/src/cmd/`, 30 modules) and 143 UI commands (`UI_COMMANDS` in
`crates/ui-egui/src/menus.rs`, 73 with a shortcut) plus 10 language commands; 23 secondary
shortcut bindings (`ALIASES`, `crates/ui-egui/src/shortcuts.rs`); a keymap editor.
- 122 develop controls plus 10 indexed templates (`crates/develop/src/controls.rs`).
- Checklist: menus 95.3% (86 in-scope rows), desktop shortcuts 94.4% (81 rows), Classic extras
48.2% (82 rows), measured by recounting [parity-checklist.md](parity-checklist.md).
- 31 panel modules (`crates/ui-egui/src/panels/`), 26 context-menu sites.
## Assessment by area
| Area | Target | LightCraft | Ready | Main gaps |
|---|---|---|---:|---|
| Layout and views | Lightroom: grid / detail / edit; Classic: Library, Develop, Map, Book, Slideshow, Print, Web modules, filmstrip, panels | Lightroom-style single window: Photo Grid, Square Grid, Detail, Compare, Survey (≤ 48), Before / After, People, quick slideshow, second window, filmstrip | 75% | no Classic module switcher (by design) or output modules; dark theme only |
| Develop panels and sliders | Light, Color, Effects, Detail, Optics, Geometry, Lens Blur, Calibration | every global slider; scrub, double-click reset, Alt-drag previews where implemented | 80% | Lens Blur, Calibration panel depth; slider feel (acceleration, fine Shift-drag) unmeasured |
| Crop, Upright, transform handles | handles, aspect lock, angle, overlays (O / ⇧O), guided Upright | ✅ all of them; overlay cycle on ⇧O | 85% | crop opacity of cut-out area (15.5) |
| Masking tools | brush (A / B, flow, density, auto mask, pressure), linear / radial, range masks, AI masks, pins | brush, linear, radial, colour / luminance range, add / subtract / intersect / invert, masks panel, pins | 60% | brush live preview (#517 / #518), no pen pressure, no depth range, AI masks, Feather / Edge controls (15.5) |
| Remove / heal | content-aware remove, heal, clone, visualize spots | heal, clone, auto source, visualize spots, red / pet eye | 65% | content-aware (patch synthesis) remove, generative remove, detect distractions |
| Zoom and navigation | Fit / Fill / 1:1 / 2:1 … 11:1, Navigator, spacebar pan | Fit to 800%, pinch zoom, pan, Navigator-like | 60% | **original-pixel detail at 100% (preview capped at 2,560 px; P0 gap LR-VIEW-ZOOM)** |
| Library culling and metadata | ratings, flags, labels with keys, painter, keywording, metadata panel, filter bar | ratings / flags / labels and advance, keyword list and sets, keywording box, metadata fields, smart albums, filter bar | 85% | painter tool, quick collection, some Classic keys |
| Shortcuts | Lightroom desktop and Classic keymaps | Lightroom-desktop keymap with Classic additions, editable | 85% | deliberate differences below; no Classic keymap layer |
| Context menus | everywhere | 26 sites (grid, filmstrip, albums, folders, keywords, masks, presets…) | 70% | unaudited against Lightroom's menus item by item |
| Text fields | native editing behaviour | custom text field (LR-BEHAV-TEXTFIELD) | 70% | IME and selection edge cases |
| Accessibility | VoiceOver / Narrator, keyboard navigation | AccessKit: sliders, buttons, dropdowns, section headers announce | 30% | canvas tools pointer-only; not audited with a screen reader |
| Feel and responsiveness | GPU-interactive sliders (15.3) | ≤ 16 ms slider budget on GPU; background renders | 75% | colour NR at half resolution, 100k-photo grid test |
| **UI/UX overall** | | | **~70%** | estimated, weighted by use (develop and library 60%, tools 25%, rest 15%) |
Remaining: **40–70 h** (zoom detail 8–15 h, brush and masking feel 8–12 h, accessibility audit 10–20
h, Classic keymap layer 4–8 h, context-menu audit 4–8 h, text-field and IME polish 4–8 h). Output
modules and AI tools are counted with their features in [target-app-parity.md](target-app-parity.md).
## Shortcuts
Compared `plan/lightroom/06-shortcuts.md` (desktop part) with our bindings: command specs in `crates/engine/src/cmd/`,
`UI_COMMANDS` in `crates/ui-egui/src/menus.rs` and secondary bindings (`ALIASES`) in `crates/ui-egui/src/shortcuts.rs`.
`no_conflicting_bindings` (same file) fails when one key fires two actions.
**Fixed (M16.1):** added Lightroom-desktop keys as secondary bindings for existing commands — ⌘D Select None, ⇧E
Export dialog, Space Toggle zoom, ⇧M Create Version, ⇧X Reject + advance, ⇧U Unflag + advance. `⇧Y` fired both
Before/After Split and the History panel; History lost the binding. `W` and `⇧⌘I` also fired the engine command
under the UI command that wraps it (a no-op error); the UI command now wins.
**Deliberate differences (our key → Lightroom desktop key)** — each is a conflict with another binding we have:
| Action | Ours | Lightroom desktop | Why |
|---|---|---|---|
| Pick flag | P | Z | Z = toggle zoom (Classic convention); P is the Classic pick key |
| Photos panel (left) | ⌘⇧L | P | P = pick |
| Expand/collapse edit sections | ⌘⌥1–5 | ⌘1–6 | ⌘0 = Zoom to Fit, ⌘1 = Zoom 100 %; Geometry lives in the Crop panel |
| Histogram | ⌘⇧H | ⌘0 | ⌘0 = Zoom to Fit |
| Square Grid | ⇧G | (none; ⇧G = Guided Upright) | Guided Upright is a button in the Crop panel |
| Export dialog | ⌘⇧E (+ ⇧E) | ⇧E | ⌘⇧E is "Edit in Photoshop" there; no external-editor command yet |
| Crop overlay cycle | ⇧O | O | O = mask overlay; ⇧O (mask colour / overlay orientation) unused otherwise |
| Create Version | ⌘⇧S (+ ⇧M) | ⇧M (Windows: Ctrl+⇧S) | — |
| Select None | ⌘⇧A (+ ⌘D) | ⌘D | — |
**Library culling (KEYC-RATING):** `0–5`, `6–9` and `P/X/U` reach egui on macOS even when displayed in the native menu (adapted from PR #261; issue #283). `Shift+0–9` applies and advances once; `Shift+P` picks and advances in Photo Grid / Square Grid and retains Presets elsewhere. See [library shortcuts](library-shortcuts.md) for the verified Classic mapping and regression coverage. Remaining Classic gaps: rating `[` / `]`, flag cycling and filter-bar keys.
**Still missing / broken:**
- No command yet: F1 help (verify the rest of the old list: full screen, settings, stacks,
visualize spots and merges have commands now).
- `H` opens Remove; Lightroom also uses it (Classic) to hide pins — pins toggle from View → Show Mask Pins.
- ⌘M / ⌘H / ⌘Q / ⌘W rely on the platform window defaults (unverified).
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created: measured command and shortcut counts, assessment by area, estimates; moved the shortcut conflicts section here from the checklist |
+77 -67
View File
@@ -1,6 +1,6 @@
# What's new in LightCraft
## October 2026
## 2026-10-10
### Activity stack
- Long-running tasks show in one place, top left under the top bar, as in Lightroom Classic (issue #345): imports and
@@ -11,6 +11,8 @@
- Quitting while a task that can be stopped is running asks first ("Quit Anyway" stops it).
- Agents list and stop tasks with `activity.list` and `activity.cancel`; `ui.inspect` reports them as `activity`.
## 2026-10-09
### Smart album rules
- The rule editor's field menu is grouped: Rating, Pick Flag, Color Label and Any Searchable Text at the top, then
submenus for Source, File, Date, Keywords & People, Description, Camera Info, Location, Size, Develop and Assisted
@@ -129,6 +131,8 @@
next to it while you rotate (issue #534). For an exact angle, type it in the new Angle field under Straighten and press Return
(Esc keeps the old angle; a decimal comma works too), or click the Straighten value; hovering any slider's value now says it can be typed.
## 2026-10-08
### Albums tree
- Album folders fold with the same disclosure triangle as Local, By Date, Folders and Keywords.
- Right-click a folder ▸ New ▸ Create Album… / Create Smart Album… / Create Smart Album from Filter… / Create Folder…
@@ -158,6 +162,60 @@
press the new keys (Esc cancels), × removes it, ↺ restores the original, Reset All undoes every change. A key that
belonged to another command moves to the new one. Menus show the new keys; agents use `app.setShortcut`.
### Formats
- HEIC / HEIF photos (iPhone and Mac) open now: the optional `lightcraft-heif` crate (heic-rs, pure Rust) behind
codecs' `heif` feature — 8- and 10-bit, alpha, grid tiles, the container's rotation/mirror/crop, ICC, EXIF and XMP.
Off by default (HEVC patents are the distributor's call, same as PhotoCraft); official builds pass `--features heif`.
- HEIC colours now match libheif to within one code value (they were up to ~10 off): the HEVC stream's own
full-range/matrix signalling is honoured (iPhone photos are full range), chroma is upsampled like libheif, grids
take their tiles' ICC profile, and `imir` mirrors the way libheif writes it. Importing a HEIC reads its size from
the container instead of decoding it; small previews use the file's embedded thumbnail. The release packages
(macOS, Windows, Linux, FreeBSD, Nix) now really are built with HEIC support; a build without it reports
"HEIC/HEIF support isn't included in this build" for each `.heic`/`.heif` at import.
### Editing
- The Tint slider works the right way round (issues #188, #321): left adds green, right adds magenta, as its track
shows and as in Lightroom, and Tint values in Lightroom XMP sidecars now render as they do there. A custom Tint
saved in an earlier version now shifts the other way; set it again (or re-run Auto / the white-balance picker).
- White balance on DNGs (and other raws with a colour matrix) re-develops the photo for the new white through the
camera's own colour matrices, as Lightroom does, instead of shifting the colours of the as-shot rendering: a grey
lit by the chosen white comes out grey and saturated colours move as the camera records them. The eyedropper and
Auto use the same model. Custom white balances on these photos render slightly differently than before.
- Crop (issue #295): a Lock toggle keeps the aspect ratio on every handle, Custom takes your own ratio (Apply), and
dragging a handle into the image edge stops there instead of pushing the crop out of shape.
### Library and views
- Trackpads: pinch to zoom around the pointer and scroll with two fingers to pan the photo; panning keeps the photo
inside the view. A plain mouse wheel over a zoomed photo pans it too.
- A Folders section in the sidebar lists the folders your photos were imported from; choose one to see its photos.
- Select All and multi-selection show every selected photo in the grid and filmstrip, not only the active one
(issues #187, #298). Importing files that are in Recently Deleted asks whether to leave them there, restore them
(with their edits) or import them as new; the trash view's Photo menu has Empty Recently Deleted.
- The Import Photos review opens bigger and can be resized; its photo grid fills it (issue #337). Shift-click checks
or unchecks a range of photos (issue #338).
- When a folder holds several file types, the Import Photos review has a toggle per type (`ARW · 120`, `JPG · 120`):
import only the raws and leave the JPEGs beside them (issue #344).
### Languages
- The interface is available in Spanish (issue #371), German and Russian (Edit ▸ Language), alongside English,
Chinese (Simplified and Traditional), Japanese and Brazilian Portuguese.
### Editing
- Type an exact value into any slider (issue #322): click the number next to its name, type (`1.5`, `-20`, `5600`)
and press Return; Esc keeps the old value.
### Editing
- The eye on the Light, Color and Detail section headers now hides their adjustments, as it already did for Effects,
Optics, Geometry and Calibration (issue #316).
### Library
- Choosing a date under By Date or a keyword under Keywords shows those photos from All Photos, as their counts
promise, instead of filtering whatever album or folder was open, which often showed nothing (issue #341).
)
)
## 2026-10-07
### RAW decoding
- Olympus ORF raws get the starting look fitted to the camera's own JPEG too, instead of opening flat and grey (the
E-1, E-400 and XZ-2 corpus files: all accepted), with white balance relative to the as-shot look as for the other
@@ -214,72 +272,7 @@
existing LightCraft edits are preserved by default. Source settings/history are archived, unsupported
fields are reported, and the original Lightroom database stays read-only. Rendering is approximate.
### Formats
- HEIC / HEIF photos (iPhone and Mac) open now: the optional `lightcraft-heif` crate (heic-rs, pure Rust) behind
codecs' `heif` feature — 8- and 10-bit, alpha, grid tiles, the container's rotation/mirror/crop, ICC, EXIF and XMP.
Off by default (HEVC patents are the distributor's call, same as PhotoCraft); official builds pass `--features heif`.
- HEIC colours now match libheif to within one code value (they were up to ~10 off): the HEVC stream's own
full-range/matrix signalling is honoured (iPhone photos are full range), chroma is upsampled like libheif, grids
take their tiles' ICC profile, and `imir` mirrors the way libheif writes it. Importing a HEIC reads its size from
the container instead of decoding it; small previews use the file's embedded thumbnail. The release packages
(macOS, Windows, Linux, FreeBSD, Nix) now really are built with HEIC support; a build without it reports
"HEIC/HEIF support isn't included in this build" for each `.heic`/`.heif` at import.
### Presets and profiles
- Import presets from other editors: XMP presets, classic `.lrtemplate` files, "DNG presets" from mobile apps and `.zip`
bundles of any of these — whole folders at once, grouped by pack. Masks inside presets come along.
- Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders
with a counterpart here come along, the rest is listed.
- 23 new built-in presets: Portrait, Landscape, Urban, Food, Seasons, Vintage and B&W toners.
- Importing XMP presets no longer lists bookkeeping fields (`Cluster`, `SortName`, `SupportsAmount2`, the as-shot
white, empty Point Color slots…) as settings that couldn't be carried over.
- A preset whose lens-profile switch is off no longer turns off the lens corrections built into a DNG (iPhone ProRAW
and other files with embedded distortion / vignetting corrections), matching what the preset does elsewhere.
- XMP presets apply their red / green / blue curves only when they also have the master curve and all three channel
curves, as Lightroom does: a preset with just one channel curve (or no master curve) leaves the channels alone.
- Imported `.cube` LUT profiles appear in the Profile menu and the profile browser, grouped by their folder, and stay
favourites across restarts (issue #328).
### Editing
- The Tint slider works the right way round (issues #188, #321): left adds green, right adds magenta, as its track
shows and as in Lightroom, and Tint values in Lightroom XMP sidecars now render as they do there. A custom Tint
saved in an earlier version now shifts the other way; set it again (or re-run Auto / the white-balance picker).
- White balance on DNGs (and other raws with a colour matrix) re-develops the photo for the new white through the
camera's own colour matrices, as Lightroom does, instead of shifting the colours of the as-shot rendering: a grey
lit by the chosen white comes out grey and saturated colours move as the camera records them. The eyedropper and
Auto use the same model. Custom white balances on these photos render slightly differently than before.
- Crop (issue #295): a Lock toggle keeps the aspect ratio on every handle, Custom takes your own ratio (Apply), and
dragging a handle into the image edge stops there instead of pushing the crop out of shape.
### Library and views
- Trackpads: pinch to zoom around the pointer and scroll with two fingers to pan the photo; panning keeps the photo
inside the view. A plain mouse wheel over a zoomed photo pans it too.
- A Folders section in the sidebar lists the folders your photos were imported from; choose one to see its photos.
- Select All and multi-selection show every selected photo in the grid and filmstrip, not only the active one
(issues #187, #298). Importing files that are in Recently Deleted asks whether to leave them there, restore them
(with their edits) or import them as new; the trash view's Photo menu has Empty Recently Deleted.
- The Import Photos review opens bigger and can be resized; its photo grid fills it (issue #337). Shift-click checks
or unchecks a range of photos (issue #338).
- When a folder holds several file types, the Import Photos review has a toggle per type (`ARW · 120`, `JPG · 120`):
import only the raws and leave the JPEGs beside them (issue #344).
### Languages
- The interface is available in Spanish (issue #371), German and Russian (Edit ▸ Language), alongside English,
Chinese (Simplified and Traditional), Japanese and Brazilian Portuguese.
### Editing
- Type an exact value into any slider (issue #322): click the number next to its name, type (`1.5`, `-20`, `5600`)
and press Return; Esc keeps the old value.
### Editing
- The eye on the Light, Color and Detail section headers now hides their adjustments, as it already did for Effects,
Optics, Geometry and Calibration (issue #316).
### Library
- Choosing a date under By Date or a keyword under Keywords shows those photos from All Photos, as their counts
promise, instead of filtering whatever album or folder was open, which often showed nothing (issue #341).
)
)
## 2026-10-05
### Reliability
- The Windows installer asks where to install LightCraft (Program Files by default; upgrades keep the folder you
@@ -377,6 +370,23 @@
library) are written atomically and saved as soon as you open another library, not only at quit. Quitting while
changes couldn't be saved tries once more, then asks: Try Saving Again, Quit Anyway or Cancel.
## 2026-10-02
### Presets and profiles
- Import presets from other editors: XMP presets, classic `.lrtemplate` files, "DNG presets" from mobile apps and `.zip`
bundles of any of these — whole folders at once, grouped by pack. Masks inside presets come along.
- Luminar looks: `.lmp` files and `.mplumpack` collections import as presets (grouped by collection); the sliders
with a counterpart here come along, the rest is listed.
- 23 new built-in presets: Portrait, Landscape, Urban, Food, Seasons, Vintage and B&W toners.
- Importing XMP presets no longer lists bookkeeping fields (`Cluster`, `SortName`, `SupportsAmount2`, the as-shot
white, empty Point Color slots…) as settings that couldn't be carried over.
- A preset whose lens-profile switch is off no longer turns off the lens corrections built into a DNG (iPhone ProRAW
and other files with embedded distortion / vignetting corrections), matching what the preset does elsewhere.
- XMP presets apply their red / green / blue curves only when they also have the master curve and all three channel
curves, as Lightroom does: a preset with just one channel curve (or no master curve) leaves the channels alone.
- Imported `.cube` LUT profiles appear in the Profile menu and the profile browser, grouped by their folder, and stay
favourites across restarts (issue #328).
### Library
- Photos in Recently Deleted can be restored from the app: right-click ▸ Restore (or Delete Permanently), also in the
Photo menu. The filmstrip has the photo context menu too. Adding a file again that is in Recently Deleted no
+1 -1
View File
@@ -75,7 +75,7 @@ have none. So saving one photo never overwrites the other's metadata (`Session::
LightCraft reads face, pet, focus and barcode regions in the Metadata Working Group's region schema
(`mwg-rs:Regions`, `http://www.metadataworkinggroup.com/schemas/regions/`), as Lightroom, digiKam, Picasa and others
write them, from sidecars and from XMP embedded in the file. Named faces become people in the People view
(LR-LIB-PEOPLE in [`parity.md`](parity.md)), and every region is drawn as a box in the loupe.
(LR-LIB-PEOPLE in [`parity-checklist.md`](parity-checklist.md)), and every region is drawn as a box in the loupe.
- **Read only.** LightCraft never writes `mwg-rs:Regions`; saving a sidecar keeps another application's regions byte
for byte. Removing or resizing a box in the loupe changes the library only.
+1 -1
View File
@@ -27,7 +27,7 @@ commands:
pack square PNGs (<= 256 px) into a Windows .ico (see packaging/icons.sh)
layers enforce the crate dependency layering (plan/architecture.md §3)
parity [--write]
check docs/parity.md (every cmd:/ctl: id and path it cites exists) and print the
check docs/parity-checklist.md (every cmd:/ctl: id and path it cites exists) and print the
Lightroom parity summary; --write refreshes the summary table in the document
wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates (+ the web app)
web [--serve [port]] [--dev]
+2 -2
View File
@@ -1,4 +1,4 @@
//! `cargo xtask parity`: the Lightroom parity tracker (`docs/parity.md`).
//! `cargo xtask parity`: the Lightroom parity tracker (`docs/parity-checklist.md`).
//!
//! - **Reference check** (in `ci`): every `` `cmd:<id>` `` must be a registered command (engine command specs, as
//! listed by `lightcraft-cli commands --json`, or a UI command from `UI_COMMANDS`), every `` `ctl:<id>` `` a develop
@@ -10,7 +10,7 @@
use std::collections::{BTreeSet, HashSet};
use std::path::Path;
pub const DOC: &str = "docs/parity.md";
pub const DOC: &str = "docs/parity-checklist.md";
const BEGIN: &str = "<!-- parity:summary -->";
const END: &str = "<!-- /parity:summary -->";