diff --git a/AGENTS.md b/AGENTS.md index 7b1bce3a4..1ac827152 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,27 +9,55 @@ LightCraft is a clean-room, open-source, pure-Rust photo library + non-destructi `plan/` is gitignored (local-only). +**Resuming after a crash / another session:** check `git status` on main, `git worktree list`, and each worktree's +`git log main..HEAD` + `git status` for unmerged commits or uncommitted work before starting anything new. Commit small +and often so a crash loses minutes, not hours. + ## Non-negotiables - **Clean-room.** Never read/disassemble anything inside Adobe app bundles (names/listings only). Never copy Adobe icons, presets, profiles (DCP), lens profiles (LCP), camera matrices, fonts. Observation of the installed Lightroom is read-only (it syncs the user's personal library: never import/edit/rate/delete there). Never copy GPL/LGPL/AGPL code (darktable, RawTherapee, ART, LibRaw, rawspeed, rawloader, rawler, lensfun, dcraw-derived GPL code…). - **Pure Rust** in the product. No C/C++ dependencies. - **Layering** (`plan/architecture.md` §3, enforced by `cargo xtask layers`): nothing below L5 depends on egui/eframe/winit/rfd. - **Everything is a command** (`crates/engine`): id, label, menu path, shortcut, params, enabled(), run(). UI, CLI, control channel and MCP all dispatch by id. Every slider is a `develop` control spec. - **Resolution independence:** settings use normalized image coordinates and relative radii; previews and exports must match. -- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, layers, wasm). +- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, layers, assets, wasm). - **Commits:** one task id per commit (`M2.3: local Laplacian highlights/shadows`). Only green states. End messages with the attribution line required by the environment. ## Assets: icons, images, fonts (ABSOLUTE RULE — never violate) - **Never use any iconography, image, artwork, font, sound or other asset from Adobe products** (no Lightroom/Creative Cloud icons, no screenshots, no presets/profiles/LUTs, no UI bitmaps — not even as a temporary placeholder or "reference copy"). Observing Adobe's UI to imitate *layout and behaviour* is allowed; copying or tracing its assets is not. +- **This includes Adobe's open-licensed assets**: no Source Sans/Serif/Code or Source Han fonts, no Adobe Fonts, no + Adobe-published icon sets, sample photos, colour profiles or LUTs — even when OFL/MIT. The UI font is Inter (OFL). - Every asset in the repository must be one of: **our own original work** (e.g. icons drawn in code as vectors, procedurally generated demo photos), **public domain / CC0**, **Creative Commons** (CC-BY / CC-BY-SA with attribution honoured), **OFL** (fonts), or **permissive open-source** (MIT/Apache-2.0/BSD/ISC) — or contributed by a person who created the asset and licenses it openly. - **Every asset must have an entry in `assets/ATTRIBUTION.md`** (path, title, author/creator, source URL or "original work", licence, date added, modifications) and its licence text when required (e.g. `assets/fonts/OFL-*.txt`). Add the entry in the same commit as the asset. Assets without an attribution entry must not be committed. - Icons drawn in code (e.g. `crates/ui-egui/src/icons.rs`) are original work and are recorded in `assets/ATTRIBUTION.md` as such; do not trace them from Adobe icons. - Demo/test images: generated procedurally by `lightcraft-scenes`, or CC0 downloads kept in the gitignored `corpus/` with their source recorded. Screenshots of Adobe apps live only in the gitignored `plan/` and are never committed or published. +- **Enforced:** `cargo xtask assets` (in `ci`) fails when an image/icon/font/sound/video/raw/ICC/XMP file is not matched + by a path pattern in the first column of `assets/ATTRIBUTION.md`, when a referenced licence file is missing, when a + file name suggests Adobe material, or when an Adobe profile/template format (`.dcp`, `.lcp`, `.lrtemplate`, …) appears. + Never weaken this check to make a commit pass — fix the attribution or remove the asset. - When in doubt about an asset's licence: don't use it. ## Running and looking at the app - `cargo run --release -p lightcraft -- --control 7980` opens the desktop app with the JSON-lines control server (see `docs/control-protocol.md`). - For UI work, **look at the result**: drive via the control channel and take `ui.screenshot`, compare with `plan/lightroom/screenshots/`. -- MCP: `lightcraft-cli mcp` (see `docs/mcp.md`). +- MCP: `lightcraft-cli mcp` (headless, `--demo` for the procedural library) or `lightcraft-cli mcp --connect` (drives + the running app). See `docs/mcp.md`. Quick non-UI checks: `lightcraft-cli render in.jpg -o out.jpg --set light.exposure=1`. +- Export goes through `lightcraft_engine::export` (one encoder for app, CLI, MCP and web); UI-only commands live in + `crates/ui-egui/src/menus.rs`. - Shell gotcha: `mv`/`cp` are aliased interactive here — use `/bin/mv -f` / `/bin/cp -f`. - Parallel agents: separate git worktrees and `CARGO_TARGET_DIR=target/agent-`; keep every `Cargo.toml` valid at all times (the `crates/*` glob means one broken manifest breaks everyone). - Test corpora: `cargo xtask corpus --download` into `corpus/` (gitignored, CC0 only). Never commit media. + +## Testing & performance (do this often) +- Unit/property tests next to the code; end-to-end tests drive real binaries (`crates/mcp/tests/e2e.rs`, + `apps/lightcraft-cli/tests/`). New features need at least one test that would fail without them. +- **Run the app after every user-visible change**: launch with `--control 7980`, drive it with a JSON-lines script + (`docs/showcase/run.py file.jsonl`), take `ui.screenshot`, and look at it. Check `ui.inspect` → `perf`. +- **Measure, don't guess**: `LIGHTCRAFT_PROFILE=1` prints per-stage pipeline timings to stderr; time CLI renders + with `/usr/bin/time`. Record numbers in `plan/STATUS.md` → Metrics. Budgets: slider update ≤ 16 ms (draft) / loupe + ≤ 60 ms on ~2.5 MP; export ≤ 1 s per 24 MP JPEG. +- Never commit media: test images are procedural (`lightcraft-scenes`) or CC0 downloads in the gitignored `corpus/`. + +## Map of the code +`geom`, `color`, `raster`, `tiff` (L0) → `raw`, `codecs`, `meta`, `develop` (L1) → `pipeline` → `catalog` → `engine` +→ `ui-egui`, `mcp` (L5) → apps `lightcraft` (desktop), `lightcraft-cli` (render/commands/MCP). `scenes` generates demo +photos. `xtask` = tooling (`ci`, `layers`, `assets`, `wasm`, `corpus`, `stats`). diff --git a/CLAUDE.md b/CLAUDE.md index 7b1bce3a4..1ac827152 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,27 +9,55 @@ LightCraft is a clean-room, open-source, pure-Rust photo library + non-destructi `plan/` is gitignored (local-only). +**Resuming after a crash / another session:** check `git status` on main, `git worktree list`, and each worktree's +`git log main..HEAD` + `git status` for unmerged commits or uncommitted work before starting anything new. Commit small +and often so a crash loses minutes, not hours. + ## Non-negotiables - **Clean-room.** Never read/disassemble anything inside Adobe app bundles (names/listings only). Never copy Adobe icons, presets, profiles (DCP), lens profiles (LCP), camera matrices, fonts. Observation of the installed Lightroom is read-only (it syncs the user's personal library: never import/edit/rate/delete there). Never copy GPL/LGPL/AGPL code (darktable, RawTherapee, ART, LibRaw, rawspeed, rawloader, rawler, lensfun, dcraw-derived GPL code…). - **Pure Rust** in the product. No C/C++ dependencies. - **Layering** (`plan/architecture.md` §3, enforced by `cargo xtask layers`): nothing below L5 depends on egui/eframe/winit/rfd. - **Everything is a command** (`crates/engine`): id, label, menu path, shortcut, params, enabled(), run(). UI, CLI, control channel and MCP all dispatch by id. Every slider is a `develop` control spec. - **Resolution independence:** settings use normalized image coordinates and relative radii; previews and exports must match. -- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, layers, wasm). +- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, layers, assets, wasm). - **Commits:** one task id per commit (`M2.3: local Laplacian highlights/shadows`). Only green states. End messages with the attribution line required by the environment. ## Assets: icons, images, fonts (ABSOLUTE RULE — never violate) - **Never use any iconography, image, artwork, font, sound or other asset from Adobe products** (no Lightroom/Creative Cloud icons, no screenshots, no presets/profiles/LUTs, no UI bitmaps — not even as a temporary placeholder or "reference copy"). Observing Adobe's UI to imitate *layout and behaviour* is allowed; copying or tracing its assets is not. +- **This includes Adobe's open-licensed assets**: no Source Sans/Serif/Code or Source Han fonts, no Adobe Fonts, no + Adobe-published icon sets, sample photos, colour profiles or LUTs — even when OFL/MIT. The UI font is Inter (OFL). - Every asset in the repository must be one of: **our own original work** (e.g. icons drawn in code as vectors, procedurally generated demo photos), **public domain / CC0**, **Creative Commons** (CC-BY / CC-BY-SA with attribution honoured), **OFL** (fonts), or **permissive open-source** (MIT/Apache-2.0/BSD/ISC) — or contributed by a person who created the asset and licenses it openly. - **Every asset must have an entry in `assets/ATTRIBUTION.md`** (path, title, author/creator, source URL or "original work", licence, date added, modifications) and its licence text when required (e.g. `assets/fonts/OFL-*.txt`). Add the entry in the same commit as the asset. Assets without an attribution entry must not be committed. - Icons drawn in code (e.g. `crates/ui-egui/src/icons.rs`) are original work and are recorded in `assets/ATTRIBUTION.md` as such; do not trace them from Adobe icons. - Demo/test images: generated procedurally by `lightcraft-scenes`, or CC0 downloads kept in the gitignored `corpus/` with their source recorded. Screenshots of Adobe apps live only in the gitignored `plan/` and are never committed or published. +- **Enforced:** `cargo xtask assets` (in `ci`) fails when an image/icon/font/sound/video/raw/ICC/XMP file is not matched + by a path pattern in the first column of `assets/ATTRIBUTION.md`, when a referenced licence file is missing, when a + file name suggests Adobe material, or when an Adobe profile/template format (`.dcp`, `.lcp`, `.lrtemplate`, …) appears. + Never weaken this check to make a commit pass — fix the attribution or remove the asset. - When in doubt about an asset's licence: don't use it. ## Running and looking at the app - `cargo run --release -p lightcraft -- --control 7980` opens the desktop app with the JSON-lines control server (see `docs/control-protocol.md`). - For UI work, **look at the result**: drive via the control channel and take `ui.screenshot`, compare with `plan/lightroom/screenshots/`. -- MCP: `lightcraft-cli mcp` (see `docs/mcp.md`). +- MCP: `lightcraft-cli mcp` (headless, `--demo` for the procedural library) or `lightcraft-cli mcp --connect` (drives + the running app). See `docs/mcp.md`. Quick non-UI checks: `lightcraft-cli render in.jpg -o out.jpg --set light.exposure=1`. +- Export goes through `lightcraft_engine::export` (one encoder for app, CLI, MCP and web); UI-only commands live in + `crates/ui-egui/src/menus.rs`. - Shell gotcha: `mv`/`cp` are aliased interactive here — use `/bin/mv -f` / `/bin/cp -f`. - Parallel agents: separate git worktrees and `CARGO_TARGET_DIR=target/agent-`; keep every `Cargo.toml` valid at all times (the `crates/*` glob means one broken manifest breaks everyone). - Test corpora: `cargo xtask corpus --download` into `corpus/` (gitignored, CC0 only). Never commit media. + +## Testing & performance (do this often) +- Unit/property tests next to the code; end-to-end tests drive real binaries (`crates/mcp/tests/e2e.rs`, + `apps/lightcraft-cli/tests/`). New features need at least one test that would fail without them. +- **Run the app after every user-visible change**: launch with `--control 7980`, drive it with a JSON-lines script + (`docs/showcase/run.py file.jsonl`), take `ui.screenshot`, and look at it. Check `ui.inspect` → `perf`. +- **Measure, don't guess**: `LIGHTCRAFT_PROFILE=1` prints per-stage pipeline timings to stderr; time CLI renders + with `/usr/bin/time`. Record numbers in `plan/STATUS.md` → Metrics. Budgets: slider update ≤ 16 ms (draft) / loupe + ≤ 60 ms on ~2.5 MP; export ≤ 1 s per 24 MP JPEG. +- Never commit media: test images are procedural (`lightcraft-scenes`) or CC0 downloads in the gitignored `corpus/`. + +## Map of the code +`geom`, `color`, `raster`, `tiff` (L0) → `raw`, `codecs`, `meta`, `develop` (L1) → `pipeline` → `catalog` → `engine` +→ `ui-egui`, `mcp` (L5) → apps `lightcraft` (desktop), `lightcraft-cli` (render/commands/MCP). `scenes` generates demo +photos. `xtask` = tooling (`ci`, `layers`, `assets`, `wasm`, `corpus`, `stats`). diff --git a/README.md b/README.md index 7fa919a42..392d1b3e3 100644 --- a/README.md +++ b/README.md @@ -174,12 +174,23 @@ lightcraft --control 7980 ~/Pictures/trip {"method": "ui.screenshot", "params": {"path": "after.png"}} ``` -- **90 engine commands** and **48 UI commands** — list them all with `engine.commands`, read every slider's range, +- **91 engine commands** and **48 UI commands** — list them all with `engine.commands`, read every slider's range, default and current value with `develop.controls`. +- **MCP server** — `lightcraft-cli mcp` gives Claude (or any MCP client) ~100 tools: import, query, develop, mask, + render (returned as an image), export — headless, or attached to the running app with screenshots, clicks and + gestures. See [docs/mcp.md](docs/mcp.md). + + ```sh + cargo build --release -p lightcraft-cli + claude mcp add lightcraft -- "$PWD/target/release/lightcraft-cli" mcp ~/Pictures/shoot # headless + claude mcp add lightcraft-app -- "$PWD/target/release/lightcraft-cli" mcp --connect 127.0.0.1:7980 # live app + ``` +- **Scriptable CLI** — `lightcraft-cli render in.dng -o out.jpg --set light.exposure=0.7 --preset …`. - **Undo for everything**, including agent actions: a slider drag (or a scripted burst of updates) is one undo step. - **Every widget is addressable** (`ui.widgets`) and clickable by name, so agents can operate the real UI, not a side door. - The screenshots in this README were produced by [`docs/showcase/`](docs/showcase/) scripts, end to end. + Protocol reference: [docs/control-protocol.md](docs/control-protocol.md).
@@ -208,12 +219,14 @@ LightCraft is young and moving fast — see the [roadmap](ROADMAP.md) for estima | Light, Color, Effects, Tone Curve, Color Mixer, Color Grading, B&W | ✅ | | Masking: brush, linear, radial, luminance/colour range, add/subtract/intersect | ✅ (AI subject/sky use classical heuristics for now) | | Crop, straighten, flip, rotate, aspect ratios, overlays | ✅ | -| Presets, versions, history, copy/paste/sync settings | ✅ | +| Profiles (Color, Neutral, Vivid, Landscape, Portrait, Monochrome — our own looks), presets, versions, history, copy/paste/sync settings | ✅ | | Control channel + every widget addressable | ✅ | -| RAW: DNG, CR2 | ✅ · NEF, ARW, CR3, RAF, ORF, RW2… 🚧 | -| Detail (sharpening ✅, noise reduction 🚧), Optics, Geometry/Upright | 🚧 | -| Remove / Heal / Clone, Red Eye | 🚧 (spots are recorded; rendering lands in M8) | -| Export dialog, MCP server, CLI, GPU pipeline, web build | 🚧 | +| RAW: DNG, CR2, ARW, NEF (uncompressed) | ✅ · compressed NEF, CR3, RAF, ORF, RW2, PEF… 🚧 | +| Detail: sharpening, luminance + colour noise reduction | ✅ · AI Denoise, Super Resolution ⬜ | +| Remove / Heal / Clone spots (auto source) | ✅ · content-aware fill (PatchMatch), Red Eye 🚧 | +| Export: JPEG / PNG / TIFF / WebP / AVIF, sizing, file-size limit, output sharpening, naming, batch | ✅ · metadata policy, watermark, DNG ⬜ | +| MCP server, CLI, control channel | ✅ | +| Optics, Geometry/Upright, GPU pipeline, web build, persistent library | 🚧 |
@@ -224,6 +237,7 @@ git clone https://github.com/storytold/lightcraft && cd lightcraft cargo run --release -p lightcraft # opens with a procedurally generated demo library cargo run --release -p lightcraft -- ~/Pictures/trip # or point it at your photos (folders are scanned) cargo run --release -p lightcraft -- --control 7980 # with the automation channel +cargo run --release -p lightcraft-cli -- render photo.jpg -o out.jpg --set light.exposure=0.5 cargo xtask ci # fmt, clippy, tests, layering, wasm checks ``` @@ -235,7 +249,20 @@ Keyboard: G grid · D detail · E edit · An engine-first Cargo workspace of small, tested crates with enforced layering (`cargo xtask layers`): `geom`, `color`, `raster`, `tiff` → `raw`, `codecs`, `meta`, `develop` → `pipeline` → `catalog` → `engine` → `ui-egui`. The -egui frontend is one swappable crate; nothing below it knows a UI exists. +egui frontend is one swappable crate; nothing below it knows a UI exists. `mcp` and the apps (`lightcraft`, +`lightcraft-cli`) sit on top of `engine`. + +## Contributing + +Humans and agents follow the same rules — read [AGENTS.md](AGENTS.md) first. The short version: + +- **Clean-room.** Never read Adobe binaries or GPL raw/photo code (darktable, RawTherapee, LibRaw, rawspeed, dcraw…); + work from public specs and black-box observation. +- **No Adobe assets, ever** — no icons, screenshots, presets, profiles, LUTs or fonts from Adobe products. Every + image, icon and font in the repo is original, public domain, Creative Commons, OFL or permissively licensed, and has + an entry in [assets/ATTRIBUTION.md](assets/ATTRIBUTION.md) added in the same commit. +- **Pure Rust**, enforced crate layering, everything is a command, and `cargo xtask ci` green before every commit + (one task id per commit).
@@ -258,7 +285,7 @@ Clean-room, pure-Rust creative tools from the same workshop — native on macOS, Showcase photographs are public-domain works, used via Wikimedia Commons: Ansel Adams, *The Tetons and the Snake River* (1942, U.S. National Archives); Dorothea Lange, *Migrant Mother* (1936, Library of Congress); Bill Anders / NASA, *Earthrise* (1968); NASA, *The Blue Marble* (1972). The demo library is procedurally generated by LightCraft. UI font: -Source Sans 3 (SIL OFL). All icons are original. See [assets/ATTRIBUTION.md](assets/ATTRIBUTION.md). +Inter (SIL OFL). All icons are original. See [assets/ATTRIBUTION.md](assets/ATTRIBUTION.md). LightCraft is an independent project and is not affiliated with or endorsed by Adobe. Licence: MIT OR Apache-2.0. By the artcraft team. diff --git a/docs/images/ba-blue-marble.jpg b/docs/images/ba-blue-marble.jpg index 6d9444f29..ae1ed9d12 100644 Binary files a/docs/images/ba-blue-marble.jpg and b/docs/images/ba-blue-marble.jpg differ diff --git a/docs/images/ba-earthrise.jpg b/docs/images/ba-earthrise.jpg index 33f7b2a60..76cbf59b0 100644 Binary files a/docs/images/ba-earthrise.jpg and b/docs/images/ba-earthrise.jpg differ diff --git a/docs/images/ba-migrant-mother.jpg b/docs/images/ba-migrant-mother.jpg index 2ee7e4291..7583448f5 100644 Binary files a/docs/images/ba-migrant-mother.jpg and b/docs/images/ba-migrant-mother.jpg differ diff --git a/docs/images/ba-tetons.jpg b/docs/images/ba-tetons.jpg index 07ebf913c..ce35ac729 100644 Binary files a/docs/images/ba-tetons.jpg and b/docs/images/ba-tetons.jpg differ diff --git a/docs/images/bw-split.jpg b/docs/images/bw-split.jpg index bc4ec46dd..ce2644ece 100644 Binary files a/docs/images/bw-split.jpg and b/docs/images/bw-split.jpg differ diff --git a/docs/images/crop-tetons.jpg b/docs/images/crop-tetons.jpg index f4ab18e0f..87faf6499 100644 Binary files a/docs/images/crop-tetons.jpg and b/docs/images/crop-tetons.jpg differ diff --git a/docs/images/curve-tetons.jpg b/docs/images/curve-tetons.jpg index c744ef4bb..93f73cc20 100644 Binary files a/docs/images/curve-tetons.jpg and b/docs/images/curve-tetons.jpg differ diff --git a/docs/images/grading-migrant-mother.jpg b/docs/images/grading-migrant-mother.jpg index 6c04c8000..e6012a707 100644 Binary files a/docs/images/grading-migrant-mother.jpg and b/docs/images/grading-migrant-mother.jpg differ diff --git a/docs/images/grid-demo.jpg b/docs/images/grid-demo.jpg index 6d891cdc8..2e0d5de2e 100644 Binary files a/docs/images/grid-demo.jpg and b/docs/images/grid-demo.jpg differ diff --git a/docs/images/grid-pd.jpg b/docs/images/grid-pd.jpg index 8b3beafc3..c6ff0fc37 100644 Binary files a/docs/images/grid-pd.jpg and b/docs/images/grid-pd.jpg differ diff --git a/docs/images/hero-tetons.jpg b/docs/images/hero-tetons.jpg index 251139549..c72273f57 100644 Binary files a/docs/images/hero-tetons.jpg and b/docs/images/hero-tetons.jpg differ diff --git a/docs/images/info-earthrise.jpg b/docs/images/info-earthrise.jpg index d93af913d..5030e145f 100644 Binary files a/docs/images/info-earthrise.jpg and b/docs/images/info-earthrise.jpg differ diff --git a/docs/images/masking.jpg b/docs/images/masking.jpg index 850d3fdbe..826258e11 100644 Binary files a/docs/images/masking.jpg and b/docs/images/masking.jpg differ diff --git a/docs/images/presets-mixer.jpg b/docs/images/presets-mixer.jpg index 2babc65bd..93747490c 100644 Binary files a/docs/images/presets-mixer.jpg and b/docs/images/presets-mixer.jpg differ