Commit Graph
1934 Commits
Author SHA1 Message Date
tylerphotosandCodex 4cb90d4b7e LR-IMP-ADD-DIALOG: clear deleted import destinations
Keep the stored destination consistent with the picker's None fallback after
catalog changes. Extend the real-file import regression to delete the chosen
album before confirmation, then verify import membership and undo.
Document the helper contracts and destination transitions for review coverage.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 20:34:52 -05:00
Bruno-Alumn 79f11e098c Web: lightcraft.command refuses params that aren't a JSON object
The page's automation call parsed its params with a fallback to {}, so a
typo such as lightcraft.command("photo.delete", "{ids: [3]}") ran
photo.delete with no params, which acts on the selection. Params must
now be a JSON object (blank text or null is {}); anything else rejects
the promise and runs nothing, as the control channel and MCP already do.
2026-10-21 01:05:03 +00:00
Bruno-Alumn 7ab5b150f3 KEYC-PANELS: F8 shows and hides the right panel
Lightroom Classic's F8 hides the right panel; F6 and F7 (filmstrip, left
panel) were bound but F8 did nothing. View > Right Panel (view.rightPanel,
F8 as a secondary key like F6 / F7) hides the right panel and shows the
same one again next time, or Edit when none was hidden. Hiding a tool
ends it, as closing its panel does.

Gap 28 listed rating [ ], flag cycling and F1 help as missing; they are
bound, so the entry now lists only filter-bar keys, Tab / Shift+Tab and F5.
2026-10-21 00:39:53 +00:00
Bruno-Alumn 61823b1736 LR-PRE-PANEL: the applied preset stays marked on returning to the photo (#2392)
The panel marked the last applied preset only while the selection was
the one it was applied to, and forgot it on the first frame with another
photo: back on the photo, nothing showed which preset it had. It now
remembers the preset per photo together with the photo's settings right
after, and marks it while the photo still has them; another photo shows
its own (or none), and a further edit drops the mark. The Amount slider
is no longer forgotten on a switch either: it comes back with the photo
while no later edit, undo or redo owns the undo step.
2026-10-21 00:27:45 +00:00
Bruno-Alumn 360bf89903 LR-MASK-OVERLAY: a new or picked mask shows its overlay again (#1800)
A mask slider hides the overlay so the adjustment can be judged, and
nothing showed it again: creating another mask, picking one in the list,
duplicating it or adding a part left it hidden while the Overlay menu
still named Color Overlay. Those now show the overlay, as Lightroom does;
so does a new AI selection from a click or a description.
2026-10-21 00:13:57 +00:00
Bruno-Alumn 8ef46aa088 Web: the page title names the open photo and unsaved changes (#2397)
eframe's web runner doesn't handle ViewportCommand::Title, so the web
build never named what was open, and a host embedding the page could
only guess whether a dropped file had opened. The page title is now
"<file name> — LightCraft" for the active photo, with " •" after the
name while changes are not yet written to browser storage, and the
window title when no photo is active. It is set only when it changes.
2026-10-21 00:02:23 +00:00
Bruno-Alumn f16c6ef07f LRC-LIB-COMPARE: the Info panel labels the active photo while culling (#2398)
In Compare and Survey the selection holds both photos on screen, so the
Info panel's colour-label swatches and stars (and the Set Color Label
context menu) applied to the whole selection, while the bottom bar and the
rating/label keys act on the active photo only. They now go through
compare::target_active like the bottom bar does.

The culling panes' captions showed stars and flags but not the colour
label, so labelling there looked like it did nothing; each caption now
shows the label as a dot.
2026-10-20 23:49:03 +00:00
tylerphotosandCodex 286171e2e5 LR-IMP-ADD-DIALOG: preserve import destination album hierarchy
Reuse the shared album picker in Import Photos, retaining None/New album,
editable names, album-context preselection and existing import semantics.
Keep long paths within the viewport and cover hierarchy, localization,
keyboard choices, real imports, undo and layout regressions.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 16:41:40 -05:00
helgehelge123andClaude Opus 5.5 d1eeff9600 LR-BEHAV-LOCALIZE: say what German's 59 and its 3,754 count
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:44:36 +02:00
Roope Gröhnandcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> 89a916a31d Update docs/localization-parity.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-10-20 18:54:28 +03:00
Roope GröhnandClaude Sonnet 5.5 494d9d77bb i18n: add Finnish (fi) interface language
Adds Finnish catalogs (fi.json, fi-formats.json), the language table entry
and menu command, Finnish tests, docs and an attribution row. What's New text
stays English, as in most catalogs.

AI-assisted translation (Claude Code), reviewed by a native Finnish speaker.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 18:29:23 +03:00
fabiodalez-dev fa135940e7 i18n(it): native-speaker corrections and every interface string translated
Corrections from my review of #1198: Exposure is Esposizione (not Tempo di esposizione, the shutter time), Sharpening is Nitidezza (not Contrasto), Preset stays Preset in every preset label, and blurry photos are sfocate, not mosse.

Adds the 339 interface messages Italian lacked (print, slideshow, mask effects, faces, HDR, external editors, keywords, focus points and their dialogs) and translates the 60 format strings still in English in it-formats.json. Only the What's New lines stay in English, as before: 2,628 of 3,278 messages.
2026-10-20 16:08:27 +02:00
helgehelge123andClaude Opus 5.5 f64d9a2e3c i18n(de): speak to the user with du throughout
The German catalog mixed du and Sie. It now uses du everywhere: the 11
messages that used Sie (imperatives such as "Wählen Sie", and "Ihr Name oder
Studio") changed; "Sie" and "Ihr" that mean they and their stay.
docs/localization-parity.md records the choice for the next batch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:59:38 +02:00
helgehelge123andClaude Opus 5.5 6d5a3b02d2 i18n(de): translate the 862 What's New lines the German catalog lacked
Help → What's New now reads in German down to the oldest entry: every
wrapped line of docs/whats-new.md without a German entry has one. Dates
read DD.MM.YYYY; issue numbers, code spans, file names and link targets
are unchanged, and link texts stay English because the pages they open
are English. Each wrapped line is its own catalog key, so the German
lines break near the English line breaks. "Raw(s)" is "RAW-Datei(en)",
menu paths use →, and the text keeps the catalog's "du" form.

Held back: the 59 lines whose English text contains a ▸ menu path.
Their translations are ready (with →) and go in once #2016 (for #1950)
renames those keys; adding them now would only conflict with it.

localization-parity.md and ROADMAP.md: German re-measured with the
documented count over the catalogs, 2,572 → 3,644 of 3,754 messages
(80% → 97%). The denominator grows because German now translates
What's New lines no other catalog has; other rows keep their counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:57:40 +02:00
Matthew James SivakandClaude Opus 5.5 f08522b8a9 LR-VIEW-ZOOM: the 20 ms rule clears a slow verdict only on full-size drags (docs)
Only a drag timed at full size (median of its full-size drafts, after the
first, at most 20 ms) forgets a slow-drag verdict; a drag that drafts small
from its start, or times fewer than two full-size drafts, leaves it unchanged,
as `DragScale::finish` does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:56:48 +02:00
Davit MatchakhelidzeandClaude Opus 5.5 2015f44c06 Release: keep the web build without craft-fonts for now (its WASM would pass Cloudflare's 25 MiB limit); docs say so
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-20 12:56:17 +04:00
nevicia2010-hub ab96162e03 export: preserve graphic watermark insets when fitting 2026-10-20 09:50:18 +02:00
insideTheFluxandClaude Opus 5.5 4ea9be25b2 Gap 27: the Windows x64 installer is verified on Windows 11
The released 0.9.1 x64 MSI was tested on Windows 11 Pro 24H2 (build
26100.9711) with verbose msiexec logs. A fresh install and an upgrade
from 0.8.0 into a custom folder both end on the completion page, so
#790 is fixed (by #1569). The upgrade keeps the folder, Launch starts
the app as the signed-in user, and both removals leave nothing behind.

Uninstalling from Settings -> Apps still ends without any confirmation
(#892, #931), so that stays in the gap. Hours and percentages are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:40:21 -07:00
Claude 2c085e0ae5 LR-EDIT-DETAIL-DENOISE: check the transposed convolution's stores exactly too
A max-pool, a channel-copy 2x2 transposed convolution (mode 1) and the
channel-copy 1x1 layer give an exact answer, so a store fault in mode 1
can't hide in tolerance (CodeRabbit review of #2380).

On the GTX 1070 this test passes even without mode 1's stepped stores:
FXC merges them the same way, but the driver runs that store right, so
only mode 0 was shown wrong. Mode 1 keeps the stepped stores as a
precaution; the shader comment and docs/gpu-pipeline.md now say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:34:56 -07:00
Claude 75292874a3 LR-EDIT-DETAIL-DENOISE: GPU denoise gives the right result on DX12 with NVIDIA Pascal
On DX12, FXC merged the conv kernel's four output stores (modes 0 and 1)
into one 16-byte store_raw. The DXBC is valid and aligned, but NVIDIA's
driver ran it wrong on a GTX 1070: every second pixel's channels came
out shifted, so AI Denoise on the GPU was silently wrong on Windows.
DXC and Vulkan were right on the same card.

The stores now step by `1 + p.zero` (the always-0 uniform, renamed from
`pad`), which FXC cannot fold, so it keeps them apart. A two-layer
channel-copy network checks the stores exactly; it fails on that card
without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:54:24 -07:00
Andrew FrahnandClaude Sonnet 5.5 6b4c192195 Strict proof equivalence check without warnings, tolerant warned count; fix zoom docs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:06:07 +11:00
Andrew FrahnandClaude Sonnet 5.5 e09e91f890 Move the dated LR-IMP-FORMATS entries from the checklist table to the revision history
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:06:04 +11:00
Andrew FrahnandClaude Sonnet 5.5 376ad8177d Review: correct ColorTemperatureAuto tag id, dedupe relative-scale text
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:03:36 +11:00
Andrew FrahnandClaude Sonnet 5.5 a5a4b64ec6 Review: fluorescent accuracy bound 5 %, drop stale relative-scale text
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:03:32 +11:00
Andrew FrahnandClaude Sonnet 5.5 131de8cccd Merge upstream/main into pr/overlay-windows (#1027 landed)
GPU handles(): only output-device proofs stay on the CPU; Show All Masks now renders zoom windows (upstream); proof-boundary tolerance in the GPU equivalence test; device-profile draft test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 10:57:07 +11:00
Andrew FrahnandClaude Sonnet 5.5 52c4ec6649 Restore LF line endings
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 10:09:11 +11:00
Andrew FrahnandClaude Sonnet 5.5 e2b56367db Merge upstream/main; KEY-SLIDER-TYPE: keep the long-click fix only (scrub landed in #1604)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 10:06:35 +11:00
Andrew FrahnandClaude Sonnet 5.5 5e1bac1264 Merge upstream/main into pr/longtail-raws
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 09:58:17 +11:00
Andrew Frahn 522e29919d Merge remote-tracking branch 'upstream/main' into pr2006-fix 2026-10-20 09:42:25 +11:00
Andrew FrahnandClaude Sonnet 5.5 041f91d1cc Fix raw-parity merge markers
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 09:20:10 +11:00
Andrew FrahnandClaude Sonnet 5.5 b2a58e8f33 Merge upstream/main into canon-colordata-kelvin
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 09:19:53 +11:00
Ted Mao 67fa3dbb26 Merge branch 'main' into low-memory-guided-filter 2026-10-19 10:44:36 -07:00
Arekatla Nishanth ChowdaryandClaude Opus 5.5 3a6e7d0b9b Merge main into feat/1449-people-search; people and quotes go through text_matches (#2099)
Review on #1468: main's #2099 split out text_matches() and lets unknown field
prefixes fall back to plain text. On top of it, text_matches() now also matches
Photo::people(); the free-text token is unquoted before text_matches(); an
unknown field's quoted value is unquoted in the fallback (`10:"30 am"` is the
text `10:30 am`); and the field split keeps the !t.starts_with('"') guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:18:49 +05:30
Alvaro Gonzalez-JimenezandClaude Opus 5.5 c782bf6a85 #2312: culling goes on from a photo rated out of the view
With a filter showing one-star photos, taking the star off a photo took it
out of the view but left it the active photo: the grid highlighted nothing,
Detail kept showing it, and the next step (→, Shift+0–5 or Auto Advance)
started from the view's first photo, because `library.next` finds no place
in the view for an active photo the view doesn't show.

A rating, flag or label applied to the selection now does what a delete
already does when it takes the active photo out of the view: the photo after
it becomes active (the one before it at the end). That photo is the next one,
so `advance`, Shift+key and Auto Advance (keys and the Photo menu) don't step
past it. Commands that name their photos with `ids` leave the selection
alone, so Compare and Survey still show the photo they rate; a held view
keeps the photo, and the selection with it.

photo.pick, photo.reject, photo.unflag and photo.label now take `advance`
like photo.rate and photo.flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:33:22 +02:00
Davit MatchakhelidzeandClaude Opus 5.5 04e11e701a docs: Georgian draws with craft-fonts' Noto Sans Georgian; the web WASM keeps the Japanese, Thai and Georgian faces
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-19 18:13:10 +04:00
Claude 82a703111e #2267: the Before label stays in view when zoomed in
Zoomed in, the photo's corner is off the canvas, and the "Before" label
(\ key or the Before view) left the screen with it. The label's pill now
sits at the canvas' corner when the photo reaches past it, on whichever
axes it does; at Fit nothing changes. Same rule for the hovered preset's
name. Stacked on #2274 (the dark pill behind the label, same lines).

Tests: the pill geometry with the photo inside and past the pane, and a
headless check that at 100 % the registered label rect stays inside the
canvas.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-19 13:09:20 +00:00
Claude e2ea657668 #2114: hidden Local locations come back one at a time
"Show N hidden locations" put every location removed from Local back at
once. With several hidden, the row now lists them (name, path on hover):
each comes back on its own, or all with Restore All. With one hidden, the
row restores it directly, as before. The command side already had
local.restoreHidden {path}; only the panel called it without a path.

The headless test hides a second place, opens the list from the row,
restores one, checks the other stays hidden, then restores the rest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-19 11:29:48 +00:00
sanyamsingh001andCodex 30cdb4b1c4 LR-VIEW-PHOTOGRID: preserve embedded previews through priority changes and Undo
Queued embedded grid-preview requests now change priority without restarting their work. Undo to an embedded preview retires obsolete thumbnail requests so a late edited render cannot replace the restored preview.

Partially addresses #348.

Co-authored-by: Codex <codex@openai.com>
2026-10-19 19:33:20 +10:00
Matthew James SivakandClaude Opus 5.5 5690afe51a Gap 9: cargo xtask ci on every PR (Linux x64); ci --quick; one local ci at a time
- .github/workflows/ci.yml: the full `cargo xtask ci` on every pull request and push to main
  (Linux x64, craft-fonts, rust-cache for dependencies), so it becomes the merge gate.
- `cargo xtask ci --quick [--base REF]`: fmt, clippy, the changed packages' tests, layers and
  assets, plus heif / parity / wasm when the changes touch them, measured against the merge base
  with origin/main (xtask/src/ci_quick.rs). Workspace-wide files test everything.
- A machine-wide lock (xtask/src/ci_lock.rs): a second `ci`, from another worktree, waits and
  names the run it waits for. LIGHTCRAFT_CI_SLOTS=N, LIGHTCRAFT_CI_LOCK=off|<dir>.
- README, CLAUDE.md quality gate, gaps.md gap 9, target-app-parity.md stability note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:59:30 +02:00
helgehelge123andClaude Opus 5.5 3e163f3f3d LRC-LIB-LIBFOLDERS: the sidebar trees narrow their indent step before names are cut (#2298)
Every level of Albums, Local, By Date, Folders and Keywords still steps one
level right of its parent, but the step is chosen each frame from the panel's
width and the deepest open row: 16 pt while that row keeps about 80 pt for its
name and room for its count, else 14, 12, 10 or 8 pt. Past 8 pt the sidebar
scrolls sideways as before. Callers keep passing indents in 16 pt steps;
`indent_x` maps them to the drawn step for the icon, name, chevron, album drop
line and the width a row asks for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:51:31 +02:00
Matthew James SivakandClaude Opus 5.5 58c38ead2f LR-VIEW-ZOOM: describe the slow-drag verdict as per photo and control
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:13:51 +02:00
helgehelge123andClaude Opus 5.5 35be24bcbe LR-LIB-STACK: note the filmstrip badge click in the parity checklist
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:11:27 +02:00
Matthew James SivakandClaude Opus 5.5 0360f940e3 Merge main into lightroom-jxl-dng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 08:33:20 +02:00
Reva Doni AprilioandClaude Opus 5.5 61402815b5 docs: gaps header for gap 21; Indonesian parity counts messages only
Address review: gaps.md's header and history record the 2026-10-19 gap 21
change, and the Indonesian parity row counts the 2,555 catalog messages,
with the 69 command labels noted separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:26:32 +07:00
Reva Doni AprilioandClaude Opus 5.5 822c6ed101 docs: Indonesian in the key-languages tables and the localization headline numbers
Address review: the twelve-key-languages row for Indonesian still read 0%
while the shipped table listed it, and ROADMAP repeated it under Also
shipped. Indonesian is a key language, so it moves to its row (100% but
What's New) and out of the other-languages table (back to 4). Localization
mean of the 12 key languages ~55% -> ~64%, 8 of 12 present; the new-script
estimate drops Indonesian (135-239 h); the full-target weighted sum moves
61.2% -> 61.5% (still ~61%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:07:58 +07:00
Reva Doni AprilioandClaude Opus 5.5 816a1112e3 i18n: Indonesian (id) interface language
Adds crates/ui-egui/locales/id.json and id-formats.json: every plain
(2,258) and formats (297) message any catalog has, plus 69 command
labels no catalog translated yet. What's New stays in English.

Indonesian keeps a noun unchanged after a count, so English plural
suffixes are consumed with {:.0}; dates read "Minggu, 20/09/2026".
Menu triangles use → and ⌄ like the other catalogs. 356 labels reuse
the sibling apps' Indonesian wording (PhotoCraft, VectorCraft,
FilmCraft, FigCraft) so the suite reads the same; credited in
ATTRIBUTION.md.

Registers Locale::Id ("Bahasa Indonesia", Latn), the
app.language.indonesian command, the keyword-list catalog check and
an Indonesian switch/persist/format/date test. Docs: localization.md,
localization-id.md, localization-parity.md, ROADMAP.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:17:59 +07:00
chordpli 266e668376 LR-LIB-STACK: a double-click on a stack badge toggles the stack once (#2233)
A click on a grid stack badge expands or collapses the stack. A double-click,
as in Lightroom, toggled it twice: the second click undid the first and the
stack stayed as it was. The badge now ignores the second click of a
double-click.
2026-10-19 09:05:04 +09:00
helgehelge123andClaude Opus 5.5 7f2375458c LR-LIB-CULL: adjustable burst gap and similarity in Assisted Culling (#2275)
photo.analyze takes burstGap (seconds, 0..86400, default 10) and
similarity (0..1, default 0.93); values out of range are refused before
anything is measured. The Assisted Culling dialog gets both sliders and
remembers them for the session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:06:56 +02:00
Claude 81f02a6947 #2253: crop ratios keep the orientation asked for
set_aspect always turned the ratio to the image's orientation, so a Custom
ratio taller than wide came out landscape on a landscape photo, and a
ratio picked after X (crop.rotateAspect) turned the crop back. A named
ratio now takes the crop's present orientation (landscape, or portrait
after X; a square crop follows the image), a custom [w, h] is used as
given, and crop.aspect takes orientation: "crop" | "given" to choose.
The window reapplies the remembered ratio to an untouched photo with
orientation "crop", as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-18 22:48:56 +00:00
Claude 55b7b47925 #2242: reverseGeocode maxDistance, and the 15 000-people limit is documented
GeoNames cities15000 holds towns of 15 000 people or more, so a photo in a
smaller town got the nearest larger one in City (Portofino → Rapallo,
5.3 km), another municipality. metadata.reverseGeocode takes maxDistance
(metres): past it, City and Sublocation stay empty, State and Country
still fill, and the reply names the town as nearestCity. Hostile values
are refused. The command help, the Fill Location tooltip and the parity
row say what the list holds. Default unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-18 20:13:25 +00:00