258 Commits

Author SHA1 Message Date
Brandon Thomas 77adc30a75 Release 0.16.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:57:45 -05:00
Whatever Industries 5ed4952d43 Add shared custom colors and complete marker editing (#1435)
* M3: Add shared custom colors and complete marker editing

* #1435: refine native colors and range endpoint flags

Use the macOS Colors panel for custom label colors and reuse the established egui picker on other hosts. Preserve draft confirmation, exact sRGB values, native text shortcuts and project ownership. Compact the swatches and center the add control, split range glyphs across their endpoints, localize the new controls, protect newer marker edits from stale dialogs, and cover the behavior with rendered UI and hit-test regressions.

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

* #1435: preserve imported palettes and marker double-click ownership

Union saved OTIO palettes across timelines with deduplication, bounded capacity,
first-name preservation and explicit overflow warnings. Keep null authors
consistent with omitted fields, and consume marker double-clicks before the
work-area gesture so opening the editor does not alter project history.

Correct the CSV URL column and schema documentation. Add six regressions for
palette retention/capacity, author handling, and physical overlapping gestures.

Validation: full cargo xtask ci (3666 passed, 45 skipped), 42 rendered UI tests,
and strict workspace/all-target Clippy on Rust 1.99.1.

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

* #1435: retain OTIO swatch names and generator labels

Ignore orphan name entries when retaining saved palette names so input ordering
does not hide valid names after the first 64 entries. Keep names bounded by the
retained palette and preserve existing valid names.

Include generator preset labels alongside custom label colors in OTIO metadata.
Add regressions for orphan-prefixed name maps and three generator kinds with
preset/custom colors through actual export/import round trips.

Validation: both regressions failed before fixes; all 72 interchange tests and
full cargo xtask ci pass (3668 tests, 45 skipped), plus strict workspace/all-target
Clippy on Rust 1.99.1.

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

* #1435: preserve distinct OTIO generator item identity

Use exported FilmCraft item IDs for generator media identity so identical
content can retain distinct source names, labels and custom colors. Repeated
references to one source item still share a single imported media entry.

Preserve content-based fallback for missing or invalid item IDs. Cover black
video, bars and tone, and color mattes with distinct items/shared references,
plus legacy and malformed identity metadata.

Validation: distinct-generator regression failed before fix; legacy compatibility
passed. All 74 interchange tests and final full cargo xtask ci pass (3670 tests,
45 skipped); strict workspace/all-target Clippy also passes on Rust 1.99.1.

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

* #1435: align Edit Marker layout and add safe marker navigation

Give the editor a wide aligned form, larger Notes area, side action column,
and grouped palette with vertical marker types. Expand the Web Link field
with the form and keep actions accessible in small windows.

Previous/Next saves valid edits as one Undo step and stays with the original
sequence/source owner, including coincident markers. Invalid drafts stay open;
unchanged navigation and Done add no history. Keep native/shared color pickers,
Author, Notes, URL validation and immediate marker creation.

Validation: all 45 rendered sequence/marker UI tests pass, including five new
navigation/owner/validation/layout regressions. Native macOS layout, picker
Cancel and exact single-step Undo restoration verified. Full standard cargo
xtask ci passes 3675 tests (45 skipped), doctests and all remaining gates;
strict Rust 1.99.1 workspace/all-target Clippy also passes.

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

* #1435: refine Edit Marker proportions and action alignment

Narrow the dialog to 680 logical pixels and keep the core order Name,
Time/Duration, Notes, Color and marker type. Place Author after the type-specific
options as secondary metadata. Preserve our palette, custom picker and range controls.

Use consistently sized, centered rounded action buttons with a primary Done action.
Shorten Delete Marker to Delete and remove the navigation helper and unused translations.
Keep the existing navigation save/validation/Undo semantics and automation IDs.

Validation: all 45 rendered marker/sequence UI tests pass, including small-window
action accessibility. Actual macOS layout and no-op Previous/Next/Cancel verified.
Full standard cargo xtask ci passes 3675 tests (45 skipped), doctests, formatting,
Clippy, translations, layers, assets and 49 WASM crates. Strict Rust 1.99.1
workspace/all-target Clippy passes separately.

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

* #1435: tighten marker layout and validate text editing

Use a narrower aligned form with Author below Name, bounded scrolling Notes,
left-aligned colors, centered actions and an inline Web Link URL/open icon.
Remove the legacy Flash Cue choice while preserving imported marker types.

Constrain timecode typing/paste to complete numeric colon-separated fields,
validate drop-frame labels and frame bounds, and disable Done for invalid timing.
Preserve high-frame-rate timecodes and point-marker semantics when Duration is
unchecked. Route native/menu clipboard and text Undo commands to focused fields;
explicit engine commands retain project Undo and selection semantics.

Validation: standard cargo xtask ci passes 3679 tests (45 standard skips),
doctests, fmt, strict workspace/all-target Clippy, i18n, layers, 69 assets and
49 WASM crates. Also passed 48 rendered marker/sequence tests and strict Rust
1.99.1 Clippy. Actual macOS clipboard, bounded Notes, point save and exact Undo
were checked. Windows/Linux desktop interaction remains pending.

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

* M0: Wait for frame-worker recovery before asserting

Do not treat a nonempty request queue as proof of worker death in the
panic-recovery regression. Keep waiting for all injected faults and enough
post-fault completions, then drain the queue without adding more seeks.
Retain the exact fault-count, successful-recovery and empty-queue assertions
and bound the wait with a two-minute deadline.

The inherited test failed twice in independent fork CI. It did not reproduce
locally: baseline passed 20 normal and 10 delayed-report runs; the repair
passed 50 normal and 10 delayed-report runs. No product or marker UI changes.

Validation: standard cargo xtask ci passed all 4485 tests (52 standard skips),
doctests, formatting, strict workspace/all-target Clippy, i18n, layers,
69 assets and 49 WASM crates.

Assisted-by: OpenAI Codex

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <codex@openai.com>
2026-11-01 03:04:14 +01:00
aiongg 477c983694 updates: show check results with craft-update's CheckResultDialog 2026-10-31 04:42:43 +00:00
Brandon Thomas 94ceaa91a5 Release 0.15.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:22:55 -04:00
Dylan M. Taylor fed0f42fd5 UPD.1: honor app pretend versions in update checks (#3668) 2026-10-30 02:58:39 -04:00
Dylan M. Taylor 45d6a68077 Update prompt shows the app icon and accent color instead of a letter (#3663)
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#8b5cf6, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).

craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- crates/prores/src/decode.rs
- crates/ui-egui/src/panels/file_dialogs.rs
- crates/ui-egui/src/panels/timeline/interact.rs
- crates/ui-egui/src/panels/timeline/layout.rs
2026-10-30 01:27:42 -04:00
Abdullah 25f3e9eade Captions: File ▸ Export ▸ Captions… asks for the file format (#3365) (#3523)
The menu item, and the Text panel's Export captions…, opens Caption Export
Settings with a File Format menu of every format captions.export writes. OK
opens the save panel with only that format's filter and a matching name. A
name typed with another caption format's extension is written in that format
(it is the file the save panel asked about); any other name gets the chosen
format's extension. If a file with that new name already exists, nothing is
written: with WebVTT chosen, typing "keep" when keep.vtt exists leaves
keep.vtt alone. With a path the command still exports directly.

Also fixes a panic: captions.export with params that are not an object
indexed into them.

Fixes #3365

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 01:22:42 -04:00
Brandon Thomas a2d8e9ce26 Release 0.14.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 12:09:21 -04:00
aiongg 70375a3ee8 refactor(ui): use craft-ui's ComboBox for every dropdown (#3445)
* ui-egui: use craft_ui::ComboBox for dropdowns; repin craft-libs to 62bb0e1

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 6af63481 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)
2026-10-27 10:27:01 -04:00
aiongg 3a22804ddd craft-libs: pin every crate to b926b5c0 (craft-libs main with #355) 2026-10-26 03:27:23 +00:00
aiongg a43f19c006 Merge branch 'docking-frame-trial' into docking-ime
# Conflicts:
#	Cargo.lock
#	Cargo.toml
2026-10-26 02:29:30 +00:00
aiongg 5e8c321996 craft-libs: pin every crate to cd25951c (craft-libs#355: native floating windows publish their IME descriptor) 2026-10-26 02:23:53 +00:00
aiongg e58b48aef3 craft-libs: pin every crate to e8b4dde5 (craft-libs#340 stack, for craft_ui::ime::Composer) 2026-10-26 02:17:31 +00:00
aiongg 1f0ecaa138 craft-libs: pin every crate to 1e6f1278 (craft-libs main with #353) 2026-10-26 02:13:59 +00:00
aiongg 41883346d5 Merge remote-tracking branch 'upstream/main' into docking-frame-trial 2026-10-26 02:13:37 +00:00
aiongg 61ab638439 craft-libs: pin every crate to 1a14a680 (craft-libs#340 stack, for craft_ui::ime::Composer) 2026-10-26 02:11:01 +00:00
aiongg 2afdf2e1eb craft-libs: pin every crate to 37c907d2 (craft-libs#353: a drop beside a too-narrow frame at its row's edge) 2026-10-26 02:00:55 +00:00
skylar taylor-barrick 6f9197975d chore(deps): refresh safe dependency bumps (#3325)
serde_json 1.0.154, proptest 1.12.0, rmcp 3.6.0, tokio 1.54.1, base64 0.23.1,
schemars 1.2.3, objc2 0.6.5, arboard 3.7.0, open 5.4.5, winresource 0.1.34,
pollster 1.0.1, muda 0.21.2, ureq 3.5.0, rustls 0.23.46, zip 8.6.0.
2026-10-25 19:30:40 -04:00
Dylan M. Taylor fa0502602c build: pin craft-update to craft-libs main (495e597) (#3322)
Picks up the startup prompt without the glyphs a font may lack (storytold/craft-libs#343, #344): the close mark is painted and the version pill is ASCII, so apps that panic on a missing glyph no longer take the prompt down.

Part of tracking issue storytold/craft-libs#319
2026-10-25 17:55:43 -04:00
Dylan M. Taylor df106680d4 feat: startup update prompt modal and direct self-updating (#3298)
* feat: startup update prompt modal and direct self-updating

The update flow (check at start or on request, the startup prompt, the self-update worker) is craft-update's Updater; the app only supplies the suite, its close path and its status window. The check at start is opt-in for the desktop app, an install holds back while documents are unsaved, and the Windows update helper runs before argument parsing.

Ref: storytold/craft-libs#319

* build: refresh the lock

* fix(updates): drop the manual window's custom id; pin craft-update to craft-libs main (db19c37)

* fix(updates): address review feedback

Wake the UI when a manual check is queued from a menu callback; the update prompt owns the keyboard while it is open (LightCraft); Download opens through the desktop URL hook (FilmCraft); the Help menu dispatches through menus::invoke (FigCraft); print jobs and comment drafts hold an install back (WordCraft); Check for Updates is a registered command (GridCraft); an install holds back while documents are unsaved.

* fix(updates): localize the update status messages and format the sources

* fix(updates): give Check for Updates a Help menu hover hint
2026-10-25 16:22:56 -04:00
skylar taylor-barrick 320cae243d Migrate FilmCraft to egui 0.37 with current editing changes preserved (#3249)
* egui 0.37: migrate FilmCraft input and rendering integration

* egui-037: fix capture failures, UTF-8 input and hidden timing

* Fix screenshot crop scale for fitted native surfaces

* egui037: simplify UI helpers and preserve pointer IME cancellation

* Translate graphics and effect control accessibility labels

* egui037: Document capture and IME lifecycle contracts

* egui-037: document UI and input integration contracts

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
2026-10-25 14:45:04 -04:00
aiongg 75e89dffff Merge #3249 (egui 0.37) into docking-frame-trial 2026-10-25 17:16:31 +00:00
aiongg 217374ba5b docking: craft-libs 5bbe9f6 (main) 2026-10-25 16:58:17 +00:00
aiongg daeda75a11 Merge remote-tracking branch 'upstream/main' into docking-frame-trial
# Conflicts:
#	crates/ui-egui/tests/it/keyboard_ui.rs
2026-10-25 16:25:58 +00:00
aiongg 583fc2ebb9 docking: craft-libs d24e4bc (Mac round 3) 2026-10-25 14:02:11 +00:00
Brandon Thomas 30536bc5d0 Release 0.13.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:26:28 -04:00
aiongg 364d0ba18f docking: craft-libs 8a503cf 2026-10-25 03:55:40 +00:00
aiongg 190f5def2f docking: craft-libs 865c9af 2026-10-25 02:55:01 +00:00
skylartaylor 4ce159e1cd egui037: migrate FilmCraft UI and reconcile current main 2026-10-25 02:59:42 +01:00
aiongg 2ff95d03d6 docking: craft-libs 6e7f285
Repins craft-docpath, craft-media and craft-ui to storytold/craft-libs 6e7f285. No API changes are needed.
2026-10-24 23:05:59 +00:00
aiongg 7f77bd7377 docking: craft-libs 16fb3d4 with shared docking and native windows
craft-docpath, craft-media and craft-ui pin storytold/craft-libs main at
16fb3d4, which has craft-libs#264 and the undock-hint fix craft-libs#285.
craft-ui builds with `native-windows`.
2026-10-24 18:50:09 +00:00
aiongg 6d3e6daeab Merge remote-tracking branch 'upstream/main' into docking-frame-trial
# Conflicts:
#	crates/ui-egui/src/panels/mod.rs
2026-10-24 18:47:25 +00:00
Dylan M. Taylor 057f460085 security: harden developer tools, scripts, and testkit against hostile input (#3078) 2026-10-24 05:15:45 -04:00
skylartaylor df5f86ae31 egui 0.37: migrate FilmCraft input and rendering integration 2026-10-24 11:13:28 +02:00
Earl Co e69122c0b3 fix(speech): contain and verify downloaded model artifacts (#2867) 2026-10-24 04:51:16 -04:00
Earl Co d4595df9c4 security(tts): verify Kokoro checkpoint before parsing (#2918)
* security(av1): require unique complete tile coverage

* security(tts): verify Kokoro checkpoint before parsing
2026-10-24 04:49:53 -04:00
aiongg fa550ce2d0 Build: use craft-media for bitstream, isobmff and matroska (#2435)
* Build: use craft-media for bitstream, isobmff and matroska

filmcraft-bitstream, filmcraft-isobmff and filmcraft-matroska re-export
craft_media::{bitstream, isobmff, matroska} from craft-libs. The packages
and their public paths stay, so dependent crates build unchanged. The
integration tests in crates/isobmff/tests and crates/matroska/tests run
against the re-exports.

* Build: pin craft-media at 9db732e

craft-media spells the Matroska colour types in US English: Colour is
Color and VideoInfo::colour is VideoInfo::color. The spec names
element_ids::COLOUR, COLOUR_SPACE and VpcConfig::colour_primaries stay.

* matroska: the oracle skips the duration of a track's last frame

Ported from craft-media: the last audio or video frame of a track cut by
-t is shorter than a codec frame. ffmpeg 8 writes a shortened
BlockDuration and reports the codec frame duration; a remux by our writer
stores DefaultDuration and ffprobe reports the shortened one. Subtitle
cue durations are still compared. This fixes oracle::mjpeg_ac3 with
ffmpeg 8. The HDR test is named hevc_hdr_color, as in craft-media.

* matroska: laced_remux laces every audio track and checks timestamps

craft-media laces only tracks with a DefaultDuration. The remux gives
each audio track without one its mean packet spacing, so Vorbis, FLAC
and PCM lace too, and compares every packet's timestamp with the
source's. Ported from craft-media's oracle_matroska.rs.

* codecs: the Matroska audio timing test laces its Xiph case

craft-media laces only tracks with a DefaultDuration. The test's
Matroska helper sets the AAC access unit's duration (1024 samples,
rounded to the nanosecond), and the test checks that the Xiph-laced file
has laced blocks and the unlaced one has none.

* Build: repin craft-media to f97c84d27 (NAL length-size checks)

craft-libs#245 is on storytold/craft-libs main, so the dependency points there.

* Build: repin craft-media to f0ad6c1e1 (QuickTime v2 PCM entry limits)
2026-10-23 17:51:38 -04:00
Dylan M. Taylor c5c1693989 Use chrono instead of hand-rolled UTC conversion (#2662)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil_from_days / days_from_civil copies (app log
timestamp, Media Browser date column, auto-save file-name stamp, MXF header
timestamp, golden-image attribution date) with chrono as a workspace
dependency. The existing chrono entry on apps/filmcraft (clock feature) was
lifted to the workspace. Output formats are unchanged and pinned by tests.
AGENTS.md now says time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Never panic on a clock outside chrono's range; keep 5-digit years unprefixed

chrono's From<SystemTime> unwraps internally, so a clock past year 262143
panicked. logging::timestamp and golden::today now read the duration since the
epoch and go through the fallible DateTime::from_timestamp, reading an
out-of-range or pre-epoch clock as the epoch as the old saturating code did.
timestamp, today and media_browser::format_date write the year with {:04}
rather than %Y, which prefixes a '+' past year 9999.

Tests cover the far-future and year-10000 cases for timestamp and format_date.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* time: preserve out-of-range years instead of the epoch (FredApps review)

`DateTime::from_timestamp(..).unwrap_or_default()` changed the existing output:
inputs the old hand-rolled civil-from-days converted (e.g. `10_000_000_000_000`
s → 318857-05-20 17:46:40) collapsed to `1970-01-01 00:00:00`. Restore the old
conversion domain with a cycle-based helper: reduce by whole 400-year Gregorian
cycles (146_097 days), convert the in-range remainder with chrono, and carry the
year back as i128 (saturating to the output type). Only the year leaves chrono's
range; month, day and time of day are always exact.

Sites (all UTC):
- apps/filmcraft logging.rs `timestamp` (SystemTime, u64 secs): pre-1970 still
  clamps to the epoch; a far-future clock keeps its year. u64::MAX/2 s →
  "292277026596-12-04T15:30:07.000Z", 10e12 s → "318857-05-20T17:46:40.000Z"
  (was "1970-01-01..."). SystemTime cases built with a checked add (Windows-safe).
- crates/engine media_browser.rs `format_date` (u64): 10e12 s → "318857-05-20
  17:46", u64::MAX → "584554051223-11-09 07:00" (was "1970-01-01 00:00").
- crates/format autosave.rs `civil` (i64 + i32 offset): keeps years, e.g.
  i64::MAX → 292277026596-12-04 15:30:07, i64::MIN → -292277022657-01-27. The
  separate `unix + offset_secs` overflow guard (checked_add) is kept: only an
  overflowing shift (old code wrapped it to garbage) reads as the epoch.
- crates/mxf from_unix (i64): keeps month/day/time, clamps only `year` to the
  u16 field as before. 10e12 s → year 65535, May 20 17:46:40; -10e12 s → year 0,
  Aug 13 06:13:20.
- crates/testkit golden.rs `today` (u64): same helper; pinned via `utc_parts`.

chrono stays the only calendar logic (NaiveDate::from_num_days_from_ce_opt on the
in-cycle remainder). No new chrono features; still default-features = false, std.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-23 11:18:37 -04:00
Earl Co 9a0096a979 security(automation): isolate bridge screenshots (#2919) 2026-10-23 10:54:17 -04:00
Earl Co 68cfb0b52d security(text): keep font scans within configured folders (#2876)
* security(text): keep font scans within configured folders

* fonts: still find symlinked font files; skip only symlinked folders

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

* fonts: rustfmt

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

---------

Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:52:49 -04:00
Earl Co ebe15de141 security(bench): isolate temporary export outputs (#2928)
* security(bench): isolate temporary export outputs

* chore(bench): record tempfile dependency
2026-10-23 10:52:26 -04:00
aiongg 6a017acf41 Merge remote-tracking branch 'upstream/main' into docking-frame-trial 2026-10-23 04:58:02 +00:00
coderabbitai[bot] d3801e2df8 control: Require session-token authentication before dispatching requests (#2764)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-10-22 22:17:48 -04:00
Brandon Thomas 274c4cf85b Release 0.12.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:06:07 -04:00
Brandon Thomas 74242b51d6 Release 0.11.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:37:00 -04:00
skylar taylor-barrick 410f44e341 Merge pull request #1795 from g1obalworlds/fix/hostile-input-video-codecs
Hostile-input hardening for video decoders (AV1 panic + oversize allocation, MPEG-2 allocation) and fuzz tests
2026-10-21 17:09:37 -06:00
skylar taylor-barrick c6581d83a7 Merge pull request #2023 from nuclearspike/codex/security-aaf-extraction-collision
engine: preserve existing files when AAF/OMF imports embedded audio
2026-10-21 17:09:16 -06:00
aiongg 5963690cd3 UI.9: follow craft-ui docking at 958c5ad 2026-10-21 16:51:06 +00:00
aiongg 8525f836ad UI.9: follow craft-ui docking at 2fa4ad7 2026-10-21 16:30:24 +00:00
aiongg 9a590f0fcd UI.9: repin craft-ui to craft-libs 352a830 2026-10-20 15:49:18 +00:00