Commit Graph
100 Commits
Author SHA1 Message Date
Brandon Thomas aec820033b Merge pull request #206 from anarion80/add_nix_build
Packaging: add a Nix flake (nix build / nix develop)
2026-10-07 20:15:50 -04:00
Brandon Thomas b90c06b347 Merge pull request #210 from voshart/pr/fetch-crate
Fetch: the model downloader becomes its own crate (no behaviour change)
2026-10-07 20:15:46 -04:00
Brandon Thomas 52f64ce0b9 Merge pull request #215 from XRTce/rw2-panasonic-lumix
LR-IMP-FORMATS: Panasonic RW2 / Leica RWL / Panasonic RAW in every raw format, with the RW2 camera look
2026-10-07 20:15:41 -04:00
Brandon Thomas 767ed15adc Merge pull request #235 from Gremiger/fix/issue-212-nef-dng-white-balance
Issue #212: Raw: keep vendor white balance when writing DNG
2026-10-07 20:15:37 -04:00
Brandon Thomas 1c025fbb97 Merge pull request #207 from voshart/pr/tests-windows
Tests: pass on Windows (path separators, temp folder inside home, one GPU edge pixel)
2026-10-07 20:15:33 -04:00
Brandon ThomasandClaude Opus 5.5 46f5d212e7 Merge main into #207 (keep main's step_until wait for the folder row)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:11:00 -04:00
Brandon Thomas eba0b9723b Merge pull request #223 from Ndsanes/l10n/zh-hans-catalog-gap
LR-BEHAV-LOCALIZE: fill the zh-hans catalog to match zh-hant
2026-10-07 20:09:36 -04:00
Brandon Thomas 5372309ad8 Merge pull request #228 from RicSchonfelder/i18n-pt-br
i18n: add Brazilian Portuguese (pt-br) UI translation
2026-10-07 20:09:32 -04:00
Brandon Thomas b63ea8f5c2 Merge pull request #222 from Ndsanes/fix/craft-fonts-relative-path
Build: resolve a relative CRAFT_FONTS_DIR against the workspace root
2026-10-07 20:09:28 -04:00
Brandon Thomas 2dda7cf842 Merge pull request #241 from agorevski/copilot/issue-cluster-docs-consistency
Docs: fix release, sibling, and command references
2026-10-07 20:09:24 -04:00
Brandon Thomas be87e1b6e7 Merge pull request #238 from DWAA1660/fix/export-missing-folder
Export: clear error when there's no export folder (instead of "Access is denied")
2026-10-07 20:09:19 -04:00
Brandon Thomas 97e34434d0 Merge pull request #217 from nledford/feat/random-sort
Library: Random sort with a stable seed and Reshuffle
2026-10-07 20:09:14 -04:00
Brandon Thomas 30192541ea Merge pull request #242 from nledford/feat/collapsible-sidebar-sections
Sidebar: collapsible Albums, Local, By Date and Keywords sections
2026-10-07 20:09:10 -04:00
Brandon Thomas c4d7c00e74 Merge pull request #225 from nledford/fix/stale-panels-after-library-switch
Library: switching libraries no longer shows the old library's sidebar
2026-10-07 20:09:06 -04:00
Brandon Thomas 3fe0bef364 Merge pull request #239 from nledford/feat/smart-album-file-path
Smart albums: File Path rule field
2026-10-07 20:09:03 -04:00
Brandon Thomas 590b387a53 Merge pull request #221 from MusseJusse/codex/navigation-arrows-pr
M16.1: complete navigation arrowheads
2026-10-07 20:08:59 -04:00
Brandon Thomas 51c878ddd8 Merge pull request #199 from storytold/fix/flaky-profile-hover-test
Tests: fix three FreeBSD-flaky headless UI tests
2026-10-07 20:08:55 -04:00
Brandon ThomasandClaude Opus 5.5 e2a941887e Nix: mark the package community-maintained in the agent guide; craft-fonts holds CJK fonts, not only Japanese
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:03:05 -04:00
Brandon ThomasandClaude Opus 5.5 f0632e7022 Fetch: crate root forbids unsafe and denies panicking lints, like every other crate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:56:42 -04:00
Brandon ThomasandClaude Opus 5.5 d3c6dc0aa8 i18n zh-hans: "Add Remove Spot" means adding a spot removal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:56:03 -04:00
Brandon ThomasandClaude Opus 5.5 ce165dfa4a Export: calmer wording for the missing-folder error
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:56:00 -04:00
Brandon ThomasandClaude Opus 5.5 7aab3fd97f Rename PrintCraft to PdfCraft (storytold/pdfcraft) (#219)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:45:42 -04:00
Brandon ThomasandClaude Opus 5.5 6408ccf244 Tests: the keyword-list test lets the list settle before clicking rows
keyword_list_filters_renames_and_suggests failed on FreeBSD CI (b35487a) and
locally (2 of 13 runs under load): ui.clickWidget clicks last frame's rect,
and right after opening the panel / expanding "travel" the rows could still
move, so the click hit "sunrise" instead of "travel|italy". Settling first:
30 of 30 runs pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:58:39 -04:00
Brandon ThomasandClaude Opus 5.5 517c745fad Tests: the folder-tree test waits for the subfolder row, not three frames
local_folder_tree_expands_and_browses failed on FreeBSD CI (707138f) and under
local load: the expanded folder's listing can land after the fixed three frames.
It now steps until the row is laid out (bounded by SETTLE).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:18:53 -04:00
Brandon Thomas 30225fb6a0 Merge remote-tracking branch 'origin/main' into fix/flaky-profile-hover-test 2026-10-07 10:15:03 -04:00
Brandon Thomas b35487add2 Merge pull request #162 from GuintherKovalski/feat/sam3-object-masks
M12: SAM 3 Object and Describe masks (pure Rust, Metal)
2026-10-07 10:14:20 -04:00
Brandon Thomas 65bc68fd33 Merge remote-tracking branch 'origin/main' into land-162 2026-10-07 10:07:54 -04:00
Brandon ThomasandClaude Opus 5.5 d5be201431 M12: SAM 3 download dialog: no Download button without a location, clearer wording
Looked at in the running app: without a configured mirror the dialog
offered Download / Try Again that could only fail; it now shows the
manual-install hint and Close (an agent confirming still gets the
reason). "A one-time download of about 3.4 GB, saved in <folder>"; a
cancelled download is reported as stopped (resumable), not failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:06:46 -04:00
Brandon ThomasandClaude Opus 5.5 d379e780cc M12: AI masks never require SAM 3 — background worker, consented download, review fixes
Engine (crates/engine/src/segment/):
- One worker thread owns the model and the encoded photo; the session
  sends jobs (with the render job for the model input) and gets results
  over channels, never locking what the model holds. In the app
  (Segmenter::background) clicks, descriptions, prepares and detail
  passes return at once and Session::segment_poll applies results (one
  undo step per settled selection, pending clicks shown on the photo);
  the CLI/MCP wait for them. Newer requests for the same selection
  supersede queued ones.
- Every job runs under catch_unwind: a candle panic becomes an error and
  the model is reloaded next time; busy counters are reset by drop
  guards; a dead worker is restarted. The model unloads after 10 min idle.
- segment.model.status / .download {acknowledged: true} / .cancel: the
  download runs on its own thread; status via atomics (try_lock only).
  Without the model every AI request fails at once with "The SAM 3 model
  is not installed…"; renders/exports never need it; `seg` params make
  AI masks from stored segmentations without it.
- Hostile documents: at most 4 detail patches per component (capped on
  deserialize and in the renderer), at most 64 Object clicks.

UI: Object / Describe without the model open "Download the SAM 3
Model?" (size, folder, SAM License link; Not Now / Download, progress,
cancel, Try Again with the reason, Continue once installed); progress in
the Masking panel when the dialog is closed. Reverted the PR's unrelated
default change (mask overlay off + hover-red) to main's behaviour.

tools/install-sam3.*: --fail so error pages never land in files, 416
restarts instead of looping, the weights are verified before they are
moved into place (a bad file is deleted, never resumed from).

Docs: docs/ai-masks.md (in-app download, mirrors, SAM License summary,
no weights in the repo), NOTICE, parity LR-MASK-OBJECTS, What's New,
ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:56:50 -04:00
Brandon ThomasandClaude Opus 5.5 b52f43d1d5 M12: lightcraft-segment: Apache-2.0, checked weights, pure-Rust model download
- The crate ports Apache-2.0-only Hugging Face transformers code: it is
  now `license = "Apache-2.0"`, and every ported file carries the
  modification notice Apache-2.0 §4(b) asks for.
- Weights::open checks every tensor's byte range (and the header)
  against the file's length: a truncated or damaged download is an
  error at load, never a short read later; regression test with
  hostile offsets.
- fetch/: the model download, only when asked for. An ordered mirror
  list (env LIGHTCRAFT_SAM3_MIRRORS, a mirrors file, DEFAULT_MIRRORS —
  empty until LightCraft's CDN exists, TODO for the maintainer),
  fallback to the next mirror, resume via Range, redirects, connect and
  stall timeouts, cancel, size caps, exact size + SHA-256 (pinned from
  tools/install-sam3.sh) before an atomic rename; damaged files are
  deleted, HTTP error bodies never written.
- HTTP/1.1 client over std sockets + rustls with the RustCrypto provider
  (rustls-rustcrypto) and webpki-roots: no ring / aws-lc-rs, nothing
  compiled from C (no new `cc` users in the app's build graph).
- Tests against a local TcpListener server (no internet): fallback,
  redirects, chunked bodies, resume, 416, hash mismatch, too much data,
  stalls, cancel.
- *.safetensors are gitignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:56:49 -04:00
Brandon ThomasandClaude Opus 5.5 fefd61c967 M12: merge origin/main into the SAM 3 masks branch (PR #162)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:16:09 -04:00
Brandon Thomas fb9fb7717e Merge pull request #201 from haraldh/fix/arw-saturated-hues
LR-PROF-CAMERACOLOR: camera-look hue table, chroma curve and per-model camera profiles
2026-10-07 08:36:09 -04:00
Brandon Thomas f2f449611d Merge pull request #198 from sakamoto824/codex/zh-tw-localization
M16: add Traditional Chinese UI, menus and stock preset localization
2026-10-07 07:09:14 -04:00
Brandon Thomas 288fd3f125 Merge sakamoto824's original PR #198 commit (superseded by the port above) 2026-10-07 07:06:54 -04:00
Brandon Thomas 1779216514 Merge remote-tracking branch 'origin/main' into land-198 2026-10-07 07:06:50 -04:00
Brandon Thomas f0bb7c768e Merge pull request #184 from lzjtugjc/i18n/zh-hans
LR-BEHAV-LOCALIZE: a language table, Simplified Chinese, and per-script font fallback
2026-10-07 07:06:42 -04:00
Brandon Thomas 2eff66dd1e Merge remote-tracking branch 'origin/main' into land-184
# Conflicts:
#	docs/parity.md
2026-10-07 07:04:00 -04:00
Brandon Thomas 549cbe728c Merge pull request #170 from voshart/pr/faces-1-regions
Faces: read face regions from XMP, show them in the loupe, and a People view
2026-10-07 06:49:45 -04:00
Brandon ThomasandClaude Opus 5.5 4e0f8ced0c Tests: the hover-preview tests wait for the hover render, not just a quiet spell
profile_browser_previews_on_hover_and_applies_on_click failed on FreeBSD CI
(loupe showed "render", not "hover"): settle() returns after 12 idle frames,
which can come before the hover render lands on a loaded VM. A step_until
helper waits for the condition itself; the preset hover test had the same race.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:36:17 -04:00
Brandon ThomasandClaude Opus 5.5 862c1f253a LR-LIB-PEOPLE: document MWG face regions in xmp-interop and the parity row
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:21:27 -04:00
Brandon ThomasandClaude Opus 5.5 4ded49ecd9 LR-LIB-PEOPLE: face boxes and People close-ups follow Rotate Left/Right
Regions are stored on the upright (EXIF-oriented) photo, but the loupe's normalized frame and the
close-up crop include the user's orientation. The loupe overlay now maps each box into that frame
(and a resize drag back out of it), and face_job maps the face and swaps the photo's size for a
quarter turn. Flips need nothing: they are applied after the normalized frame. Adds
Orientation::inverse and Orientation::map_norm_rect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:21:04 -04:00
Brandon ThomasandClaude Opus 5.5 269934caca LR-BEHAV-LOCALIZE: reinstall fonts on a language switch; restore the painted-UI tests
- the CJK fallback order follows the UI language's script, but the fonts were
  only installed on the first frame: switching 日本語 ↔ 简体中文 at runtime kept
  the previous language's Han forms. The app remembers the language its fonts
  were built for and reinstalls them when it changes.
- the native menu bar rebuilds on any language change (keyed on the language
  code, not on "uses CJK fonts", which is true for both CJK languages)
- restore the tests the language-table change dropped, for every language:
  core catalog entries, user-named menu items stay untranslated, the window
  paints each language and menu ids don't change with it, CJK glyphs in every
  UI family, and the UI runs without craft-fonts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:19:50 -04:00
Brandon ThomasandClaude Opus 5.5 8c253b28ad LR-LIB-PEOPLE: a sidecar that states mwg-rs:Regions replaces the photo's regions, even when empty
Re-reading a sidecar whose region list was emptied by a region-aware app now clears the stale
regions. A sidecar without mwg-rs:Regions at all (an app that doesn't do regions) says nothing about
them and the photo's regions are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:19:45 -04:00
Brandon ThomasandClaude Opus 5.5 87a58b4183 LR-BEHAV-LOCALIZE: one Language menu entry per language; parity reads the language table
- UI_COMMANDS still listed app.language.english/japanese next to the new
  LANGUAGE_COMMANDS table, so Edit > Language showed English and 日本語 twice
- LANGUAGE_COMMANDS is `pub const`, the form xtask parity scans for; a test
  reads the real menus.rs and checks every language id is found once
- the Simplified Chinese command is app.language.simplifiedChinese, in line
  with the other camelCase command ids (the settings code stays zh-hans)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:17:06 -04:00
Brandon ThomasandClaude Opus 5.5 60a8649779 LR-LIB-PEOPLE: leave empty face regions out of the catalog JSON
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:16:02 -04:00
Brandon ThomasandClaude Opus 5.5 313c555b50 LR-BEHAV-LOCALIZE: compile-checked tr_format! for every language catalog
Restore main's compile-checked formatting, generalised to N catalogs: build.rs
writes one tr_format! arm per English message that matches on the active
language and calls format! with that language's translation (English is the
fallback arm). The runtime substitution dropped format specs ({:.1}, {:+},
{:.0}%), e.g. the smart-preview size and the merge progress percentage.

- formats catalogs use main's convention again ({0}/{1} for reordering, {:.0}
  to consume an unused plural suffix); zh-hans converted, with the size and
  percentage placeholders fixed by hand
- build.rs: auto-discovers locales/*-formats.json, validates the code
  (^[a-z]+(-[a-z]+)*$), fails when the catalogs' keys differ, and reruns
  when the locales directory changes
- zh-hans: translate the strings main added since the PR branched
- test: precision, sign and reordered positional values survive in every
  language

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:13:44 -04:00
Brandon ThomasandClaude Opus 5.5 3793e8fc33 LR-LIB-PEOPLE: clip XMP face regions to the photo, drop off-photo ones, read Rotation π
A region parsed from mwg-rs:Regions is now intersected with the 0..1 frame and dropped when it
misses the photo, so a hostile or stale sidecar (x=1e5, a 1e5-wide box) can't park a box far
outside the image. Lightroom's mwg-rs:Rotation of ±π (Exif orientation 3) is mapped to the upright
frame like the quarter turns; mirrored orientations can't be expressed in MWG and are taken as
written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:12:49 -04:00
Brandon Thomas 1b22a0e53b Merge origin/main into land-170 2026-10-07 06:09:24 -04:00
Brandon Thomas d814a31497 Merge remote-tracking branch 'origin/main' into land-184
# Conflicts:
#	crates/ui-egui/locales/ja-formats.json
#	docs/parity.md
2026-10-07 06:03:46 -04:00
Brandon Thomas 889b610e9f Merge pull request #192 from itsmunzir/fix/167-connect-hint
CLI: the connect hint names the port it actually tried (#167)
2026-10-07 06:02:12 -04:00
Brandon Thomas eacce855b9 Merge pull request #179 from coygeek/docs/star-history
docs: add star history chart to README
2026-10-07 06:02:08 -04:00
Brandon Thomas 3757506f46 Merge pull request #178 from cruzer45/feat/cr3-preview-metadata
CR3: full-size preview and metadata from the container
2026-10-07 06:02:03 -04:00
Brandon Thomas 01c9b743fe Merge remote-tracking branch 'origin/main' into fix-178
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/locales/ja.json
#	docs/parity.md
#	docs/whats-new.md
2026-10-07 06:01:50 -04:00
Brandon Thomas db2d94a233 Merge pull request #177 from cruzer45/fix/recently-deleted-restore
Restore from Recently Deleted; re-adding a deleted photo shows where it is
2026-10-07 06:01:33 -04:00
Brandon Thomas 2c2694ff1e Merge pull request #165 from treyreynolds/feat/nef-camera-look
Issue #150: Raw: NEF colour from the camera JPEG; 12-bit NEF black level
2026-10-07 06:01:27 -04:00
Brandon Thomas 136c1a0d89 Merge pull request #155 from kywk/feat/radial-masking-tuning
feat(ui): improve radial mask resizing and rotation
2026-10-07 06:01:23 -04:00
Brandon Thomas 9ef83ae3ae Merge pull request #152 from storybored379/fix/symlink-original-guard
Export: protect originals imported through differently named symlinks
2026-10-07 06:01:18 -04:00
Brandon ThomasandClaude Opus 5.5 51f0ef25ae Export: look up the library's symlinked originals once per guard
The symlink fallback ran read_link on every library entry for each existing
target; a large library made every Overwrite export check do thousands of
syscalls. The guard now finds the links on first need and keeps them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 05:41:28 -04:00
Brandon Thomas 1ce28c3aea Merge main into fix/symlink-original-guard
# Conflicts:
#	crates/engine/src/tests_export.rs
2026-10-07 05:41:26 -04:00
Brandon Thomas 5cee0c08d0 Merge pull request #158 from storytold/fix/issue-148-rx100m3-green
Issue #148: Raw: read white balance, black level and crop of pre-2017 Sony ARWs
2026-10-06 18:25:50 -04:00
Brandon ThomasandClaude Opus 5.5 33a84b8427 Issue #148: Raw: read white balance, black level and crop of pre-2017 Sony ARWs
Sony bodies from before ~2017 (RX100–RX100M5, RX10, NEX, SLT, ILCE-6000,
A7/A7II/A7RII, ...) write no plain 0x7313/0x7310/0x74c7 tags in the raw IFD,
so the decoder used unit WB multipliers (strong green cast, e.g. the CC0
DSC-RX100M3 sample), black 512 (800 on 1-inch sensors), and kept padding
columns at the right edge.

- White balance: WB_RGBLevels from the maker note's enciphered Tag2010
  block (layouts per ExifTool's Tag2010a..i tables; byte substitution
  p^3 mod 249 checked black-box on 15 CC0 files: SonyISO matches Exif ISO,
  ILCE-7M3 levels match its plain 0x7313).
- Black level: recovered from the encrypted SR2SubIFD by known-plaintext
  analysis (constant key in every file; RX100M6/ILCE-7M3 plain 0x7310 as
  plaintext; 8 keystream bytes at offset 2510, plausibility-checked).
- Crop: DNG DefaultCrop or the maker note's FullImageSize.
- "12-bit uncompressed" ARWs hold 14-bit-scale data: black/white follow it.
- Render cache version bumped; corpus manifest + corpus test, unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:27:33 -04:00
Brandon Thomas 265248c86f Merge pull request #151 from storytold/fix/snapshot-test-settle
Tests: snapshot-determinism test asserts both runs settled
2026-10-06 15:14:10 -04:00
Brandon ThomasandClaude Opus 5.5 1130e99095 Tests: the snapshot-determinism test asserts both runs settled before comparing pixels
snapshot() ignored settle()'s result, so on a loaded machine (seen on the FreeBSD VM and
under local load) a timed-out settle compared half-rendered frames and failed as a
misleading pixel diff. The test now settles explicitly with a 300 s budget, asserts it
settled, then paints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:13:58 -04:00
Brandon Thomas 07a7316d8b Merge pull request #149 from storytold/pr/craft-fonts
Fonts: use craft-fonts as an optional build input; move the Japanese fonts out
2026-10-06 14:49:22 -04:00
Brandon ThomasandClaude Opus 5.5 2aa236537f Fonts: use craft-fonts as an optional build input; move the Japanese fonts out
The Japanese fonts (BIZ UDPGothic Regular/Bold for the UI, BIZ UDMincho for text
watermarks; #110, #114) now come from storytold/craft-fonts instead of assets/fonts/.

- crates/engine/build.rs: the craft-fonts recipe. With CRAFT_FONTS_DIR set it embeds
  the manifest's fonts as lightcraft_engine::CRAFT_FONTS (wasm32: BIZ UDPGothic Regular
  only, for the web size budget); unset, CRAFT_FONTS is empty. Local files only, no
  network; craft-fonts is not in any Cargo.toml.
- UI: theme::font_definitions adds the Japanese faces after Inter and egui's defaults
  in every family (BIZ UDPGothic first, Bold first for semibold). About box lists the
  embedded families.
- Watermarks: Inter, then the craft-fonts Japanese faces (Mincho first).
- Removed BIZUDPGothic-Regular/Bold.ttf, BIZUDMincho-Regular.ttf and their OFL files,
  and their ATTRIBUTION rows; added an attribution row for craft-fonts as an optional
  build input; NOTICE updated.
- Tests: Japanese glyph tests use CRAFT_FONTS and skip without it; new tests for
  Japanese in the UI with craft-fonts and for the UI and watermarks without it.
- CI: the FreeBSD job builds/tests with craft-fonts. Releases check out craft-fonts at
  a pinned commit, build with CRAFT_FONTS_DIR + CRAFT_FONTS_REQUIRED=1, and ship the
  fonts' OFL licences (plus NOTICE) in every package.
- Docs: AGENTS.md, CLAUDE.md, README, docs/web.md, docs/localization-ja.md, ROADMAP,
  parity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:35:02 -04:00
Brandon Thomas bd3185ef4d Merge pull request #145 from storytold/fix/issue-138-lightroom-dng
Issue #138: DNG: apply the file's own camera-profile look (HueSatMap, LookTable, ToneCurve)
2026-10-06 11:27:16 -04:00
Brandon Thomas 4cf883155a Merge pull request #144 from storytold/fix/issue-136-vulkan-startup-crash
Issue #136: Windows: use DX12 by default, honour WGPU_BACKEND, never let GPU init block startup
2026-10-06 11:27:03 -04:00
Brandon ThomasandClaude Opus 5.5 71eac70696 Issue #138: DNG: apply the file's own camera-profile look (HueSatMap, LookTable, ToneCurve)
Lightroom-converted DNGs carry their camera profile's ProfileHueSatMapData1/2
and ProfileLookTableData (and sometimes ProfileToneCurve). We used only the
colour matrices, so such DNGs rendered flat and muted.

- raw: new `profile` module reads the tags (DNG spec ch. 6: value-major,
  hue-middle, saturation-minor tables, wrap-around hue, tri-linear lookups,
  sRGB value encoding) from the raw IFD or IFD 0; malformed tags are ignored.
- engine: the raw loader applies the hue/sat map (interpolated by the same
  illuminant weight as the matrices) before BaselineExposure and the look
  table after it, in linear ProPhoto; a ProfileToneCurve becomes the source's
  camera tone. Without one the standard base tone is kept.
- dngwrite keeps the look with the data (conversions, smart previews, merges).
- Render cache version 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:36:30 -04:00
Brandon ThomasandClaude Opus 5.5 b66cdb23a3 Issue #136: Windows: use DX12 by default, honour WGPU_BACKEND, never let GPU init block startup
wgpu loads the driver of every backend in an instance's set while it
enumerates adapters. The compute device (crates/gpu) hard-coded
Backends::PRIMARY (Vulkan + DX12 + Metal) and ignored WGPU_BACKEND, and
was created from LightcraftApp::new on a background thread at launch, so
a crashing Vulkan driver (Intel UHD 630, igvk64.dll) killed the process
before the window appeared; the window (egui-wgpu) also listed Vulkan.

- lightcraft_gpu::backend: DX12 only on Windows (Metal on macOS, as before
  on Linux) for both the compute device and the window;
  LIGHTCRAFT_GPU_BACKEND=dx12|vulkan|metal|gl|auto|off, else WGPU_BACKEND;
  backends missing from the build fall back to the default.
- The device is created only when GPU rendering is enabled, after the
  first frame; the preference is applied before the window opens.
- Crash sentinel: gpu-init.marker in the settings folder around device
  creation; if left behind, the next launch starts with GPU rendering off
  and a notice saying how to turn it back on.
- Tests: backend parsing/selection, sentinel, window defaults, headless
  snapshot with LIGHTCRAFT_GPU=0 / LIGHTCRAFT_GPU_BACKEND=off.
- Docs: gpu-pipeline.md (backends, env vars, troubleshooting), whats-new,
  parity LR-BEHAV-GPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:16:05 -04:00
Brandon Thomas d2359ce095 Merge pull request #143 from storytold/fix/issue-134-trim-write-safety
Issue #134: Exports: atomic without fsync; Copy import verifies against the probe hash
2026-10-06 10:11:47 -04:00
Brandon ThomasandClaude Opus 5.5 7a2596cd43 Issue #134: Exports: atomic without fsync; Copy import verifies against the probe hash
- safe_file: write policy documented (durable for what can't be recreated, atomic-only for
  recreatable outputs); new write_atomic_nosync (temp + rename, temp removed on failure, no
  file/folder sync); per-thread sync counter for tests.
- export::write_file (exports, renders, screenshots, merge previews, CLI/MCP) uses the
  non-syncing writer; new write_file_durable keeps the sync for Edit a Copy (the TIFF becomes a
  library photo). Catalog, sidecars, settings, DNG conversion/merges and smart previews stay
  durable; the #93 original-overwrite guard is untouched.
- Import > Copy verifies the synced copy against the probe's content hash (SipHash-1-3/128 of the
  whole file) instead of re-reading the source; byte compare when there is no hash. A file changed
  since Review Import is now refused instead of imported with stale details. Move keeps its
  byte-for-byte check before deleting sources.
- check_write_target: skip building the library-wide guard when nothing is at the target.
- write_new_unique keeps its read-back (DNGs replace raws; cheap next to encoding).
- Tests: no sync on the export path, durable writers still sync, Copy caught by the probe hash
  (corrupt copy, stale hash, changed source); ignored timing test write_policy_timing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:08:29 -04:00
Brandon Thomas 8bef0b1ef3 Merge pull request #141 from storytold/pr/windows-arm64
Windows on ARM64: release builds, PE header check, install test on ARM64 hardware
2026-10-06 09:59:27 -04:00
Brandon ThomasandClaude Opus 5.5 a2dbefd1ee Windows ARM64 workflow: pin third-party actions by commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:51:08 -04:00
Brandon ThomasandClaude Opus 5.5 f5bd3cc2db Windows on ARM64: release builds, PE header check, install test on ARM64 hardware
Release builds add an arm64 MSI and portable zip, cross-compiled on the x64
runner (signing and WiX as for x64). package.ps1 checks each binary's PE
header before packaging: Machine must match -Arch, the app must be a GUI
program and the CLI a console program. It skips the CLI smoke run when an
ARM64 build can't run on the host. A new Windows ARM64 workflow packages the
ARM64 MSI, installs it on a Windows 11 ARM64 runner, checks both installed
exes are ARM64, runs the CLI, and uninstalls. Ported from printcraft#66.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:38:47 -04:00
Brandon Thomas 1969b311cc Merge pull request #137 from benlukka/fix-flickering-preview-hover
fix(ui): eliminate preview flickering when hovering presets and profiles
2026-10-06 09:24:12 -04:00
Brandon Thomas fc3fa1a71b Merge pull request #140 from storytold/pr/release-0.2.1
Release: LightCraft v0.2.1
2026-10-06 08:01:39 -04:00
Brandon ThomasandClaude Opus 5.5 d0612b0b21 Release: LightCraft v0.2.1
Fixes the Windows installer: the Start Menu shortcut and Add/Remove Programs icon were blank, and the shortcut description was wrong.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 08:01:29 -04:00
Brandon Thomas 66dc737ff5 Merge pull request #139 from storytold/pr/windows-packaging
Windows packaging: Start Menu/Add-Remove icon, no console window, correct description
2026-10-06 07:54:46 -04:00
Brandon ThomasandClaude Opus 5.5 fec3b15234 release.yml: explicit if for the wasm-bindgen install (shellcheck SC2015)
packaging-lint has failed on main since this step was added; same behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 07:53:44 -04:00
Brandon ThomasandClaude Opus 5.5 11ebb3bdb6 Windows packaging: Start Menu/Add-Remove icon, no console window, correct description
The MSI Icon id had no .ico/.exe extension, which Windows Installer needs for
advertised shortcuts and ARPPRODUCTICON, so both showed a blank icon. Release
builds of the desktop app are now GUI-subsystem (no console window; the CLI stays
a console program), the shortcut/summary description names what LightCraft does, and
packaging-lint rejects an Icon id without an extension. Found in printcraft#57.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 07:50:38 -04:00
Brandon Thomas 65da36675f Merge pull request #115 from arata-1972/codex/sony-arw-initial-colour
Improve Sony ARW starting colour and tone, and preserve decoded source metadata
2026-10-05 19:47:57 -04:00
Brandon ThomasandClaude Opus 5.5 cbb6c3b8f7 Merge origin/main (#114) into land-115
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:41:46 -04:00
Brandon ThomasandClaude Opus 5.5 5b414ffb8e LR-PROF-CAMERACOLOR: record the ARW file-local fit's public-sample results
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:34:01 -04:00
Brandon ThomasandClaude Opus 5.5 f7a7831380 LR-PROF-CAMERACOLOR: keep the ARW camera tone curve with smart previews
Smart previews store the decoded source with the fitted colour matrix
baked in, but the file-local tone curve lives in the decoder's
SourceInfo, which a proxy did not keep: an offline ARW rendered and
exported with the generic filmic curve instead (darker, a different
look). The proxy header now carries the curve (validated on load,
ignored when invalid), DecodedSource::info_or merges it into the header
facts, and is_valid reads the longer header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:30:43 -04:00
Brandon Thomas 2b2ade7a23 Merge pull request #114 from arata-1972/codex/lightcraft-japanese
Extend Japanese localization across editing, import and export UI
2026-10-05 19:29:49 -04:00
Brandon ThomasandClaude Opus 5.5 d6c7228dd4 M16: merge origin/main into Japanese localisation (PR #114)
Keep main's data-safety work (ui.json recovery and atomic writes, library-problem
window, off-thread file checks, import Cancel) and wrap its new strings: import
cancel/progress messages, the library-problem window and banner, and the new
Back Up / Restore Library menu items now have Japanese translations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:28:34 -04:00
Brandon ThomasandClaude Opus 5.5 4b3048c48f LR-PROF-CAMERACOLOR: accept ARW camera-look fits up to 0.10 held-out RMS
The 0.055 cap rejected half of the public Sony samples tried (ILCE-6400,
ILCE-6700, ILCE-7M4) although their fits were 1.5-3x closer to the
camera JPEG than the fallback and visibly better (mean dE vs the embedded
preview 19-26 -> 5-10). Unrelated previews stay rejected (synthetic test
lands at 0.115).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:28:22 -04:00
Brandon ThomasandClaude Opus 5.5 bc4799ca42 Merge origin/main into land-115 (PR #115)
Resolve SourceRef::load_source against #104's offline fallback: a File
source keeps the decoder's SourceInfo; a smart-preview fallback has none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:25:37 -04:00
Brandon ThomasandClaude Opus 5.5 586479a309 M16: drop fork-only Japanese packaging from PR #114
Remove scripts/package-japanese-macos.py, the japanese-local feature and its
config/library/startup overrides, the settings.language migration, and the
local-build notes in the docs. Upstream library and config defaults (incl.
library::default_dir, which already honours LIGHTCRAFT_LIBRARY) are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:11:34 -04:00
Brandon Thomas 87f275b58e Merge pull request #132 from storytold/fix/issue-104-ui-fs-v2
Issue #104: keep file-system calls off the UI thread
2026-10-05 19:08:15 -04:00
Brandon Thomas 894759e6d8 Merge main into fix/issue-104-ui-fs-v2
# Conflicts:
#	docs/parity.md
#	docs/whats-new.md
2026-10-05 19:00:37 -04:00
Brandon Thomas 1952f7c960 Merge pull request #131 from storytold/fix/issue-107-web-safety
Issue #107: Web build: data-safety fixes for libraries kept in the browser
2026-10-05 18:59:14 -04:00
Brandon Thomas 7bbdbc03ef Merge main into fix/issue-107-web-safety
# Conflicts:
#	apps/lightcraft-web/src/web.rs
#	docs/parity.md
#	docs/whats-new.md
2026-10-05 18:58:53 -04:00
Brandon Thomas 0f34a65a8c Merge pull request #130 from storytold/fix/issue-97-folder-undo
Issue #97: Rename Folder / Move Folder are undo steps
2026-10-05 18:58:38 -04:00
Brandon Thomas 6c066b66f2 Merge main into fix/issue-97-folder-undo
# Conflicts:
#	crates/engine/src/lib.rs
#	docs/parity.md
#	docs/whats-new.md
2026-10-05 18:58:13 -04:00
Brandon ThomasandClaude Opus 5.5 7b59081d22 Issue #104: keep file-system calls off the UI thread
Re-applies fix/issue-104-ui-fs on top of the data-safety fixes (integrate/safety):
- availability cache: originals and smart previews are checked on a worker thread; the UI
  answers from the cache (grid, Info panel, photo menu, Missing Photos view)
- import split into ImportJob::prepare (worker) + commit_prepared, with Cancel; Copy keeps
  #96's verified copies
- Find Missing Photos: find_candidates (snapshot, no I/O) + plan_find_missing (all file I/O,
  on a worker, never the session) with #105's matching rules unchanged (name+size+hash;
  renamed by size+hash; single name+size; ambiguous look-alikes skipped and reported; files
  already in use excluded). The plan is applied with library.findMissing {found, missing,
  ambiguous}, re-checked against the catalog then: photos relinked meanwhile are left alone,
  files now in use are not taken. library.findMissing {folder} still runs synchronously.
- Build / Discard Smart Previews with background: true runs on a worker with progress and
  Stop, keeping #106's atomic writes, is_valid checks and `repaired` count (also in
  library.previewProgress); the render worker's smart-preview fallback uses is_valid
- Rename preview planned on a worker (plan_rename_photos) on the same planning core as
  Session::plan_rename_with (MoveFs, case-only respelling by file identity, #95)
- Local folder listing via fs_cached; tests_offline (slow injected probe, frames < 300 ms)

Tests: worker-planned Find Missing equals the synchronous command for a renamed + ambiguous
library; a plan is re-checked when applied; background smart previews repair a damaged proxy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:58:04 -04:00
Brandon Thomas e11f77d9ca Merge pull request #129 from storytold/fix/issue-94-control-close
Issue #94: Control: close the connection on malformed input
2026-10-05 18:57:59 -04:00
Brandon Thomas f383d1e736 Merge main into fix/issue-94-control-close
# Conflicts:
#	docs/whats-new.md
2026-10-05 18:57:50 -04:00
Brandon Thomas edf05789ed Merge pull request #128 from storytold/fix/issue-103-settings-files
Issue #103: Settings files: keep damaged ones, never overwrite unread ones, write ui.json atomically, confirm quit with unsaved changes
2026-10-05 18:57:30 -04:00
Brandon Thomas bccccfb92a Merge main into fix/issue-103-settings-files
# Conflicts:
#	crates/engine/src/library.rs
#	docs/whats-new.md
2026-10-05 18:56:50 -04:00