45 Commits
Author SHA1 Message Date
Dylan M. TaylorandCodebuff 4ae3089420 security: bounded keyword, repair and journal-recovery work (CodeRabbit) (#2763)
* security: harden dev-tool scripts and the testkit skip-log test (CodeRabbit)

- tools/install-sam3.sh: the HF bearer token went through curl's argv, where
  `ps` exposes it to other local accounts (CWE-214); it now travels through
  a private 0600 temp config file removed on exit.
- packaging/macos/import-cert.sh: the decoded .p12 was written to a
  predictable path in a shared TMPDIR, where a precreated attacker-readable
  file would receive it (CWE-377); both cert and keychain are created inside
  a mktemp -d 0700 directory now.
- docs/showcase/run.py: the reply reader copied whole responses with no size
  cap (obvious quadratic-copy and unbounded-memory DoS). It accumulates in a
  bytearray now and closes the connection past 128 MiB.
- tools/spectral_camera_table.py: alias/make/model strings and comments from
  the rawtoaces-data checkout moved directly into Rust source; one newline in
  a comment became Rust code. External text is now escaped as Rust literal
  content and comments are normalized to one printable line.
- crates/testkit: appended_lines_accumulate reused a pip-predictable temp
  dir by creating it with create_dir_all and carried on after failing to
  remove its log path, so the append would follow an attacker-planted
  symlink (CWE-59); it now fails the test if the directory exists instead of
  testing through it, and removes any existing log path only after clearly
  checking it, always failing the test instead of proceeding when removal fails.

Findings #10080/#10078 PR (rows 2, 6, 8, 9, 15 of the
storytold-lightcraft-agent-findings report).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* security: bounded catalog keyword, repair, journal recovery work (CodeRabbit)

- keywords: from_file searched every hierarchical level for each flat keyword
  and `same` lower-cased two strings per comparison — one lowered level set
  instead (CWE-407, row 97).
- keywords: parse_keyword_list scanned each keyword's growing synonym list per
  line — a lowered-synonym set per keyword instead (CWE-407, row 100).
- keywords: keyword_tree stored every level's prefix twice, so a photo XMP
  keyword nested deeper than a list file accepts made stored bytes quadratic
  in the level count; the tree caps at MAX_LEVELS, and keyword_list_text names
  whatever lies deeper from the photos' and list's own spellings, so the file
  still reads back (CWE-400, row 103).
- catalog: repair validated a folder chain once per album — memoized by chain
  now, so a valid chain in a flat snapshot costs one walk overall (CWE-407,
  row 101).
- store: journal append and truncate follow a planted catalog.log symlink;
  both refuse any non-regular file at the name before writing through it
  (CWE-59, row 107), like the staging writes since #1502.
- journal: resync re-validated the whole remaining suffix UTF-8 for every
  candidate record start; a whole line is validated once (covering every
  candidate in it), and an invalid line's re-checks stop at a 64 MiB budget,
  with the tail then staying a torn one the damaged path keeps and reports
  (CWE-407, row 109).

New tests: from_file case-insensitive level match, synonyms kept once, a
4096-level keyword cut at MAX_LEVELS, a link at catalog.log refused, and
resync over a fragment of 1024 record starts.

Findings rows 97, 100, 101, 103, 107, 109 of the
storytold-lightcraft-agent-findings report.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-23 22:45:21 -04:00
aiongg 0e6b0b150f Packaging: pin the signing client and appimagetool, and check their hashes (#2413)
* Packaging: pin the Windows signing client and check its hash

* Packaging: pin appimagetool and check its hash

* Packaging: no pinned tool or runtime for an architecture exits clearly; pin the AppImage runtime and pass it with --runtime-file
2026-10-23 13:00:02 -04:00
Dylan M. Taylor d5e639b3d1 packaging: bash tests, named positional parameters and stderr errors (SonarCloud S7688/S7679/S7682/S7677) (#2655)
Bash scripts use [[ ]] for tests, functions name their positional
parameters and end with an explicit return, and the app-specific packaging
check writes its ::error:: annotations to stderr. No behaviour change.
2026-10-23 11:45:18 -04:00
Dylan M. Taylor d79b1f33e3 security: enforce HTTPS on curl downloads (SonarCloud S6506) (#2493)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 19:35:59 -04:00
aiongg 452f317d38 Merge PR #1993: macOS bundle: drop Info.plist types LightCraft cannot open (#1951) 2026-10-21 14:52:57 +00:00
Brandon ThomasandClaude Opus 5.5 4f0b110bcb Release 0.9.1: the release web build installs the wasm-bindgen CLI
Since the web zip moved from trunk to cargo xtask web (aeaf4154), packaging/web/package.sh needs the
wasm-bindgen CLI at Cargo.lock's version, and the shared release workflow installs only trunk, so
0.9.0's Web (wasm) job failed. In CI, install it first (as FilmCraft and EffectCraft do).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 23:16:37 -04:00
Sergio PereaandDeepSeek V4.1 Flash fa26767b81 macOS bundle: drop Info.plist UTI declarations LightCraft cannot open (#1951)
The template was copied from a sibling app: it exported a "LightCraft Document"
UTI for PhotoCraft's `.pcraft` extension (MIME `application/x-lightcraft`) and
imported `.psb` (Photoshop Large Document) and `.qoi`. LightCraft reads none of
them, so the declarations only made Launch Services type PhotoCraft documents as
LightCraft's and left `.pcraft` with three claimant apps among the Craft suite.

Remove both `UTExportedTypeDeclarations` and `UTImportedTypeDeclarations`. No
CFBundleDocumentTypes is added: the formats LightCraft opens are already declared
by the system or another app, so adding them is out of scope here.

`packaging/check-app-specific.sh` now parses the template as a property list and
fails if it declares any of those types again, while still checking the required
bundle keys.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
2026-10-16 09:07:29 +02:00
skylartaylor 3885b61e6b ci: retain LightCraft installer and package checks 2026-10-16 05:25:18 +02:00
Brandon ThomasandClaude Opus 5.5 fd9d045c75 CI: the packaging scripts check out the craft-fonts revision release.yml pins (3d9ab3a, with Noto Sans Thai)
Windows ARM64 on main failed since batch 36: #1479's scripts pinned 8dcdacd, which predates the Thai face #1311
made required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:57:33 -04:00
Brandon Thomas 052aa9dccb Merge PR #1479 2026-10-14 22:32:20 -04:00
Brandon Thomas 556f3d040f Merge PR #1795 2026-10-14 22:31:48 -04:00
Brandon Thomas 81a64ed13d Merge PR #1744 2026-10-14 22:29:39 -04:00
IanHollow 69346009d2 Packaging: advertise HEIF images and repair the AppStream screenshot
Assisted-by: OpenAI Codex (GPT-6)
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-14 13:12:15 -07:00
LabDennis 1f4aaaec47 Fonts: finish Thai fallback delivery for desktop and web releases
Retain the complete reviewed change, including prior integration resolutions,
on current upstream.

#736: deliver Thai UI fonts in desktop and web releases

Use the merged craft-fonts input containing Noto Sans Thai across release,
FreeBSD and Nix builds. Retain the small Thai face in the wasm subset and
reject required release inputs that lack it. Exercise the reported Thai
folder name through all UI families and include original font licence texts
in Windows installers as well as portable packages.

Refs #736; completes delivery of the fallback added in #750.

Validation: UI tests, UI-only strict Clippy, 28 wasm checks, HEIF checks,
assets, layers, parity and formatting pass. All 21 unrelated workspace
failures reproduce with upstream Rust sources and the old font input;
existing Rust 1.95 metadata/engine Clippy findings remain unchanged.
2026-10-14 18:52:15 +02:00
tydude001andClaude Opus 5.5 0467c8904d packaging: RPM requires library sonames, so openSUSE can install it
LightCraft's RPM requires Fedora package names: `libxkbcommon`, `(vulkan-loader or libglvnd-egl)`.
openSUSE has no `libxkbcommon`, `vulkan-loader` or `libglvnd-egl` package, so zypper refuses it with
`nothing provides 'libxkbcommon'` (exit 4, which the ArtCraft Launcher shows as "error 4";
storytold/craft-launcher#341).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:41:07 -05:00
aGiuliano eac616b542 Merge branch 'main' into fix/Chinese_Japanese_Text_warning 2026-10-14 14:53:25 +02:00
notdezziandZCode 54321e6175 Packaging: confirm a successful uninstall with the completion dialog (fixes #892)
The MSI never included WiX's ExitDialog: the Publish events point at it, but only
a DialogRef pulls the UI extension's fragment (with its on-exit=success show) into
the package, so every successful run ended silently. Reference it, and note that
the shared completion page is the uninstall confirmation; packaging-lint now fails
when the reference is lost again.

🤖 Generated with [ZCode](https://zcode.ai)

Co-Authored-By: ZCode <noreply@zcode.ai>
2026-10-13 16:15:46 +02:00
draco892 bd0ca28bb0 build: fix host architecture detection in Windows PowerShell 5.1
Use Windows environment variables instead of RuntimeInformation
to avoid a null value during the final CLI smoke test.

Account for emulated shells using PROCESSOR_ARCHITEW6432.
2026-10-13 12:00:04 +02:00
draco892 eec4746a56 build: automatically include craft-fonts in desktop packages
Detect ../craft-fonts or use CRAFT_FONTS_DIR on macOS, Linux and Windows.
Download the pinned release revision when the checkout is missing
and require Chinese and Japanese fonts during the build.

Document font setup and preserve skip-build behavior.
2026-10-13 11:01:40 +02:00
Claude 9978dc739d Merge PR #643
# Conflicts:
#	crates/engine/src/export.rs
#	crates/engine/src/tests_export.rs
#	crates/mcp/src/headless.rs
#	crates/mcp/src/tools.rs
#	crates/ui-egui/locales/de-formats.json
#	crates/ui-egui/locales/de.json
#	crates/ui-egui/locales/es-formats.json
#	crates/ui-egui/locales/es.json
#	crates/ui-egui/locales/fr-formats.json
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/locales/ja-formats.json
#	crates/ui-egui/locales/ja.json
#	crates/ui-egui/locales/pt-br-formats.json
#	crates/ui-egui/locales/pt-br.json
#	crates/ui-egui/locales/ru-formats.json
#	crates/ui-egui/locales/ru.json
#	crates/ui-egui/locales/uk-formats.json
#	crates/ui-egui/locales/uk.json
#	crates/ui-egui/locales/zh-hans-formats.json
#	crates/ui-egui/locales/zh-hans.json
#	crates/ui-egui/locales/zh-hant-formats.json
#	crates/ui-egui/locales/zh-hant.json
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-11 12:43:20 +00:00
Claude 0d5f8b1ea4 Merge PR #879
# Conflicts:
#	docs/whats-new.md
2026-10-11 12:42:19 +00:00
Claude 5ce115a505 Merge PR #959 2026-10-11 11:51:56 +00:00
Claude f4d8a428ac Merge PR #848 2026-10-11 11:39:28 +00:00
xristosmoug 0b960d39e3 fix(macos): verify strict signature in release DMG (#863) 2026-10-11 13:26:48 +02:00
Alex ChambersandClaude Opus 5.5 a6431c152d LR-EXP-PHOTOS: add exported files to Apple Photos (macOS, #236)
The Export dialog gets "Add to Apple Photos" with an optional album (macOS
only). app.export takes addToPhotos / photosAlbum (dialog, Export with
Previous, presets, MCP, lightcraft-cli run and render --opt); the new
export.addToPhotos {paths, album?, wait?} adds files already on disk and
export.photosImports {job?} reports how imports went.

A constant AppleScript run by /usr/bin/osascript asks Photos' import
command (Apple Events, not synthetic input) to import the files into a
top-level album of exactly that name (made when missing; albums in folders
are never used; several of that name: refused), skip check duplicates
false, and returns the media item ids. Album names and paths are passed
only as separate arguments (on run argv), never spliced into the script.
The runner is injectable (Session::apple_photos): with_fs installs the real
one on macOS only, and tests use fakes, so no test starts osascript or
Photos.

Imports are jobs (Session::apple_photos_imports), one at a time. The
desktop app (Session::apple_photos_background, set in open_session) never
waits for Photos on its UI thread: the background export adds on its
worker, app.export without background and export.addToPhotos answer with
the running job, and the app announces the outcome. Without a window (MCP,
lightcraft-cli) imports wait by default, and both headless front ends (the
MCP/CLI backend and the snapshot UI) wait for a running one before the
process ends, on every exit path, through one engine helper
(Session::wait_for_photos_imports) whose deadline follows the job: a
writing allowance while an export still writes, then the import's own
time limit from when Photos was asked, under an overall cap. A runner that panics, waiting or on a
worker, ends its import as failed and frees the slot (panic guard plus a
completion guard). Session::after_export reserves
the import slot before an export writes anything and frees it on every
exit path (handed the files, cancelled, failed, dropped), so a competing
import is refused with the export's job number instead of the export
failing its Photos step after writing. Permission (-1743), missing Photos,
cancel, timeouts, ambiguous albums, busy imports, other osascript failures
and partial imports produce actionable messages; the export's files are
kept either way. Hidden on other platforms; the web build compiles it out.

Packaging: the hardened-runtime entitlements gain
com.apple.security.automation.apple-events (app and CLI) and Info.plist
gains NSAppleEventsUsageDescription, without which macOS refuses the
events without asking.

Not yet tested end to end against a real Photos library: manual steps,
with the packaged app, in docs/apple-photos.md. Parity row LR-EXP-PHOTOS is
now partial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:19:00 +02:00
Chad ElliottandClaude Opus 5.5 a82ecb3753 fix(windows): #399 ignore stale App Paths values in the install-folder fallback
The App Paths directory search doesn't check that lightcraft.exe exists, and
when the old installers' unquoted path is gone, Windows Installer falls back
to the text before the first space: a deleted
C:\Program Files\LightCraft\lightcraft.exe resolved to C:\, so an upgrade
would install into the drive root. Gate the fallback on a second search of
the same value with a FileSearch for lightcraft.exe.

The install-folder test gains legacy-folder-deleted (failed before this fix)
and legacy-exe-deleted cases, and removes its empty parent registry key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:18:22 -05:00
THEtheChadandGPT-6 Astra 32a358180c fix(windows): #399 preserve legacy MSI install folders
Fall back to the parent directory of the App Paths executable when an
older installer did not write InstallFolder. Keep explicit destinations
and the newer stored folder ahead of the legacy fallback.

Exercise the real MSI searches and actions with isolated per-user probes
on x64 and x86, including legacy paths with spaces and Unicode.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
2026-10-11 03:42:56 +00:00
Brandon ThomasandClaude Opus 5.5 9e6c4c6fc9 Release prep: 0.6.0 and Linux riscv64 release build (#844)
- release.yml: new linux-riscv64 job (ported from GridCraft): cross-compiles on
  ubuntu-24.04 against ports.ubuntu.com riscv64 libs, packages a tar.gz with
  package.sh --formats tar, smoke-tests lightcraft-cli under QEMU. The release
  job needs it, so its tarball lands in the draft and SHA256SUMS.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
  support (target dir, cross strip, emulated --version).
- README Downloads and docs/releasing.md list the riscv64 tarball.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:38:10 -04:00
eliets2 a940dab727 web: stop the release zip shipping Cargo build artifacts
lightcraft-web-<version>.zip carried Cargo host build output next to the site: deps/ (81 files, 90.6 MB), build/ (149 files, 22.4 MB) and .fingerprint/ (297 files), ~113 MB that the app never references and that leaked build paths and crate names to anyone hosting the zip.

Cause: xtask wrote the bundle to <target>/web (SITE in packaging/web/package.sh) while building with --profile web. Cross-compiling with --target wasm32-unknown-unknown makes Cargo write the selected profile host artifacts (build scripts, proc-macros, deps/, build/, .fingerprint/) to <target>/<profile>/, so they landed in the bundle directory and package.sh copied the whole tree into the zip.

Fix: write the bundle to <target>/web-site, a directory that is not a Cargo profile name, and point SITE at it. The wasm32/web/ target artifacts and the web profile are unchanged, so the rust-cache keys and the CI web job keep working.

Guard: package.sh now fails if deps/, build/ or .fingerprint/ exists in $SITE, and a unit test asserts the bundle directory is not a Cargo profile name, so the collision cannot come back silently.

Reference (#793)
2026-10-11 00:46:10 +03:00
Brandon Thomas 78550e5de9 Merge PR #609
# Conflicts:
#	crates/engine/src/tests_import.rs
#	docs/parity.md
2026-10-10 01:14:24 -04:00
Brandon Thomas dea37269ba Merge PR #520 2026-10-09 20:36:41 -04:00
Exalted5373andClaude Opus 5.5 90361935ba LR-IMP-FORMATS: HEIC decodes like libheif; release builds include it
heic-rs reconstructs iPhone HEVC tiles bit-exactly (checked against libde265), but
its colour stage was 2-27 code values off libheif on every iPhone photo: it ignores
the HEVC VUI and assumes BT.709 limited range. lightcraft-heif now converts YCbCr
itself (nclx, else VUI, else H.265 defaults; nearest chroma, bilinear for odd clap
offsets, as libheif), inherits tile ICC/nclx on grids, follows libheif's imir axis
and clap rounding, and outputs 16-bit RGB. Measured on 30 real and synthetic
files: within 1 code value of libheif (pillow-heif 1.8 / libheif 1.23).

Also: HEIF header reader for import (no pixel decode), embedded thumbnail for small
decodes, nclx/VUI colour hint (shared CICP mapping with PNG), clear 4:2:2/4:4:4
Unsupported error, Format::not_decodable as the one source of "why not" (import
reports "HEIC/HEIF support isn't included in this build"), `.heif` imports.
Release packaging and Nix build with the heif feature, as whats-new promised.
lightcraft_heif::testdata writes lossless (PCM) synthetic HEICs for the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:38:00 -07:00
hxwandClaude Opus 5.5 485046bf35 Issue #399: Windows MSI: choose the install folder; upgrades keep it
The interactive installer now walks Welcome -> Destination Folder ->
Ready -> progress -> Completed (from #79). Destination Folder is WiX's
InstallDirDlg: Program Files\LightCraft by default, Change... browses,
and WixUIValidatePath refuses a folder that can't be used.

The chosen folder is written to HKLM\Software\LightCraft\InstallFolder
and read back (into PREVIOUSINSTALLFOLDER, then INSTALLFOLDER after
AppSearch unless given on the command line), so a major upgrade stays in
the user's folder instead of moving back to Program Files. Silent and
passive installs show no dialogs and take INSTALLFOLDER=....

packaging-lint fails if lightcraft.wxs loses the folder page, the
remembered folder or the completion page's launch action.

Tested with wix 5.0.2 (x64, arm64, x86 build) and msiexec /qn: upgrade
from 0.4.0 stays in Program Files; a custom INSTALLFOLDER install, an
upgrade without it (stays), an upgrade with another INSTALLFOLDER (moves
there), and uninstall (files, folder and registry value removed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:04:50 -05:00
Brandon Thomas 45621f5679 Issue #18: Windows MSI: finish dialog with Launch LightCraft
Interactive MSI installs now walk Welcome -> Ready to install -> progress
-> "Completed the LightCraft Setup Wizard" (Finish) with "LightCraft has
been installed" text and a checked-by-default "Launch LightCraft"
checkbox. Failure and cancellation end on WiX's standard FatalError /
UserExit pages; silent (/qn) and basic-UI (/passive) installs show no
dialogs and launch nothing.

- lightcraft.wxs: custom UI set = WixUI_Minimal without the licence page
  (MIT OR Apache-2.0 asks nothing of installers), maintenance dialogs for
  repair/remove, ARPNOMODIFY. Launch uses the Util extension's
  WixUnelevatedShellExec via Explorer (runs as the signed-in user, never
  elevated), Return="ignore", only when NOT Installed and the box is ticked.
- package.ps1: add WixToolset.UI/Util.wixext 5.0.2 to the global cache,
  pass -ext ... -culture en-us, and generate plain side/banner bitmaps
  (brand blue / white) so the MSI carries no WiX sample artwork.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1c5feb7ab3)
2026-10-09 08:48:44 -05:00
supper_yijie bf35a3c6c5 fix #425: Restore Simplified Chinese font rendering
1.Added Simplified Chinese font support for web and desktop builds.
2.Kept Inter as the default font, with Chinese used only as a fallback.
3.Verified Chinese glyph tests and a macOS universal build.

Signed-off-by: supper_yijie <syj794844854@163.com>
2026-10-09 15:12:33 +08:00
Xus BadiaandClaude Opus 5.5 e4ab8422b4 macOS DMG: branded window background and icon layout
The DMG opened as a plain Finder window. It now shows the app icon's figure on
the LightCraft colour, with LightCraft.app and the Applications link side by side.
Same approach as VectorCraft's (storytold/vectorcraft#493).

- packaging/macos/dmg/: background.svg (source; text outlined, the figure an
  <image> of assets/app-icon), background.tiff (1x + 2x HiDPI, Deflate, sRGB)
  and dmg-layout.DS_Store (Finder view settings: window, icon size 128,
  positions, background).
- generate.py writes the TIFF and the layout on any OS, byte-for-byte
  reproducible, with nothing from the machine that ran it (no paths, users,
  disk names or volume UUIDs).
- package.sh copies them into the staging folder; the image is still built with
  hdiutil makehybrid. Nothing extra runs in the signing job.
- The volume name drops the version: the layout finds the background through
  an alias that includes the volume name. The DMG file name keeps the version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:55:32 +02:00
ebe54f934e Release: FreeBSD, Flatpak x86_64/aarch64, AppImage zsync updates; README Downloads (#302)
* Release: FreeBSD x86_64, Flatpak x86_64/aarch64, AppImage zsync updates; README Downloads

- linux: appimagetool -u embeds gh-releases-zsync update information; the .AppImage.zsync is
  published beside each AppImage (zsync installed; checked in the job).
- flatpak: new job per arch repackages the Linux tarball into a single-file .flatpak
  (packaging/linux/flatpak-bundle.sh + ai.storyteller.lightcraft.bundle.yml); the Flathub
  manifest gets the CLI and the same commented finish-args; packaging-lint checks they agree.
- freebsd: new job builds lightcraft-<ver>-freebsd-x86_64.tar.gz in a FreeBSD 14.3 VM with the
  freebsd.yml packages (packaging/freebsd/package.sh; layout dry run in packaging-lint).
- version, linux and web no longer use the release environment (they sign nothing), so a
  branch dispatch dry-runs every unsigned job; the release job still needs macOS and Windows.
- README: Downloads section listing every build; docs/releasing.md updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Linux packages: describe LightCraft, not PhotoCraft, in the deb/rpm description

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:45:26 -04:00
Claude 6bd64e4ad4 LR-IMP-FORMATS: Panasonic RW2 / Leica RWL / Panasonic RAW in every raw format
Decode every raw encoding Panasonic and Leica bodies write, from the DMC-LX1 (2005) to the DC-S1RM2 (2025):
compressed formats 4 (most bodies, 2008-2022) and 6 (S1 / S1R / S1H / S5, GH5M2), the prefix-coded strips of
format 8 (GH6 and later), packed formats 2, 5 and 7, and the 16-bit words of the 2005-2007 .RAW files. Until now
only format 5 decoded; every other Panasonic file opened as preview only.

Clean-room: no raw-decoder source was read. Tag names come from tag documentation; every encoding was recovered
by black-box analysis of 178 CC0 files from raw.pixls.us (118 bodies), and the module docs note the measurement
that settled each rule. Format-8 tags of unknown meaning must carry the values every sample has, otherwise the file
is reported as unsupported rather than guessed at.

Levels and geometry: formats 4 and 6 store samples 15 above the recorded black level (files without one use 15);
white is the active area's saturation plateau (the linearity limits are wrong on extended low-ISO shots, the GF1
and the Digilux 3); the in-camera aspect ratio is the default crop; mapped-out defect pixels are filled from
same-colour neighbours; the CFA pattern applies at sample (0, 0).

.rwl and .raw files are imported (engine, MCP folder expansion, file dialog, Linux MIME types). One file per
encoding joins the never-panic proptest; 11 CC0 files join `cargo xtask corpus`, and corpus_panasonic_encodings
checks each encoding's bit depth, black level, crop and CFA layout against the camera's own JPEG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtQmZ6peZXGn3wiqeowV2v
2026-10-07 16:00:39 +00: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 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 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 ThomasandClaude Opus 5.5 ebc73bb7b4 Issue #107: Web build: data-safety fixes for libraries kept in the browser
- File > Back Up Library... (web): a zip of the catalog files and every
  stored original, built entry by entry; Restore Library from Backup...
  reads it into a new library folder and switches only when complete
  (the previous library stays in storage).
- Failed flushes to browser storage make the catalog Store refuse
  writes, so changes show as unsaved (top-bar warning) and are retried
  every 2 s instead of being lost silently.
- A picked/dropped photo whose bytes can't be stored is not added.
- One tab per library (Web Locks); a second tab shows a message.
- Notices: storage not persistent, library failed to open (temporary
  session), experimental build; ?reset asks first; a panic shows a
  message instead of a frozen page; long toasts wrap.
- Hosting: _headers/.htaccess no longer mark the unhashed .js/.wasm
  immutable; HOSTING.md rewritten for the actual build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:46:21 -04:00
Brandon ThomasandClaude Opus 5.5 aeaf4154f7 Release: build the web zip with cargo xtask web (wasm-bindgen), not trunk
LightCraft's web app is built by xtask into <target>/web; the packaging script
ported from PhotoCraft assumed trunk and dist/web. The release job now installs
wasm-bindgen-cli 0.2.129 to match Cargo.lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 12:35:58 -04:00
Brandon ThomasandClaude Opus 4.8 453f97b549 Signed release pipeline (macOS/Windows/Linux/Web); README community note
Ports photocraft's release workflow + packaging (signing, notarization,
MSI/DMG/deb/rpm/AppImage/web), adds `cargo xtask version`. File-type
associations omitted (route B); app keeps its own .desktop. Fresh WiX
UpgradeCode. README 'about' note updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-02 12:06:14 -04:00
Brandon ThomasandClaude Opus 5.5 75e4e3ced0 app icon: lynx (owner's ArtCraft drawing), Dock/taskbar/launcher wiring, palette docs
- assets/app-icon/: lightcraft.svg (master), lightcraft-small.svg, 1024 PNG, macOS 512 PNG,
  .icns, .ico, hicolor theme (ai.storyteller.lightcraft), LICENSE.txt, README (palette,
  geometry, provenance, files)
- packaging/icons.sh regenerates everything (resvg, iconutil, new `cargo xtask ico`)
- apps/lightcraft: runtime window/Dock icon + Wayland app id; build.rs embeds the .ico and
  VERSIONINFO into lightcraft.exe (winresource, Windows targets only)
- packaging/linux/ai.storyteller.lightcraft.desktop
- ATTRIBUTION.md entry; icon at the top of README

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:37:06 -04:00