Commit Graph

9 Commits

Author SHA1 Message Date
Brandon Thomas 3ef4eb0687 M9.2: preset files — .lcpreset import/export (groups preserved), XMP presets via crs: mapping
- engine presets.rs: .lcpreset JSON format {format: "lightcraft.preset", version, presets[]},
  parse_preset_file (.lcpreset file / bare preset / array, or XMP), folder expansion,
  Session::add_presets (identical presets skipped, id clashes get fresh user.* ids, built-ins
  never replaced).
- crs::preset_from_xmp: crs: fields → partial settings, crs:Name/crs:Group (fallback: file name /
  "Imported Presets").
- Commands preset.import {paths} and preset.export {path, ids?, group?}; UI commands
  file.importPresets / file.exportPresets (File menu, with native open/save dialogs on desktop),
  Presets panel "⋯" menu (Import Presets…, Export User Presets…) and group context menu
  (Export Group…).
- Tests: export → import round trip keeps groups/settings, duplicates skipped, clashing ids,
  malformed files reported, hand-written XMP preset imports and applies.
- docs/xmp-interop.md: preset file section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:05:26 -04:00
Brandon Thomas 8af27c11b1 M10.8: XMP sidecars — save/read metadata + develop settings, auto-write, crs: interchange
- crates/engine/src/sidecar.rs: <stem>.xmp (default) or <file>.xmp next to originals with rating,
  label, title, caption, copyright, creator, keywords, capture time/GPS, pick flag + full develop
  settings in lc:settings; atomic writes; read on import (sidecar wins for metadata, edits restored)
  and via photo.readMetadataFromFile (one undo step); raw/DNG embedded XMP used without a sidecar.
- Commands: photo.saveMetadataToFile (Cmd+S), photo.readMetadataFromFile, library.xmpPreferences
  {autoWrite, naming}, library.toggleAutoWriteXmp; prefs persisted in the library's prefs.json.
  Auto-write rewrites sidecars after each committed change (not mid-drag; undo/redo too).
- crates/engine/src/crs.rs: crs: develop fields (PV2012 light, WB abs/incremental, presence, HSL,
  B&W mix, parametric + point curves, colour grading, sharpening, NR, vignette, grain, optics,
  geometry, crop) → partial settings; documented in docs/xmp-interop.md.
- meta: write_xmp_lc for extra lc: properties; crs namespace canonicalised on read (never written).
- Tests: packet round trip, crs mapping with hand-written snippets, save → delete library →
  re-import restores edits, auto-write + prefs persistence, foreign sidecar, DNG-embedded XMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:36:19 -04:00
Brandon Thomas 55c5c6f0c6 M1.4: persistent libraries for headless MCP (lightcraft-cli mcp --library DIR); bump render cache version
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:17:38 -04:00
Brandon Thomas 1da0263d56 Merge main into persistence branch (keep JobPool renderer; wasm inline job timing via now_ms)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:09:07 -04:00
Brandon Thomas 2d2bc2ad8f M0.11: web build (WASM)
apps/lightcraft-web runs the egui UI in the browser (eframe web, glow/WebGL2):
procedural demo library on load; in-memory imports via file picker
(Cmd+Shift+I) and drag-and-drop (MemStore + bytes-based engine hooks);
export goes through app.export and downloads in the browser; `?bench` logs
first-frame and slider latency. `cargo xtask web [--serve [port]] [--dev]`
builds with the matching wasm-bindgen CLI into <target>/web/; the web app is
part of the CI wasm check. Wasm fixes: lazy profiling Instant in pipeline,
web-time clocks in ui-egui (render timings were 0 on wasm). Docs: docs/web.md.
No persistence on web yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:01:18 -04:00
Brandon Thomas 17057f7bbc docs: README (MCP, CLI, export, status, contributing), AGENTS.md (asset enforcement, crash recovery, testing/perf), screenshots re-captured with Inter
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:52:34 -04:00
Brandon Thomas e7b3724b5f M1.4: crash-safe catalog persistence (op log + snapshot)
- catalog: Store trait (FsStore: temp+fsync+rename+dir fsync; MemStore),
  Journal: CRC-checked JSON-lines op log with sequence numbers + atomic
  snapshots; torn final record dropped and truncated, stale records after a
  snapshot skipped, mid-log damage preserved as catalog.log.damaged-N.
- PushHistory op so each edit logs one history step (not the full history).
- engine: Session::open_library/persist/close_library; every top-level
  command is fsynced before returning; presets.json + view.json;
  library.info / library.compact commands.
- app: default library ~/Pictures/LightCraft Library (LIGHTCRAFT_LIBRARY or
  --library DIR override), --memory for throwaway sessions, snapshot on quit.
- tests: proptest replay(log)==state with random snapshots/reopens, every
  truncation of the last record, stale log, mid-log damage, FsStore, engine
  restart without close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:40:40 -04:00
Brandon Thomas 50307e59db M0.9: MCP server + lightcraft-cli
crates/mcp (lightcraft-mcp, L5): hand-written MCP over stdio (JSON-RPC 2.0,
protocol 2025-06-18 with 2025-03-26/2024-11-05 negotiation): initialize,
ping, tools/list, tools/call, resources/list/read. Two backends behind one
trait: Headless (in-process engine Session; answers engine.execute,
engine.commands, ui.render, app.export) and Remote (the desktop app's
loopback JSON-lines control channel; lazy connect + reconnect).

Tools: helpers (list_commands, run_command, import, query_photos,
select_photos, list_controls, get/set_develop, apply_preset, crop,
render_photo -> image content, export), UI tools when connected
(screenshot -> image content, inspect_ui, set_ui, list_widgets, click,
press_key, type_text, pointer_gesture), plus one cmd_<id> tool generated
per command in the registry (--compact omits them).

apps/lightcraft-cli: `mcp [--connect [ADDR]] [--demo] [--compact] [FILES]`,
`render <in> -o <out> [--set control=value]... [--settings] [--preset]
[--size] [--quality]`, `commands`, `controls`.

Acceptance e2e: crates/mcp/tests/e2e.rs sets exposure over MCP and renders
(headless and through the TCP transport); apps/lightcraft-cli/tests/cli.rs
does the same through the real binary's stdio. Docs: docs/mcp.md,
docs/control-protocol.md. Also rustfmt of one line in pipeline/finish.rs
(main was not fmt-clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:37:08 -04:00
Brandon Thomas 440cedfa9c README: product-style showcase with screenshots of public-domain photos developed in LightCraft; reproducible showcase scripts; display-referred tone map for JPEGs (exact pass-through); fixes (crop panel wrap, overlay clipping, greyscale histogram, painted chevrons)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:56:38 -04:00