Commit Graph
501 Commits
Author SHA1 Message Date
Nathaniel LedfordandClaude Opus 5.5 31abbcee4f LRC-LIB-SMARTCOLL: rename and rules of a smart album in one step
The rule editor renamed an album (album.rename) and then set its rules
(album.setRules) as two commits. If the second failed (refused rules
before the dialog checked them, or a save error), the album kept the new
name without the rules, and undo needed two steps.

album.setRules takes an optional `name` (blank keeps the album's) and
commits the rename and the rules as one Op::Batch: both or neither, one
undo step. The dialog edits through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:57 -04:00
Nathaniel LedfordandClaude Opus 5.5 920658c76d LRC-LIB-SMARTCOLL: rule editor never rewrites a rule by drawing it
From review: the number spinner was fixed, but the "in the last" spinner
still clamped a stored N on first draw ("0 days" became 1, hiding the
problem and saving a different rule; 20,000 became 10,000). Values
that weren't an {n, unit} object or a two-item "between" were replaced
by the defaults as soon as they were drawn.

- In the last: shown as stored ({n, unit}, any case, or a plain number
  of days) and written only when the N or the unit is changed, with
  clamp_existing_to_range(false).
- Between: anything but a pair is shown as the default pair but kept
  until one bound is edited, so the check marks it. A slice pattern
  replaces the [0] / [1] indexing.
- Album picker: reads the id as the catalog does; names albums with
  their folder ("Trips / Rome") and sorts them by name.
- Opening an album's rules applies RuleSet::upgrade.
- New tests: drawing leaves five unreadable values as stored and marks
  the three that can't match, and an edit with bad rules doesn't rename
  the album (neither OK nor confirm). The parity note no longer
  overclaims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:57 -04:00
Nathaniel LedfordandClaude Opus 5.5 7b7807b499 LRC-LIB-SMARTCOLL: rule editor marks bad rules, blocks OK and picks albums from a list
The dialog showed only the first problem, in place of the match count,
without saying which rule it was about. OK stayed clickable, and an
edit renamed the album before its rules were refused.

- Each rule with a problem gets the message right under its row, in the
  caution colour; inside groups too, and on an empty group's frame. The
  rules_editor::Env carries the problems from RuleSet::check, and each
  row finds its own by path. Markers register `ruleProblem:<salt>`.
- The summary reads "Fix the marked rules to save this album." and OK is
  disabled while any problem remains.
- confirm_dialog refuses problems before anything changes (not even the
  name), and the control channel's ui.dialog.confirm keeps the editor
  open on that error, as the button does.
- Album is its own field kind: is / isn't only (it was a number field
  that offered ≥ and between). It picks its album from a list of the
  plain albums (`ruleAlbum:` / `ruleAlbumItem:<id>:`) and starts with
  none chosen ("choose an album"). album.ruleFields reports kind "album".
- Found while testing: the number editor's spinner clamped a stored
  value outside its range as soon as it was drawn, so "Rating is 9"
  quietly became "Rating is 5". It now uses
  clamp_existing_to_range(false): the range limits dragging, and a
  stored value stays as it is, marked by the check.

New labels (Choose an album…, No albums yet, Fix the marked rules…) are
translated in all seven locales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:57 -04:00
Nathaniel LedfordandClaude Opus 5.5 b5fe62e426 LRC-LIB-SMARTCOLL: check every smart-album rule value against its field
RuleSet::problems only checked that a field and operator exist (and,
lately, yes/no values). Any other value was accepted and silently
matched nothing or everything: "Rating ≥ abc", a date of "banana" or
"2026-13", "Color Label isn't pink" (everything), "Title contains ''"
(everything), "in the last 0 days", an album that is gone.

RuleSet::check(&Catalog) -> Vec<Problem> replaces it. Each Problem has
the rule's position (path [1, 0]; shown as "rule 2.1: …"), so the
editor can point at the row. It checks:
- numbers (rating 0–5), shutter speeds (1/250, 2)
- dates: 2026, 2026-08, 2026-08-14 or a full time; real dates only
- between: two bounds; dates in order (2026-08-14 … 2026-08 is fine)
- in the last: N > 0 and a known unit
- choices: the ids, the flag's picked / rejected, a colour label's
  custom name (from the catalog), copyright-status spellings
- text and keyword / people rules: something to look for, or "is empty"
- album: exists and is a plain album
- no empty groups (an empty rule list at the top stays "all photos")

album.createSmart, album.setRules and library.filter report every
problem. The editor's date defaults move from "" (which, as "between",
matched every dated photo) to the current year, and its test now
requires every default to be valid, except text and album rules, which
wait for input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:57 -04:00
Nathaniel LedfordandClaude Opus 5.5 65516b721c LRC-LIB-SMARTCOLL: Japanese yes/no field labels are plain nouns
With the values now あり / なし, the labels "Has Edits" (編集あり) and
"Has GPS" (GPS情報あり) read "edits: yes … none". They are only
used as smart-album field labels, so they become 編集 and GPS情報 ("編集 …
あり / なし"). The untranslated In a Stack and Cropped become スタック and
切り抜き. A test requires every yes/no field to have a Japanese label
without あり / なし.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 c42fc7ac24 LRC-LIB-SMARTCOLL: Japanese yes/no rule values read あり / なし
Yes/no rule values used the shared "Yes" / "No" messages, which
Japanese translates as the answers はい / いいえ. As the value of a
condition ("編集あり … いいえ") that reads oddly; あり / なし ("has" /
"has none") is natural.

Messages are keyed by their English text, so the same English word
can't carry two Japanese translations. A small context lookup fixes
that: tr_ctx_in tries "<context>|<source>" first and falls back to the
plain message. Only ja.json adds "smart album value|Yes" / "|No"; the
shared Yes / No (はい / いいえ) stay as they are elsewhere, and every
other language keeps its plain Ja / Sí / Да. A test rejects contextual
keys that name no real value, so a typo can't silently fall back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 fa982a4cc6 LRC-LIB-SMARTCOLL: rule editor keeps an unreadable yes/no value
From review: the editor rewrote a yes/no value that was neither yes nor
no (written by an agent or an older version) to true on every frame, so
the dialog never showed the problem and OK silently saved "Yes",
turning a rule that matched nothing into one that matches. The dropdown
now shows such a value as written and changes it only when the user
picks Yes or No. Until then the dialog reports the problem and OK
refuses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 7d3c61c56b LRC-LIB-SMARTCOLL: yes/no rule values read Yes / No and mean what they say
Yes/no fields (Has Edits, Cropped, Has GPS, Virtual Copy, In a Stack,
Best of Similar Shots) showed "true" / "false" in the editor and
summaries, and Russian had no translation for either. Matching read the
value with as_bool().unwrap_or(true), so an agent's "false" (a string)
or any other non-boolean counted as yes, while the summary said
"false".

- catalog: bool_value is the one reading. true / "yes" / "true" / 1 /
  no value mean yes; false / "no" / "false" / 0 mean no (strings in any
  case). Anything else matches nothing, and RuleSet::problems reports it
  ("`edited` is yes or no, not \"maybe\""), so album.createSmart and
  setRules refuse it. bool_label gives "Yes" / "No"; describe() reads
  "has edits is yes".
- ui: i18n::bool_text for the editor's dropdown and translated
  summaries (Ja / Nein…, existing keys in all locales). The editor
  stores the value back as a plain boolean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 4c826246c3 LRC-LIB-SMARTCOLL: own labels for treatment Color and label None
From review: the treatment choice "Color" reused the shared "Color" key,
which zh-hans and ru translate as the colour noun (颜色, Цвет) for the
Color panel, giving "Treatment is colour". The colour-label choice
"None" was masculine in Spanish (Ninguno) next to the feminine
"etiqueta". They are now "In Color" and "No Label", translated in all
seven locales (彩色, Цветное, Sin etiqueta…).

Also moves display_label_gaps_are_reported's doc comment back onto it;
the new choice test had been inserted between them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 12e1105861 LRC-LIB-SMARTCOLL: readable, translated labels for smart-album choice values
Choice values showed their rule ids in English ("Copyright Status is
publicDomain", "Treatment is monochrome"), and Russian had no
translation for any of them. Kind::Choice now carries (id, label) pairs
like the operators: rules still store and accept the ids, and people
see the labels.

- catalog: choice_label(field, id); RuleSet::describe uses the label
  ("copyright status is public domain").
- engine: album.ruleFields keeps `choices` as ids and adds
  `choiceLabels` {id: label}. A test pins the ids, since the new tuple
  type would otherwise serialize as pairs.
- ui: i18n::choice_text is the one path for the editor's value dropdown
  and translated summaries. Aspect labels are "Landscape (wide)" /
  "Portrait (tall)", because the existing "Landscape" / "Portrait" keys
  mean scenery and people. Seven locales gain Video, Copyrighted, Public
  Domain, Unknown, the aspect labels and Square (ru also Raw). A test
  requires every choice label to be translated in every language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 6b46c98654 LRC-LIB-SMARTCOLL: stronger rule-editor tests
The field-menu UI test now clicks a group row instead of hovering it,
guarding against the combo popup closing on that click (touch input,
fast clicks). default_values_make_valid_rules now checks each default
value's shape (none, pair, choice, number, a real shutter time) as its
earlier commit message claimed; before, it only checked operators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 5fa77aa878 LRC-LIB-SMARTCOLL: file, size, location, description and develop rules
New smart-album fields, each in its menu group:
- Source: Copy Name, In a Stack
- File: File Extension (case and leading dot ignored), Video Duration
- Description: Alt Text
- Location: City, State / Province, Country (Location still matches all)
- Size: Long Edge, Short Edge, Aspect Ratio (landscape / portrait /
  square within 1 %), measured on the photo as shown (oriented and
  cropped)
- Develop: Cropped (crop or straighten), Treatment (color / monochrome)

Photo::extension, Photo::shown_size and Photo::is_cropped hold the
domain rules. A crop rectangle that is NaN or outside the frame is
clamped, so hostile settings can't produce NaN sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 9101757bfb LRC-LIB-SMARTCOLL: Shutter Speed rule
Camera Info gains Shutter Speed, compared in seconds and written as the
camera shows it: "≤ 1/60" finds faster exposures, "between 1/1000 and
1/125" works, and a value that isn't a time matches nothing. The editor
takes it as text (1/250, 0.5, 2").

The shutter parser moves from engine export into the catalog
(parse_shutter_seconds) so export and the rule share it. A new
rules-editor test checks that every field × operator default value
makes a valid rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 e54acbd176 LRC-LIB-SMARTCOLL: Keyword Count, People and People Count rules
Smart albums can test how many keywords a photo has ("2 or more", "2 or
fewer", "exactly 2" via the number operators), who is in it (People: the
names on face regions, with the keyword operators) and how many people.

Photo::keyword_count counts a hierarchical keyword once and ignores case
and blank entries; Photo::people is the domain rule for "people in a
photo" (named face regions, trimmed, case-insensitive, pets and unnamed
faces excluded), now shared by the existing person filter. Keyword and
people rules share one name-list matcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Nathaniel LedfordandClaude Opus 5.5 8c0b70b37f LRC-LIB-SMARTCOLL: field menu with submenus in the rule editor
The rule editor's field dropdown shows Rating, Pick Flag, Color Label and
Any Searchable Text at the top, then a separator and one submenu per
field group instead of one long flat list. The group holding the current
field is shown in bold. Picking a field from a submenu closes the menu
and keeps the operator only when the new field has it. Widget ids
ruleField / ruleFieldGroup / ruleFieldItem let the control channel drive
it, and group names join the i18n display-label gap report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:54:56 -04:00
Elliot GrahamandCodex b9f951998f #491: Keep Local import headers within the centre pane
Co-Authored-By: Codex <noreply@openai.com>
2026-10-09 12:08:11 +01:00
Brandon ThomasandClaude Opus 5.5 7dcfbed05c LR-EDIT-DETAIL-DENOISE: list settings tabs from TABS; fix the SAM 3 worker's wasm check
The unknown-tab error now names every Settings tab (it missed AI Denoise after the
faces merge). lightcraft-sam3-worker (#359) only builds its server off wasm32, so
`cargo xtask wasm` passes again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:07:43 -04:00
Brandon ThomasandClaude Opus 5.5 1e1eb5fe16 Merge origin/main (batches 14 and 15) into AI RAW denoise (#384)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:30:17 -04:00
Brandon ThomasandClaude Opus 5.5 c65065de2f Merge the faces stack (#172/#173/#174, integrate-batch-14) into AI RAW denoise (#384)
One config-dir helper (engine::config::config_dir; camera_profiles re-exports it) with both
the face-models and denoise-models defaults; hosts set up both model folders; Settings has
Faces and AI Denoise tabs; both command sets registered; both model dialogs; locale entries
from both; one [features] table per app manifest; Cargo.lock regenerated by cargo; the
DecodedSource cache cost counts both segmentation mattes and the denoised twin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:29:59 -04:00
Brandon Thomas 7365d06c13 Merge PR #359 2026-10-09 00:17:59 -04:00
Brandon Thomas ab73d3d2e0 Merge PR #423 2026-10-09 00:17:58 -04:00
Brandon Thomas cae7bea08e Merge remote-tracking branch 'origin/main' into fix-359
# Conflicts:
#	crates/engine/src/segment/worker.rs
2026-10-08 23:57:36 -04:00
Brandon Thomas ca97329ae1 Merge PR #174 2026-10-08 23:45:49 -04:00
Brandon Thomas 3368eb49ee Merge PR #173 2026-10-08 23:45:49 -04:00
Brandon Thomas cbf9935b6e Merge PR #172
# Conflicts:
#	docs/parity.md
2026-10-08 23:45:49 -04:00
Brandon Thomas 91d317900f Merge PR #395 2026-10-08 23:22:56 -04:00
sanyamsingh001andCodex 56754e5703 LR-BEHAV-HEADLESS: keep CPU snapshots isolated from saved preferences
Co-authored-by: Codex <codex@openai.com>
2026-10-09 13:19:47 +10:00
Brandon Thomas 1a2d2ab975 Merge PR #422 2026-10-08 22:43:10 -04:00
Daniel Voshart 111cc893ec LR-LIB-PEOPLE: preserve later person navigation on current main
Port the original Escape return and last-person shortcut behavior, keeping current translations and a no-wrap chip. The existing headless regressions and all seven quality gates pass with the hosted fonts on the refreshed recognition dependency chain.

Generated with Codex.
2026-10-08 22:29:31 -04:00
Daniel Voshart 24f87a91a0 LR-PREF-PEOPLE: update pure-Rust recognition and preserve valid model replacements
Keep current upstream UI behavior and the later detector contract checks. Validate candidate models before replacing working weights and records, with a synthetic regression that failed before the fix. Remove the unrelated GPU equivalence-test relaxation. All seven quality gates pass with the pinned hosted fonts.

Generated with Codex.
2026-10-08 22:29:31 -04:00
Daniel VoshartandClaude Opus 5.5 20a801d6d2 Faces: YuNet face detection and one-click model downloads, with nothing bundled
Photo > Detect Faces runs the YuNet detector (a small pure-Rust interpreter over the ONNX graph, no
runtime dependency) and adds the faces it finds as unnamed face regions in one undo step. The detector
and the recognition models are opt-in downloads: Settings > Faces shows each model's licence and
training-data note, Download stays disabled until the terms are accepted, and the file is fetched over
https with lightcraft-fetch from the model's own repository at a commit-pinned address, checked against
its recorded size and SHA-256 and then installed. Detect Faces offers the detector's download the first
time it is used. No model file is part of the repository (the real-model tests read LC_YUNET_MODEL; two
ignored tests download from the real hosts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:29:30 -04:00
Daniel Voshart fd4019300a LR-EDIT-DETAIL-DENOISE: address installation and model-policy review
Generated with Codex.
2026-10-08 22:07:23 -04:00
7935999d94 LR-EDIT-DETAIL-DENOISE: non-destructive AI RAW denoise with pure-Rust CPU/GPU
Recover the unpublished denoise work against current upstream. Preserve later opt-in model setup, shared Rust HTTPS downloads, pending-photo resume and an Amount-independent switch. Keep original RAWs unchanged and share the current color finish between ordinary and denoised sources.

Bound public tiling inputs, refuse corrupt-cache exports, and retain synthetic/real-model coverage. Include two Windows path spelling fixes in existing tests. No model weights, face code, media or Tract runtime are included.

Validation: cargo xtask ci (all seven gates); installed RawNIND CPU/GPU agreement 1.38e-6; native CPU preview/export on a public 24 MP Sony RAW, unchanged original SHA-256.

Co-authored-by: Codex <noreply@openai.com>

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

Generated with Codex.
2026-10-08 22:07:20 -04:00
Daniel VoshartandClaude Sonnet 5.5 7845d515e8 Faces: nothing is bundled, so YuNet is not reported as installed
The model list marked the YuNet detector as bundled with LightCraft and installed, but no model ships
inside LightCraft (the weights are opt-in downloads or files the user adds). Drop the notion: a
model is installed when its folder is, it can be removed like any other, and the licence notice no
longer says it is bundled.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:59:02 -04:00
Daniel VoshartandClaude Sonnet 5.5 cb34bb4842 Faces: Settings > Faces tab and the add-a-model licence dialog
An off-by-default "Recognise faces" toggle and the face model list in Settings,
with a one-drop install: pick a .onnx (Add a model file…) or drop one on the
window. The engine inspects it (recognised by hash, or described from its
shape), a dialog shows its licence, whether commercial use is allowed, what it
was trained on and what LightCraft had to assume, and Install stays disabled
until "I accept" is ticked. "Get…" opens a model's own page in the browser:
LightCraft never fetches a model itself. A file it cannot use says why.

The models folder is shared by the app, the CLI and the MCP server
(`engine::config`, `$LIGHTCRAFT_FACE_MODELS` overrides `<config>/models`), so a
model installed from one is there for the others. A session has none until a host
asks (`with_default_face_models`), which keeps tests hermetic.

Nothing runs a model yet, and the tab says so. Headless tests cover the whole
flow (the dialog, refusing until accepted, installing, a file it cannot use).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:59:01 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 8ff45f5237 Sidebar: dragging albums or photos near its top or bottom edge scrolls it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 24b80b4ee3 Albums: the Albums header is the way back to the top level
It replaces the strip under the tree, which could be scrolled out of view
and shifted the rows when it appeared; the header is always visible and
nothing moves.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 085c25b10b Albums: drop beside a row to place it by hand; Sort A–Z goes back to by name
Dropping on the edge of a row places the album there (album.reorder) with
a line showing where; a folder's middle still means inside. A closed folder
opens only when the drop would go inside it. Sort Contents A–Z and Sort
Albums A–Z (album.sort) appear once a folder is ordered by hand.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 67aed0b4f4 Albums: a drag ends with the main button, Esc cancels it, hidden rows are no targets
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 aaae39fae0 Albums: drag an album or folder onto a folder to move it
A folder under the pointer is outlined when the drop is allowed and opens
after resting there; a drop zone under the tree takes an album back to the
top level. The move is album.move, so it is one undo step.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 5443ae28f9 Albums: address review of folder creation
Show a dialog's error and keep it open instead of closing it, open the
folder menu from the triangle too, draw a triangle only on folders that
hold something, reveal even when the section is folded, reuse the
translated Create … labels, and fix a misplaced doc comment.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:06 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 79403a5680 Albums: create albums, smart albums and folders inside a folder from its context menu
The dialog.new* commands take the folder to create in, the dialogs
remember it, and the Albums tree opens the folders down to the new row.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:06 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 96a9c6e04d Albums: folders get the same disclosure triangle as the other sidebar trees
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:06 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 e8b18ae636 Sidebar: one disclosure-triangle helper for the Local, By Date, Folders and Keywords trees
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:06 -04:00
Claude 12188161f9 Merge remote-tracking branch 'origin/main' into integ-b13 2026-10-09 00:46:05 +00:00
radialmonster caa102aabd MENU-BAR: pointing at another menu title switches the open menu in the in-window bar 2026-10-08 20:40:46 -04:00
Claude 43419dcfb8 Merge PR #411 2026-10-09 00:20:26 +00:00
Claude eab88ea30c Follow-up to #351: drag drafts without a window stay canvas-sized; de/es/ru hint
- With no window (a mask or point-colour overlay, Visualize Spots, soft
  proofing, a window refused for a far read) the loupe renders the whole
  frame at the size it is drawn. While a slider drags that meant the
  photo's every pixel each draft frame at 1:1 and beyond (24 MP per tick
  where 2.5 MP was rendered before #351; mask overlays are on by
  default). A drag now drafts at most the canvas size, as the windowed
  path does; at rest the zoomed frame is rendered as before.
- The Preview size hint in German, Spanish and Russian; the replaced
  'Largest long edge…' text removed from those catalogs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-09 00:16:01 +00:00
Claude 3e88a60dd6 Merge PR #351 2026-10-09 00:14:03 +00:00
ragtuxandClaude Fable 5.1 0cf3ceb438 Part of #260: Help ▸ Open Log Folder shows the log file in the file manager
The desktop app keeps logs/lightcraft.log in its settings folder (#286)
and a failed start names it (#370), but a user still had to find the
folder by hand. The host now hands the UI its log file (Services
.log_file) and Help ▸ Open Log Folder (app.openLogFolder) reveals it
through the existing reveal service: Finder and Explorer select the
file, Linux opens the folder. Off where no log is kept (the web,
--memory, LIGHTCRAFT_NO_PREFS). Translated in de, es, ja, pt-br, ru,
zh-hans and zh-hant; parity row MENU-HELP-LOGFOLDER; What's New and
README note it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 19:13:35 -05:00