Commit Graph
4107 Commits
Author SHA1 Message Date
DUY Tran Nhat (SAE-KIDS) 462c47dc73 i18n(vi): translate effects and tone controls 2026-10-13 15:54:00 +07:00
DUY Tran Nhat (SAE-KIDS) 67722fb637 i18n(vi): translate light and color controls 2026-10-13 15:54:00 +07:00
DUY Tran Nhat (SAE-KIDS) 1fb7bad093 i18n(vi): translate import workflows 2026-10-13 15:54:00 +07:00
DUY Tran Nhat (SAE-KIDS)andCursor 662ddbd2a6 i18n(vi): translate organization and metadata workflows
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 15:45:32 +07:00
DUY Tran Nhat (SAE-KIDS)andCursor 815febed6a i18n(vi): translate library and photo navigation
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 15:43:54 +07:00
DUY Tran Nhat (SAE-KIDS)andCursor 2247b9a386 i18n(vi): translate app shell and navigation
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 15:42:57 +07:00
PiMinusMaxandClaude Opus 5.5 0d13a7d5d7 M5.6: a full-size raw source is no longer copied once more after the colour model
`fit` to the source's own size copies the whole picture (`resize` returns a clone). The raw path
called it unconditionally, so every full-size decode (an export, and its denoised twin) made a
second float RGB buffer: 288 MB and 160 ms at 24 MP, ~390 MB and 225 ms at 33 MP. The JPEG and
preview paths in the same file already fit only when the picture is larger than `max_edge`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:27:54 +02:00
witkowski01andClaude Opus 5.5 488edec6c8 i18n(pl): plural forms, the messages main gained, and paintable menu arrows
Fixes for the Polish catalogs of #1100, on top of a merge of main:

- English plural suffixes ("s"/"") and the "it"/"them" words in 51 format
  messages are now consumed with `{:.0}`, as docs/localization.md asks;
  Polish showed "Zaimportowano 5 zdjęćs" and "utracisz they are". The
  counts read "Zaimportowane zdjęcia: 5", which is right for every number
  (Polish has three plural forms; ru and uk use the same pattern).
- The 19 format messages main gained since the translation was written;
  without them the build fails.
- 118 plain messages the other catalogs already translate.
- "▸" and "▾" in translations become "→" and "⌄", as the other catalogs do
  (translated_catalogs_do_not_use_missing_menu_triangles).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:27:09 +02:00
PiMinusMaxandClaude Opus 5.5 b36b0d14b7 KEY-SLIDER-NUDGE: scrolling sideways over a slider adjusts it
A trackpad swipe, a tilting wheel or Shift+wheel over a Develop slider nudges it by the
wheel/arrow-key steps, without selecting it first (the right panel only scrolls vertically).
Only a mostly sideways movement counts, so scrolling the panel leaves the sliders alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:10:24 +02:00
natocool2andClaude Opus 5.5 7a90a9e2c2 Bump quick-xml to 0.41 (RUSTSEC-2026-0194, RUSTSEC-2026-0195)
RUSTSEC-2026-0194 (quadratic duplicate-attribute check) and RUSTSEC-2026-0195 (unbounded NsReader
namespace allocation) are fixed in quick-xml 0.41. lightcraft-meta and lightcraft-lensdb already read
attributes with with_checks(false) (and #687 keeps xmp_merge strict in linear time) and do not use
NsReader, so neither is reachable today; the bump clears the advisories and leaves one copy
(wayland-scanner already locks 0.41.0). No source changes needed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 09:07:49 +01:00
witkowski01 5d981c2c68 Merge main into the Polish translation 2026-10-13 10:04:35 +02:00
radialmonster 4f51f051e7 LR-RAW-NEF: only take the NRW block's white balance where the as-shot kelvin is mirrored (P7000); P7100 gets none 2026-10-13 04:03:59 -04:00
dev-null-undefinedandClaude bc1f138ee3 Perf: ARW6 decode another 20-34 % faster, same samples
- The two halves of each stream are independent bit streams: they now decode in parallel
  (`decode_stream`) instead of one after the other inside each of a tile's 13 streams.
- The vertical inverse 5/3 runs its rows in parallel. The horizontal pass lifts each row in place
  (`lift_row`, scratch space reused per thread), rows in parallel, instead of allocating two vectors
  per row and copying the result back; a test checks it against the vertical pass, row by row.

Best of 3 on 4 CPUs, previous and new decoder alternating: ILCE-7RM6 FF HQ 0.60 → 0.48 s
(process CPU 1.14 → 0.87 s), FF Compressed 0.62 → 0.48 s, APS-C HQ 0.34 → 0.23 s, APS-C
Compressed 0.31 → 0.24 s (docs/arw6-compression.md → Timings). The decoded mosaic is identical
(hash of every sample) on the 8 ARW6 files of the RawDB ILCE-7RM6 set and 3 private A7R VI photos.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 10:00:33 +02:00
dev-null-undefinedandClaude Opus 5.5 79ab54e167 Perf: ARW6 decode 20-33 % faster, same samples
- The vertical inverse 5/3 lifts whole rows at once (`inverse_lift` with samples `w` values wide)
  instead of gathering each column through a strided iterator and scattering it back: the same
  integer arithmetic, sequential memory. The horizontal pass is the same function with w = 1.
- `0^n 1` codes are counted with one `leading_zeros` over the next MAX_DPT + 1 bits instead of bit by
  bit (same bits consumed, same errors); each line reserves its values up front.
- Colour reconstruction reads plane rows as slices and runs over rows in parallel (it was one
  thread per tile: 4 threads on a full-frame file whatever the machine).

Best of 5 on 4 CPUs, previous and new decoder alternating: ILCE-7RM6 FF HQ 0.56 → 0.46 s,
FF Compressed 0.54 → 0.38 s, APS-C HQ 0.34 → 0.23 s, APS-C Compressed 0.35 → 0.24 s
(docs/arw6-compression.md → Timings). The decoded mosaic is identical (hash of every sample) on
the 8 ARW6 corpus files and 2 private full-frame photos (ISO 100, ISO 12800); the pinned corpus
sums still match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:00:33 +02:00
dev-null-undefinedandClaude Opus 5.5 f407813569 Perf: AHD demosaic 1.7× faster and 0.8 GB lighter on a 64 MP raw, same pixels
Three changes, each leaving the output bit for bit as it was:
- Each step runs only where the tile's output depends on it (choice ±0, homogeneity ±1, Lab ±2,
  greens ±3, mosaic ±5 inside the 6 px margin), with direct neighbour indices instead of an
  index clamped on every read; the clamped values at the buffer edge never reached the output.
- A candidate pixel is built in registers before its Lab conversion: writing its channels
  through an index and reading the pixel back stalled on store forwarding (the hottest
  instructions of the profile).
- Tiles are written into the output one band at a time, instead of all 64 MP of tiles being
  collected and then copied (797 MB held twice). Tiles inside the image copy their mosaic rows
  instead of reflecting and taking a modulo per sample.

Sony ILCE-7RM6 9984 × 6656 Compressed HQ raw, demosaic only, best of 5 on 4 cores:
1.85 s → 1.05 s wall, 6.3 s → 4.0 s CPU. Verified identical (f32 bits) on 7 real raws
(ILCE-7RM6 FF/APS-C, ARW6 HQ/C and lossless, ILCE-7RM4A) and, against the previous code, on
random mosaics of all four Bayer layouts at 1 × 1 … 300 × 7, 257 × 130 (tile edges, reflection).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:00:33 +02:00
dev-null-undefinedandClaude Opus 5.5 5f2f013c8e Perf: a full-size raw decode no longer copies its 64 MP image to "fit" it
`load_bytes_now` ran every development through `resample::fit`, which returns a clone when the
image already fits. At full size (1:1 zoom, export) that cloned the whole picture: 797 MB and
~0.3 s for a 9984 × 6656 Sony ILCE-7RM6 raw. It now fits only when the image is larger, as the
other preview paths in files.rs already do. Output unchanged (same pixels, by construction).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:00:12 +02:00
radialmonster 967e57fa50 LR-RAW-NEF: read the as-shot white balance from the NRW data block when the maker note has no WB tag (P7000, P7100) 2026-10-13 03:58:09 -04:00
radialmonster fe9e6e3433 LR-RAW-NEF: size the NRW word packing by the row, not by the padded strip (P7000 stripes) 2026-10-13 03:58:09 -04:00
eliets2 be592cf2b1 LR-IMP-FORMATS: CI-enforce the unsupported CRX variants, listed in docs/cr3.md
docs/cr3.md gains a variant-status table: every supported and rejected CRX
coding variant, the function that gates it and the exact Unsupported text.

crates/raw/tests/cr3_variants.rs enforces the rejections (19 tests). Each
rejected variant is rebuilt as a small synthetic CR3 (container, CMP1
descriptor, CRX stream) and the test asserts the exact string, and that
probe_info (the import path) and decode return the same error. Control
fixtures decode through the same container, including both edges of the
accepted uniform quantization range (4..=44) and adaptive QP range
(131..=168), so a rejection can only come from the documented gate. The
table itself is prose and is not checked against the tests.

The doc said only QP values 131-167 were accepted; the decoder also accepts
168 (quantization value 44, step 102), so that sentence now says so.

Tests and docs only; no decoder change.
2026-10-13 10:56:29 +03:00
Atmik Shetty cb8b797cd4 KEY-SLIDER-RESET: a slider's name and thumb say a double-click resets it (fixes #1436)
A double-click on a slider's name or thumb already reset it, but nothing said so: only the value had a
tooltip. Resting the pointer on the name or on the thumb now shows "Exposure — double-click to reset
it", the wording (and translations) the curve channels already use. The rest of the track, which is
clicked and dragged, gets no tooltip, and the value keeps "Click to type a value".

The first click of a double-click on the thumb moved the value to where the pointer landed, a few
points off its centre: one history step, then the reset another. A click on the thumb now leaves the
value alone, so the reset is one undo step, as from the name. A disabled slider's name no longer
resets it.

No per-slider reset button: Lightroom has none, and the double-click it documents is now shown where
it works. Tests: tests_slider_reset.rs (name and thumb reset Exposure and Contrast in one undo step,
the hints, a click on the thumb keeps the value, typing a value still works) and
widgets/tests_slider_reset.rs (a disabled slider's name).
2026-10-13 13:16:08 +05:30
radialmonster e82b5089f7 LR-RAW-DNG: DNGs written by older LightCraft keep their sensor-anchored CFAPattern reading; the writer now marks its spec-anchored files 'LightCraft DNG 2' 2026-10-13 03:44:44 -04:00
eliets2 115b19bdcb LR-IMP-FORMATS: fuzz structurally valid CR3 containers in the robustness tests
crates/raw/tests/robust.rs only mutated DNGs. Add two small valid CR3
fixtures (a 4x4 lossless CRX and a 16x16 three-level C-RAW CRX) and a
property that flips bytes in them or truncates them, then runs the existing
exercise() helper (probe, embedded_preview, decode, develop and the colour
transform) plus probe_info, the header-only description used on import:
errors or clean decodes, never a panic. Unlike random TIFF-like bytes, a
structurally valid file gets past the container walk, so the mutations land
in the CRX marker walker and entropy readers. A fixture test asserts that
both files decode as built, so the mutations hit live decode paths.

Tests only; the existing DNG property keeps its 400 cases and the new one
uses proptest's default (256, PROPTEST_CASES overrides it).
2026-10-13 10:41:11 +03:00
Atmik Shetty 64ccc20853 KEY-HIDEPINS: Tool Overlay modes (Auto / Always / Selected / Never) for spot and mask pins, Shift+H cycles them (fixes #224)
The Remove tool's spot pins (Remove / Content-Aware / Heal / Clone) and the
mask pins now follow a Tool Overlay mode, saved with the UI state:

- Auto (default): shown while the pointer is over the photo (or a pin is
  dragged), hidden while a new spot or brush stroke is painted
- Always: all of them
- Selected: only the selected spot's or mask's
- Never: none; the tool still works and a click paints a new spot

A hidden spot can't be grabbed. Mask pins also need Show Pins
(view.maskPins), which keeps its meaning and reply.

Command view.toolOverlay {mode?: auto|always|selected|never} (no mode steps
to the next), Shift+H (H stays Remove), View > Tool Overlay with the modes
and the cycle item, and a Tool Overlay dropdown in the Remove and Masking
panels. Headless tests cover each mode with the pointer over and away from
the photo, grabbing, the key, the command, the menu, the dropdown, mask pins
with Show Pins, and the ui.json round trip.
2026-10-13 13:10:57 +05:30
eliets2 f4b7175429 LR-IMP-FORMATS: property tests for the CRX decoder through the public decode path
crates/raw/tests/crx_properties.rs drives lightcraft_raw::decode with
synthetic CR3 containers built around CRX streams that the test encodes
itself: reference entropy coders for the MED, Rice, MELCODE and QP-map
layouts, and the exact algebraic inverse of one 5/3 lifting line. The
tile-halo coefficients are free parameters of that inverse, so synthesis
must reconstruct any encoded plane exactly. Tests only; no decoder change.

- Wavelet round trip: random planes decode exactly across odd plane sizes
  and multi-tile halo configurations (eight geometries, arbitrary halo
  values).
- Quantization: every uniform quant value 4..=44 and every adaptive QP value
  131..=168 dequantizes within the 14-bit range. Overshoot is clamped, and
  an in-range plane lands exactly on level * step, so the step sequence
  itself is observable. Quant 3 and 45 and QP 130 and 169 are rejected by
  decode and probe_info alike. Random QP maps, including odd map heights,
  with random per-band base and gain stay in range.
- Lossless samples outside the bit depth are Corrupt errors instead of being
  clamped; in-range planes decode exactly.
- Adversarial entropy payloads planted in well-formed lossless, C-RAW,
  version 0x200 and QP-map streams either error or decode deterministically
  and never panic. A QP Rice prefix longer than the 23-zero escape is
  Corrupt.
- Random IAD1 geometry either decodes with the active area inside the
  sensor and the crop inside the active area, or is rejected.
- Decoding gives identical results across repeated and four-way parallel
  invocations.
- Odd QP-map heights decode: the last QP row has no partner and is used
  alone, and QP values are averaged before the step lookup. Large QP jumps
  take the escape code.

The case budget is proptest's default (256 per property); set
PROPTEST_CASES to change it.
2026-10-13 10:40:45 +03:00
wstockandClaude Fable 5.1 5e9a1b6ec7 Visualize: the all-masks overlay shows the union of the masks, not the last one
`Overlay::AllMasks` painted each mask's plane in turn, and every mask view
rewrites the whole image from its alpha (White on Black writes `255·a`,
Image on Black multiplies by `a`…), so each plane wiped the ones before it
and only the last visible mask showed. The planes are now merged (per-pixel
max) and painted once; the GPU path goes through the same `apply`.

The test added with #919 could not pass: besides the above, its hidden-mask
check expected the plain pixel under White on Black, where everything
outside the masks is black by definition (as the single-mask test asserts).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NH3itd85jPuM6wNjgcGfEH
2026-10-13 07:26:18 +00:00
wstockandClaude Fable 5.1 e935ad75e2 LR-VIEW-COMPARE: ⌘/Ctrl- and Shift-clicks on the filmstrip select in Compare
In Compare a filmstrip click goes to `compare.set` (#747), so the grid's
modifier clicks never reached `library.select` and multi-select from the
filmstrip was impossible there (#187 follow-up). A ⌘/Ctrl-click now toggles
the photo and a Shift-click extends from the active photo, as in the grid;
the two photos shown stay selected and the active photo is unchanged, so a
rating key still acts on a photo that is on screen. A plain click still
replaces the active side.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NH3itd85jPuM6wNjgcGfEH
2026-10-13 07:22:42 +00:00
s17sh70x2jfl031agandClaude Opus 5.5 094686a2f6 i18n(pt-br): translate AI Denoise
The AI Denoise panel, model download and settings were still in English
in Brazilian Portuguese; this translates its 98 strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:11:58 -07:00
Marco Arnulfo 0d8e3e3913 LR-IMP-ADD-DIALOG: an import ends showing its first photo, in All Photos when the view doesn't hold it, unless another photo was chosen meanwhile (fixes #1446) 2026-10-13 09:04:10 +02:00
Marco Arnulfo c10ca4e958 LR-IMP-PREVIEW-READ: a raw whose embedded preview can't be read still gets a thumbnail (fixes #1448)
The grid queues no render behind an unedited raw's quick thumbnail, since the embedded JPEG is
meant to be the thumbnail. But whether that JPEG can be read is only known when the quick job
runs, and `quick_thumb_job` had no fallback: when the preview loader returned nothing the job
failed with "no quick preview", the failure was remembered for that key, and the cell stayed
empty until an edit changed it. The quick job now carries the real thumbnail job as its last
resort, as `quick_view_job` already does for the loupe.
2026-10-13 09:01:48 +02:00
Matthew James SivakandClaude Opus 5.5 aeb21ac813 UI: align Local folder rows, paint dock gaps, bottom-align the tool strip
- Local folders in the sidebar are drawn at their tree indent like Albums and
  Folders: the icon lines up with the rows above and the disclosure triangle
  sits in the gutter left of it; children nest by 16 pt (#1097).
- The central panel that hosts the dock is filled with chrome, so the gaps the
  dock leaves between panes no longer show the dark clear colour (#1098).
- The tool strip's bottom group is two buttons and one gap tall, so Info ends at
  the bottom margin as Presets starts at the top one (#1099).

Each fix has a headless regression test that fails without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:00:28 +02:00
smposaraandClaude Opus 5.5 26df1c5cdf LR-IMP-CAMERA-COVERAGE: verify Canon EOS RP CR3 pixel for pixel
Four CC0 EOS RP samples from raw.pixls.us (lossless RAW and C-RAW, full
frame and 1.6x crop mode) now have exact full-sensor regressions against
the DNGLab 0.8.0 black-box oracle (Windows binary, checked first against
the documented M50 RAW hash). The decoder already matched; no decoder
change was needed. Crop mode is a single 4032x2656 tile, full frame two
3192-wide tiles.

docs/cr3.md also records that the white level is Canon's specular white,
which at the -1/3-stop ISOs (e.g. 11062 at ISO 5000) is well below the
sensor's saturation point.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 08:59:30 +02:00
OneSlipsandClaude Opus 5.5 bd50896ca1 LR-MASK-EFFECTS: merge upstream main into pr/mask-effects
Conflicts: the 9 locale *-formats.json catalogs (both sides appended
messages at the end; kept both) and docs/parity-checklist.md (header
change list, regenerated summary via `cargo xtask parity --write`,
revision history rows from both sides).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:54:08 +10:00
null 00000111 d3e56df54a Add a security policy 2026-10-12 23:50:09 -07:00
s17sh70x2jfl031ag b73c0599fa i18n(pt-br): fix plurals and 6 inconsistent strings
Many pt-BR format strings dropped the English plural argument with
{:.0}, so nouns never became plural ("Exportada 5 foto"). Also fixes
the gender of "matiz" and two terms that disagreed with the catalog.
2026-10-12 23:41:18 -07:00
Atmik Shetty 63f68f5044 Merge remote-tracking branch 'upstream/main' into feat/print-color
# Conflicts:
#	crates/engine/src/lib.rs
2026-10-13 12:08:59 +05:30
Andrew FrahnandClaude Opus 5.5 09378aa898 Tests: keep behaviour checks only
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 17:37:45 +11:00
Claude 64f354fca3 LR-MERGE-HDR: merged DNGs declare the white balance their source shows (follow-up to #1123)
#1123 gives HDR and panorama merges of raws without colour matrices the colour they open with, but writes
ColorMatrix1 from the forward matrix, so the as-shot white the DNG declares lands wherever the fitted look and the
generic camera model take it. On real ILCE-7M3 brackets the HDRs opened at As Shot 6113–7307 K / +115 (Duv +0.038)
where the ARWs show 3932–5268 K / +7, and any white-balance edit turned them green (CIEDE2000 11–13 against the ARW
at the same Temp/Tint). The render at As Shot was right (0.4–0.8).

The colour matrices now declare the white balance the source shows, decided by files::WbScaleOf (new dng_white):
the camera's measured matrices when they give the source's scale (lightcraft_raw::spectral; the DNG then reads every
white as the source does), else a matrix under which the as-shot neutral is the white the scale shows (Sony's
presets' reading, 6500 K / 0 on the relative scale, the file's own white otherwise). Forward matrix and neutral are
unchanged, so is the render at As Shot.

Measured on the same brackets with this change on a fork build: As Shot 4813 / 5268 / 3932 K, +8 / +8 / +7 as the
ARWs (declared white Duv +0.003); same Temp/Tint within CIEDE2000 0.8–1.7 of the ARW for most changes, about 5 for
the largest (5268 → 3200 K, 3932 → 6500 K: the ARW adapts its look with Bradford, the DNG rebalances in camera space).

Tests: a merged DNG shows its source's As Shot on all four scales (measured matrices, presets, relative, own); with a
look that tints white the DNG declares the shown white, gives the measured model's multipliers at other whites and
renders at As Shot as the source does. Both fail on main (ILCE-7M3 case: (7342, 115) for (5268, 8)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gRtdWF1E9358FfzhzYqCS
2026-10-13 06:37:11 +00:00
Jason Baldwin 6477d031fc LRC-LIB-PEOPLE: face pictures come from the embedded preview and are kept in the thumbnail cache (#1440)
An unedited raw's face tile is cut from its largest embedded preview, read
the planned way (header and JPEG, never the sensor data), when the preview
holds at least 3/4 of the tile's pixels across the face; otherwise, and for
edited photos and other files, it is developed as before. Tiles keep going
to the memory + on-disk thumbnail cache, now at 16 px size steps so the
thumbnail slider reuses them. The planned preview path carries an Adobe RGB
preview colour space and applies it instead of declining to the whole-file
read (Sony alpha 1 previews).
2026-10-13 08:31:23 +02:00
Atmik Shetty 6e5cd82ce7 Merge remote-tracking branch 'upstream/main' into feat/print-color
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-13 12:00:45 +05:30
Brandon Thomas b3d392b499 Merge pull request #1438 from storytold/claude/integrate-batch-32
Integration batch 32-2: 7 reviewed contributor PRs
2026-10-13 02:18:34 -04:00
Brandon ThomasandClaude Opus 5.5 ae9b09d3c2 Batch 32: rustfmt after merges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:07:07 -04:00
Brandon Thomas c94ebae470 Merge PR #1185 2026-10-13 02:06:07 -04:00
Brandon Thomas 4ee6a4888b Merge PR #1126 2026-10-13 02:05:14 -04:00
Arekatla Nishanth ChowdaryandClaude Opus 5.5 1462d96360 Contributors: add my people.toml entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:34:33 +05:30
Arekatla Nishanth ChowdaryandClaude Opus 5.5 edc3661680 Issue #1200: portable mode, a portable.txt beside the executable keeps settings in LightCraftData
As in PhotoCraft: when portable.txt (or LightCraft.portable) sits next to the
executable, config_dir() is <exe dir>/LightCraftData, so settings, logs and
models stay with a portable copy instead of %APPDATA%. LIGHTCRAFT_CONFIG_DIR
still wins and is used without probing beside the executable. A portable
folder that can't be written logs a warning and the platform folder is used.
The check runs once per process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:34:33 +05:30
Brandon Thomas 68bacba288 Merge PR #1113 2026-10-13 02:04:31 -04:00
Brandon Thomas 8a640dc70b Merge PR #1077 2026-10-13 02:04:06 -04:00
Brandon Thomas 478f20054b Merge PR #1056 2026-10-13 02:02:17 -04:00
Brandon Thomas d8f10a1ef7 Merge PR #919 2026-10-13 02:01:30 -04:00
Brandon Thomas 643bc7f909 Merge PR #850 2026-10-13 01:57:40 -04:00