Commit Graph
281 Commits
Author SHA1 Message Date
32749e34f6 macOS: keep AppKit's Touch Bar observers when AccessKit drops (no crash on quit) (#4002)
* macOS: keep AppKit's Touch Bar observers when AccessKit drops (no crash on quit)

accesskit_macos 0.27.1 reset the window's view to WinitView when its adapter
dropped, discarding the key-value observation AppKit's Touch Bar finder had put
on the view's nextResponder. On quit, AppKit's removal of that observer raised
and _crashOnException: ended FilmCraft with SIGILL on Touch Bar Macs. 0.27.2
resets the class only while it is still AccessKit's own subclass.

Lockfile-only bump (accesskit 0.25.2, accesskit_consumer 0.39.2, accesskit_macos
0.27.2), with a test that fails below 0.27.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5nRpBjuSq2YBDMKU2Spqs

* filmcraft: accesskit lock test in the it binary; leave tempfile's getrandom as it was

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-03 00:10:12 -05:00
Jonathan Cardoso 96d8e22c2d Image-sequence export reports the stills it wrote, not the path it was given (#4018)
* fix(export): an image-sequence export reports the stills it wrote

An export to `a.png` as an image sequence writes `a000.png`, `a001.png` and so on, but the
job's result, `file.exportMedia`'s `path` and the CLI's "exported" line all named `a.png`,
which does not exist.

The report now names the first still, the name `file.import` and `probe --image-sequence`
take for a sequence. `file.exportMedia` and `export.quick` name it as `path` up front, from
the frame count `export.resolve` uses, and add `lastPath`. The CLI prints both. A single
file keeps its path.

Fixes #4009

* fix(automation): a cancelled image-sequence export is cleaned up by its stills' name

Since `file.exportMedia` names an image sequence's first still as `path`, the MCP cancel
clean-up took `a000` as the stem: it left `a001.png` and every later still, and the `a.srt`
sidecar, behind. The result now also carries `basePath`, the name the stills are numbered
from, and the clean-up goes by it.

* fix(automation): an image-sequence cancel clean-up keeps the base name and finds .jpeg stills

An image-sequence export numbers every still, a single frame included, so a file under its base
name (`a.png`) is never its own: cancelling one deleted a user's `a.png` if it was saved during
the export. The stills of a `.jpeg` sequence were left behind instead, since the extension was
read as a format name, and `jpeg` names Motion-JPEG there; `file.exportMedia` keeps `.jpeg`
for a JPEG sequence.

* fix(automation): a cancelled image sequence removes only the stills it numbered

The clean-up matched any `<stem><3+ digits>.<ext>` written during the export, so cancelling an
export to `a.jpeg` could delete `a1000.jpeg`, the first still of an export to `a1.jpeg` in the
same folder. It now takes the digits and the last index from the result's `lastPath` and removes
only those names: `a000.jpeg` to `a120.jpeg` for a 121-frame export.
2026-11-03 00:03:30 -05:00
Jonathan Cardoso 8841e02b2a cli: a missing project stops a save in place before it opens (#3946)
* cli: a missing project stops a save in place before it opens (#3944)

The save lock was taken only when --project was already a file. A project
created after that check but before Backend::open read it was opened and
saved with no lock, so a concurrent --save run could lose its edits.

A save in place on a missing project now stops at the check, with the same
error Backend::open gives. Runs that don't save over --project still leave
that error to Backend::open, and --bridge with --project stays a usage
error.

* cli: a missing project spelt two ways is still saved in place (#3944)

`--project p.fcproj --save-as ./p.fcproj` names one file, but when it
doesn't exist yet `canonicalize` fails on both spellings, so the run wasn't
seen as saving in place and skipped the missing-file check. Paths that
don't exist are now compared by their resolved folder and file name.
Existing files are compared as before. The error names `--project`, as
`Backend::open`'s does.

* cli: check that --project exists before comparing save paths (#3944)

Two findings on #3946 were the same race reached through other spellings
of a missing path: `./p.fcproj`, then `newdir/./p.fcproj` in a folder that
doesn't exist either. Each was a run that compared the paths, found no
match, and went on to open a project that wasn't there.

`saved_in_place` now checks `--project` first. A missing one stops the run
with the error `Backend::open` gave, whatever the run saves. Only existing
paths are compared after that, where `canonicalize` is exact, so the folder
fallback from the last commit goes.
2026-11-03 00:03:01 -05:00
Dylan M. Taylor 4a23548b7f web: load only a same-origin http(s) app in the WebCodecs read-error harness (#4103)
* web: load only a same-origin http(s) app in the WebCodecs read-error harness

* web: keep the app URL's own query flags in the WebCodecs read-error harness
2026-11-02 22:50:53 -05:00
Dylan M. Taylor 326b8625c6 web: check MP4 sample extent before allocating its buffer (#4102) 2026-11-02 21:16:39 -05:00
Jonathan Cardoso 5c73ee4af6 cli: --save runs on one project take turns, so no edit is lost (#3926)
* cli: --save runs on one project take turns, so no edit is lost (#3924)

A run reads the project, edits it and writes the whole file back, so two
at once silently dropped the edits of whichever saved first. A run that
saves over the file it opened now holds an OS lock on `.<name>.lock` next
to the project from before its read until it exits. The next run says so
on stderr, waits, then edits what the first one saved.

The OS drops the lock however the process ends, so a crash leaves nothing
stale. If the lock can't be taken the run warns and saves as it did before.
The desktop app and `mcp` sessions don't take this lock.

* cli: the save lock goes by the path being saved over (#3924)

A save through a symlink replaces the link with a plain file. Resolving
the path therefore gave the runs before and after that save different
locks, and a run still waiting on the old lock could overwrite a later
run's save. The lock now uses the path as written, so replacing the link
can't change which lock a run takes.
2026-11-02 00:38:13 -05:00
b3aeb7c3df Apply background mask tracking in headless sessions (#3303)
* Apply background mask tracking in headless sessions

Fixes #3302

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

* fix: drop pending mask-tracking jobs when the project is replaced

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

* fix: drop mask-tracking jobs started on a replaced project via document epoch

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-01 15:31:44 -05:00
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 1d523fba74 Integration: keep the app's SaveAs matches in step with the dialog's extension flag 2026-10-31 04:25:30 +00:00
aiongg 8595147b71 Merge integration track i18n 2026-10-31 02:17:34 +00:00
aiongg bf0386bf76 Merge integration track sys 2026-10-31 02:17:26 +00:00
aiongg 8f16aea983 Merge PR #3714: bs: Add Bosnian (bs) to the interface languages 2026-10-31 02:14:54 +00:00
aiongg 59695f22ae Merge PR #2344: i18n: Turkish (tr) interface catalog (#1377) 2026-10-31 02:13:56 +00:00
aiongg 5b839a4cef Merge PR #2007: fix: satisfy clippy::nonminimal_bool on Rust 1.96
Only the audio.rs hunk is kept; the other files already have the fixed form.
2026-10-31 02:13:56 +00:00
aiongg 5b83f337ab Merge PR #1930: i18n: Swedish (sv) interface translation 2026-10-31 02:12:36 +00:00
aiongg 3226bbd7f0 Merge PR #2138: fix(gpu): FXC compiles the effect stage, so DX12 keeps GPU effects (#1616, #1425, #1458) 2026-10-31 02:12:27 +00:00
aiongg 9a721c45f0 Merge PR #1693: fix(linux): add an "All files" filter to the Open Project dialog (#1644) 2026-10-31 02:12:26 +00:00
aiongg 75a6836784 Merge PR #3308: #2633: a press on the ruler closes no audio stream, and the default rate skips listing configs 2026-10-31 02:11:59 +00:00
aiongg 29a98f5f34 Merge PR #1710: i18n: add Polish interface language 2026-10-31 02:11:40 +00:00
aiongg f189bdabef Merge PR #1156: i18n: add Czech (cs) interface language 2026-10-31 02:11:03 +00:00
aiongg 6f68f084c8 Merge PR #1891: voice-over: the Mixer's input meter follows the microphone while recording 2026-10-31 02:10:12 +00:00
MOzcelik14 2e2f10498f Merge branch 'upstream/main' into feature/turkish-localization
Resolve conflict in crates/ui-egui/src/i18n/tests.rs using switch_and_check
helper and add 22 new catalog entries to tr.tsv matching upstream additions.
2026-10-30 13:50:46 +03:00
Claude 293d4e908d Add Bosnian (bs) to the interface languages
bs.tsv: Bosnian (Latin script, Ijekavian) catalog covering every key of
FilmCraft's other catalogs, its wording shared with storytold/craft-i18n
locales/bs/ and the strings craft-i18n lacks translated new. Every bs-*
locale selects it; counts use one/few/other. Locale and plural tests,
localization docs and an attribution entry (AI-assisted, not yet
reviewed by a native speaker).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
2026-10-30 09:05:03 +00:00
3590cd1bcf control: say why the control server is not serving (#3436) (#3535)
* control: say why the control server is not serving (#3436)

With --control but a missing or malformed FILMCRAFT_CONTROL_TOKEN the
server declined to start and said so only on stderr, which a desktop
launch has no reader for: the window opened, nothing listened, and the
bridge blamed the launch command.

- control server: log the disable reason and the listening state through
  log::warn!/log::info! so they land in filmcraft.log; start returns a
  typed Option<DisabledWhy> instead of hiding the reason
- desktop app: show the token reason in the status bar whenever it is
  idle (persistent but replaceable by any real status)
- --control-input-only: exit with an error when the server cannot start
  instead of parking a window that ignores all native input
- bridge: the connection-refused error names the token requirement
- i18n: status-bar string translated in the 8 active locales

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

* control: drop the unused ControlNotice::Bind and its catalog rows

A bind failure is only logged until #3318; nothing constructed the variant.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-30 01:46:18 -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
Michael HolzheuandCodex e94c42716a web: Keep WebCodecs enabled after media read errors (#3422)
Report source read errors as I/O failures without permanently disabling the
browser decoder. Pending reads still retry and real decoder errors retain
the software fallback. Add a synthetic browser regression that checks both
paths and recovery on a readable region of the same file.

Co-authored-by: Codex (GPT-6-Astra) <noreply@openai.com>
2026-10-30 01:21:58 -04:00
Michael ButlerandBrandon Thomas cc57ebb95b #3364: warn about one-frame In/Out exports (#3402)
* #3364: warn about one-frame In/Out exports

Show the marked range duration and an advisory in Export, command results, and CLI stderr. Preserve export contents and explicit-range behavior. Add engine, CLI, and UI regressions and document the warning.

* #3364: retain one-frame warnings in queued exports

Collect range advisories in export.queue.add while preserving queued ranges and existing response fields. Cover default and explicit queued ranges plus CLI --queue warning output.

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-30 01:20:44 -04:00
Sam SandweissandClaude Opus 5.5 f949574658 fix: satisfy clippy::nonminimal_bool on Rust 1.96
`cargo xtask ci` stops at clippy on stable 1.96.1: nonminimal_bool flags
four boolean expressions (file dialogs, timeline scroll, audio output
watchdog, and the ProRes decoder's frame-size cap). Rewritten to the
forms clippy suggests; same truth tables, NaN and overflow included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:07:50 -07:00
Tomasz LewandowskiandClaude Opus 5.5 929b67023a i18n: add Polish interface language
Adds a Polish catalog (pl.tsv) covering every Spanish entry plus the
macOS-only menu rows, registers Polski in the language menu, settings and
the native macOS menu, lists app.language.polish in the localization docs,
and adds a test that keeps the catalog complete and checks Polish letters
render with the bundled fonts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DukHNvUY45rjRnvtz91x33
2026-10-29 06:59:14 +01:00
Dylan M. Taylor be560f5aa8 Refactor filmcraft-cli for strict Clippy checks 2026-10-28 04:36:48 +00:00
LosminekandClaude Sonnet 5.5 589a68233b Merge upstream/main into cs-ui
Main moved i18n/mod.rs to i18n.rs (and tests to i18n/tests.rs) and split
engine settings.rs into settings/{prefs,schema}.rs. Re-applied the Czech
language entry, catalog lookup and tests in the new files, and the cs
mentions in the interface_language doc and the language choice list.
Czech: 3,617 rows, i18n-report 0 missing, ui-egui lib 244/0, engine
settings 44/0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 17:07:09 +01:00
MOzcelik14 9fc1631cbd Merge remote-tracking branch 'upstream/main' into feature/turkish-localization 2026-10-27 11:35:55 +03:00
aiongg 806fbe8af5 style: cargo fmt the moved test files 2026-10-26 18:20:21 +00:00
aiongg ba3079dc71 refactor(filmcraft): move control_server.rs tests to their own file 2026-10-26 18:20:21 +00:00
aiongg d9dff5ed89 refactor(filmcraft): move graphics.rs tests to their own file 2026-10-26 18:20:20 +00:00
LosminekandClaude Sonnet 5.5 ff97dc4b1c Merge upstream/main into cs-ui
The merge brought in Language::bcp47() without a Cs arm, so the branch did
not compile; added "cs". Translated the seven strings main added since
(audio output errors with the new ">" separator, the update check).
Czech: 3,617 rows, i18n-report 0 missing, ui-egui lib tests 244/0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 18:48:53 +01:00
Patrik Lermon d6a777b26f Merge remote-tracking branch 'upstream/main' into HEAD
# Conflicts:
#	crates/ui-egui/README.md
#	crates/ui-egui/src/i18n/mod.rs
#	docs/localization-parity.md
2026-10-26 08:26:34 +01:00
Dylan M. Taylor de529c88f4 chore: resolve SonarCloud maintainability issues (#3329)
* chore: resolve SonarCloud maintainability issues

* fix: repair CI on the Sonar maintainability refactor

- h264: the coefficient scratch is i32, so the method path is <[i32]>::first_chunk_mut
- hevc: Px::w32 takes self, so keep the closure over the &P from slice::get
- tts: upsamples is a method, not an importable item
- vp8: drop the unused B_DC_PRED/DC_PRED imports; cargo fmt the import lists
- ui-egui: editing no longer needs to be mutable
- packaging: keep literal printf formats (shellcheck SC2059)

* fix: restore the mutable binding in hot_number
2026-10-25 19:40:57 -04: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 7d8dd5ae78 Linux: default to XWayland for file drag-and-drop on Wayland desktops (#634) 2026-10-25 19:05:15 -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-barrickandDylan M. Taylor 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
BimThoi 655b26c008 #2633: a ruler press closes no audio stream, and skips the rate search
`scrub_playhead` called `stop()` on every press, and `stop()` closes the output
stream. A drag calls it twice -- once on the press, once when the drag starts --
so the grain the scrub had just started lost its stream a frame later, and the
next grain opened the device again: 0.5-1 s on WASAPI, on the UI thread, which
froze the playhead at the start of every click and drag. The press now stops only
a running transport, and the Source monitor's clock, which `stop()` leaves alone,
is stopped with it.

`stream_config` listed every supported configuration to find the rate, ~190 ms
per playback start (measured), while the default configuration is free: it is
now used as is unless the settings name a rate the device does not already run
at.

Part of #2633: the scrub's own output and the playback stream it reopens follow
in a separate pull request.
2026-10-25 23:45:37 +07:00
LosminekandClaude Opus 5.5 8e3bec5ace Merge remote-tracking branch 'upstream/main' into cs-ui
The conflict was in ROADMAP.md, where main recorded the ProRes alpha
work: the header names both changes and both revision-history rows
are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:08:15 +01:00
jahvariandCodex 87b093de61 CTL2807: release idle control connections after bounded socket waits (#2989)
Set two-minute read/write timeouts and close expired connections quietly.
Keep partial requests out of the UI queue and preserve the separate UI
reply wait and active connection reuse.

Fixes #2807.

Co-authored-by: Codex <noreply@openai.com>
2026-10-24 10:15:57 -04:00
MOzcelik14 b1bc3decea Merge upstream/main into feature/turkish-localization 2026-10-24 11:03:36 +03:00
LosminekandClaude Opus 5.5 8872fe008d Merge remote-tracking branch 'upstream/main' into cs-ui
Main reworked the i18n tests (#3012): catalogs are listed through
`Language::ALL` and `catalog_text`, missing translations no longer
fail a test, and the per-language coverage tests are gone in favour of
`cargo xtask i18n-report`.

- crates/ui-egui/src/i18n/mod.rs: main's structure, with Czech in
  `catalog_text`, the native-name table and the bare-code check
  (`cs-CZ`). The Czech coverage test is dropped, like the other
  languages' ones.
- docs/localization-parity.md: main's rows (no "must cover" wording)
  with the Czech row kept; both revision-history rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:03:20 +02:00
aiongg 0a881266c8 CI: xtask ci in the dev profile, one test binary per crate, nextest (#2860)
* Tests: one integration-test binary per crate

Each crate with several tests/*.rs files keeps them as modules of tests/it/,
so cargo links one test executable per crate instead of one per file. Files
that change process-wide state or time a workload stay binaries of their own.

* Profiles: line tables for workspace crates, no debug info for dependencies

* Windows ARM64: nightly and on release pushes instead of every push to main

* xtask ci: clippy and tests in the dev profile

The release profile's thin LTO and single codegen unit made linking the test
binaries take most of the gate. The codec and audio crates stay at opt-level 3
in the dev profile, so their tests run at release speed.

* xtask ci: nextest, doctests, no examples, one wasm check

Tests run with cargo nextest when it is installed (cargo test otherwise) and
build with --lib --bins --tests, so examples aren't linked; doctests run
separately. The wasm check keeps going past the first failing crate. VP8
fixture generation locks across processes, since nextest runs each test in
its own.

* VP9 synthetic fixtures: write aside and rename

A test in another process could read a fixture ffmpeg was still writing.

* Fuzz tests: a third of each sweep by default, all of it with FILMCRAFT_FUZZ_ITERS

Every seed, mutation kind and thread count still runs. Header bytes each get
one overwrite value and two bit flips in rotation, so every value and bit
index still occurs across the region. FILMCRAFT_FUZZ_ITERS=N runs the whole
sweep plus N random rounds per seed, as before.

* Platform fallback tests: one failure point per hybrid path

The failure-anywhere test injected a failure at four points around every
restart point; the hybrid's paths differ only in the first GOP, around the
second and last restart points, at the end and never. The replay test needs
the first two GOPs.

* Export tests: shorter ranges with the same checks

The bitrate test measures 0.5–1.5 s, where each preset reaches its own
target (on 0–3 s the simple demo left two presets at the same rate). The
every-preset test exports three frames per preset.

* Audio tests: effects in parallel, a table-driven FFT for the Opus quality metric

The extreme-settings test keeps both settings and the 40 s tail for every
effect, one thread each. The Opus quality metric's FFT builds its twiddles
once and allocates nothing per transform (same algorithm and summation order).

* CI: dev-profile gate with nextest

xtask ci no longer builds with --release, so the release-profile overrides
go; nextest is installed for the test step.

* CI: apt packages through the cached install-apt-packages action

* Review fixes: fuzz tests with a panic hook in their own binaries, loud fixture lock

The fuzz tests of av1, h264, hevc, mpeg2v, vp8 and vp9 count panics through
a process-wide hook, so a panic in another test of the same process would
fail them; they are binaries of their own again. The VP8 fixture lock fails
the test instead of skipping it silently, and the full-sweep doc comments say
how many truncation points the full run samples.

* Fuzz tests: rotate the default subset per run (FILMCRAFT_FUZZ_SEED replays one)

* platform tests: decode-switch tests in their own binaries, one NVENC lock
2026-10-23 13:34:16 -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
Dylan M. Taylor 689e37782a fix: harden CLI file I/O and AV1 tooling (SonarCloud)
- Read and write CLI inputs/outputs on a blocking pool instead of stalling
  the async runtime (rust:S7493).
- Document the FLAC STREAMINFO MD5 as the RFC 9639 integrity signature it
  is, and validate the AV1 generator's spec path before reading it.
- Normalize the DCT basis literals that read as numeric suffixes.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-10-23 09:53:17 -04:00