Commit Graph

209 Commits

Author SHA1 Message Date
Brandon Thomas 156535a6e4 Merge origin/main into i18n-spanish-panels
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	crates/codecs/tests/mpeg_oracle.rs
2026-10-09 09:59:28 -04:00
Brandon Thomas 183884fd34 web: WebCodecs busy check honours STALE_MS; checked row offsets in plane()
A copyTo that never settles kept copying > 0 and bypassed the stale timeout,
wedging the session; now busy requires recent output. plane() computes each
row's start/end with checked arithmetic and bounds it by the validated end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:58:06 -04:00
Brandon Thomas de1320dc88 Merge origin/main into i18n-spanish-panels
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:57:17 -04:00
Brandon Thomas 67634241c8 Merge remote-tracking branch 'origin/main' into fix-375 2026-10-09 09:56:15 -04:00
Brandon Thomas b3f2a89944 Windows: default to Vulkan | DX12 | Metal (drop only GL) instead of forcing DX12
Forcing DX12 compiles shaders through FXC, which rejects fx.wgsl (silent CPU
fallback), and leaves machines without DX12 with no backend. Leaving GL out is
what avoids the AMD atio6axx.dll crash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:44:20 -04:00
Brandon Thomas aff136ff67 Merge remote-tracking branch 'origin/main' into fix-365
# Conflicts:
#	apps/filmcraft/src/main.rs
2026-10-09 09:44:20 -04:00
Brandon Thomas c497b648f5 Merge origin/main into i18n-spanish-panels
Resolve conflicts: keep main's macOS/other hint text and mask vertex
tooltip variants (each wrapped in tl!), take main's shared keyframe_nav
helper and translate its tooltips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:34:01 -04:00
Brandon Thomas 33f3656071 #262: drop new apps/filmcraft/README.md; explain file filters in module docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:33:38 -04:00
Brandon Thomas 45e951ff61 Merge remote-tracking branch 'origin/main' into fix-390
# Conflicts:
#	apps/filmcraft/src/main.rs
2026-10-09 09:33:32 -04:00
Brandon Thomas de0299bd1b Merge remote-tracking branch 'origin/main' into fix-240
# Conflicts:
#	apps/filmcraft-web/tests/smoke.mjs
2026-10-09 09:27:59 -04:00
Brandon Thomas 9736b2a6ba
Merge pull request #264 from carlitosteso3/fix/recovery-retry-197
#197, #193: web recovery retries failed snapshot writes and keeps skipped snapshots dirty
2026-10-09 09:25:20 -04:00
Brandon Thomas 996ccf72fd
Merge pull request #349 from rossaai/rossa/embedding-hooks
Embedding: set_context on the web app, header and status bar flags, status bar colour token
2026-10-09 09:24:31 -04:00
Brandon Thomas ae79acad8a
Merge pull request #241 from WavJaby/fix/import-bin
fix(import): use the open Project bin as destination
2026-10-09 09:24:07 -04:00
Brandon Thomas e919d3f80b
Merge pull request #249 from switch87/desktop-log-file
Desktop: write log records to standard error and a rotating log file
2026-10-09 09:23:08 -04:00
Brandon Thomas bfa819a448
Merge pull request #358 from JordyUSA/vaapi-h264-decode
HW5: Linux VA-API hardware decoding for H.264 and HEVC (Main / Main 10)
2026-10-09 09:22:56 -04:00
Manuel Camacho 2b0f263418 GPU3: render exports on the GPU compositor (#30)
Add off-screen GPU export renderer (filmcraft-gpu::ExportRenderer) reading back
the linear float accumulator as premultiplied RGBA f32, plug it into the
export pipeline via FrameRenderer hook and GpuRendering setting, register
in desktop app and CLI, and record export.gpu_frames statistics.

🤖 Completed by agy (Antigravity Agent, Gemini 3.8 Flash) based on draft by Merlin
2026-10-09 06:18:17 -07:00
Brandon Thomas d51f6b1b7d
Merge pull request #362 from JordyUSA/fix/341-export-message
#341: CLI export message names the file written, not the requested path
2026-10-09 08:16:41 -04:00
txiki739 43e3d26823 #218: System Language follows the operating system's language
Settings > General > Interface Language gains System Language
(`system`), now the default: a new installation shows the first of the
user's preferred languages that the interface has (es-419, pt_BR.UTF-8,
ja-JP...; any Portuguese gets pt-br), otherwise English. A language
already chosen, or saved in preferences.json, is kept.

The host supplies the preferred languages through
HostHooks::system_languages: sys-locale on the desktop (LANGUAGE,
LC_ALL, LC_MESSAGES, LANG on Linux; the OS lists on macOS/Windows) and
navigator.languages on the web. Without the hook (tests, headless),
System Language is English, so tests do not depend on the machine's
locale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:06:43 +02:00
txiki739 5f3682fe7c #262: file dialogs list extensions in any capitalisation on Linux
rfd hands filter extensions to the XDG portal, GTK and Zenity as
case-sensitive `*.ext` globs, so `CLIP.MP4` and `clip.Mp4` were hidden.
`file_filters::extensions` keeps the given extensions first (the save
dialogs' default suffix) and, outside Windows and macOS, adds one
bracket pattern per extension (`mp4` -> `[mM][pP]4`), the form the
portal's FileChooser docs recommend.

Every filtered dialog uses it: import, relink, Open file, Open
Project, Save Project and Save As.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:06:35 +02:00
WavJaby 6893cb4f03 perf(web): feed native YUV frames to the shared compositor 2026-10-09 13:47:06 +08:00
JordyUSA 9e8ad1d6a2 #341: CLI export message names the file written, not the requested path
When the format changes the extension (APV into `out.mp4` writes
`out.mp4.mov`), `filmcraft-cli export` said "exported out.mp4" on stderr
while stdout JSON and the filesystem had `out.mp4.mov`. The message now
takes the path(s) from the export result: `path` of a direct export, each
item's `path` with --queue; the requested path only when the result names
none. Unit test for the helper; end-to-end test (direct and queued APV
export) that failed before the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:53:28 +07:00
Idiotic f146d7ba9f feat(media,engine): implement multi-stream container audio support and schema v13
- Update MediaInfo to store all discovered audio streams in audio_streams

- Retain independent stream metadata and decoder state for MP4/MOV and Matroska/WebM

- Update audio_placement_specs to allocate successive tracks via ensure_audio_tracks

- Isolate clip rendering to read assigned audio stream rather than replaying stream 0

- Bump project schema to v13 with backwards compatibility for legacy v12 projects

Resolves #312

Fixes #200

Fixes #315
2026-10-08 22:36:45 -04:00
jnohclee-rgb 0bfea22e1b cli: make --help print usage successfully
Fixes #344. Handle the leading help flag before command parsing and decoder registration; cover output and exit status with a native CLI regression.
2026-10-09 10:14:06 +08:00
Cathy Shapiro 9f0ed51b49 M3.12: Export frames from Source and Program monitors
Wire both camera buttons to captured-monitor frame export with original media at full resolution. Add a movable settings dialog with format/depth selection, a visible destination folder, Browse, overwrite confirmation, and optional project import.

Reuse existing 8-bit still encoding; add JPEG and direct float-to-16-bit PNG/TIFF encoding. Cover monitor routing, captured frame time, proxy bypass, hostile parameters, depth, import, cancellation, overwrite, and fractional header movement with synthetic regressions.

Assisted-by: Codex
2026-10-08 20:46:12 -05:00
JordyUSA 3496e553e7 HW5: Linux VA-API H.264 hardware decoding (#30)
Stateless VA-API decoding with FilmCraft's own H.264 host side: the
software decoder's SPS/PPS/slice-header parsers and its DPB (now generic
over the picture type in filmcraft-h264) drive the GPU, so reference
marking, reference lists and output order are shared and the pictures are
bit-exact with the software decoder. libva is loaded at run time; no libva
or driver means software decoding as before. frame_num gaps (open-GOP
seeks) get the software decoder's stand-in frames. HybridDecoder keeps the
transparent software fallback.

Tests: hardware parity on 7 H.264 streams incl. 1080p/2160p, seeks,
flushes, forced failures, fuzzing, concurrency; front end against a
recording stand-in on every OS; ABI checks against va.h. Docs: platform
README, ADR 0001 addendum, architecture, performance (H.264 2160p CPU per
frame 417 -> 11 ms on Iris Xe), roadmap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:35:57 +07:00
rossaai 83501964f6 Web: public set_context for a host that runs its own WebApp
post and repaint wake the egui context that start stores in a private
thread-local. An app that embeds FilmCraft and builds WebApp in its own
eframe runner had no way to set it, so posted actions and window.filmcraft
requests waited for the next input event. start now calls the same
set_context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:57:43 -05:00
DWAA1660 8d6461705e
Fix #179: default Windows startup to DirectX 12
eframe's default wgpu instance enables PRIMARY | GL on Windows. Creating
the OpenGL backend can crash inside AMD's atio6axx.dll before the window
appears, so the app flashes in Task Manager and exits. When WGPU_BACKEND
is not set, the Windows instance now enables only DirectX 12; an explicit
WGPU_BACKEND is still honoured. macOS, Linux and web are unchanged.

Same fix as storytold/designcraft#168.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyVbT6Vv4BwWZ4hY8973qD
2026-10-08 17:52:30 -06:00
Oldrich333 44248c060f CLI: a closed stdout no longer panics filmcraft-cli, and the work still finishes (#285)
`filmcraft-cli commands | head -c 10` panicked with "failed printing to stdout: Broken pipe
(os error 32)". Output now goes through `outln!` / `out!`. When stdout fails, later output is
dropped but the program does not stop: the rest of `exec`, `run` and `import` (later script
lines, `--save`, `--save-as`) still runs and the exit status still reports a failing command.
Exiting at the first failed print would report success while skipping the save, e.g.
`filmcraft-cli run edits.jsonl --project p.fcproj --save | head -1`. A closed pipe is not an
error; any other stdout write error is reported and makes the exit status 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 17:09:53 -04:00
Manuel Camacho beebdbcd39 M7.12: natural Text to Speech voices (Kokoro-82M in pure Rust)
- filmcraft-tts (feature kokoro): Kokoro-82M on candle, implemented from
  the StyleTTS 2 / iSTFTNet / ALBERT papers, config.json and the
  checkpoint's tensor shapes; official .pth read with candle's restricted
  pickle reader; voice packs from their zip. Neural Voice: tts-text
  phonemize -> Kokoro per chunk -> pauses -> pitch via audio-dsp.
- catalog: 9 US English voices (model card grade C+ or better) + CMUdict,
  every file pinned to a revision and SHA-256 (336 MB).
- speech: generic download_files (same verified downloader).
- engine: tts.render (background synthesis into Session::tts_cache),
  tts.downloadVoices (background job, cancellable), voices list with
  package state; feature neural-voices (default on in the desktop app).
- ui: natural/basic voice groups, consent box (size, sources, licences),
  download progress + Cancel, synthesis never blocks the window;
  ui.set {tts:{...}} for agents.

Measured: Whisper-base WER on 50 original sentences 2.1-3.6 % for all 9
voices (built-in robotic voice 96.6 %); 2.2-2.3x real time on CPU.
Gates: fmt, clippy, layers, assets, wasm pass; tests pass except
shortcuts_tests::assign_reassigns_conflicts_and_undoes (fails on main)
and the frame pool test (flaky under load, passes alone).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:52:30 -07:00
Ahmed Hosny 9bf6595ccd Playback: fall back to a working output device when the ALSA default cannot be opened
On a machine whose ALSA default PCM is misconfigured (missing 99-pipewire-default.conf symlink, #23/#106) the host default could not be opened: playback ran without sound and without any user-facing message. The device picker now falls back to the first output device that can open, logs why, and a new defaulted AudioOut::note() surfaces the note in the status bar (first frame and when playback starts); a machine with no device at all reports it too.

🤖 Generated with [Kimi Code](https://github.com/storyteller/kimi-code)
Co-Authored-By: Kimi <noreply@storyteller.dev>
2026-10-08 13:59:59 +03:00
Gert Pellin 2d6c4d3a3d Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error! in
the workspace was discarded: GPU compositor fallbacks, audio output
problems, a panicked frame job or audio mixer, container warnings. A
launch from a desktop menu has no terminal either, so there was nothing
to attach to a bug report.

apps/filmcraft/src/logging.rs (no new dependency):
- standard error plus <data dir>/Logs/filmcraft.log, next to the crash
  logs (--data-dir / FILMCRAFT_DATA_DIR respected, Help > Reveal Log Files
  opens the folder); each launch rotates the previous log to
  filmcraft.1.log and .2.log, so the log of a run that crashed survives
  the next start; the file is capped at 16 MiB
- records logged before the data directory is known are buffered
  (bounded) and written once the file is attached
- default levels: info for filmcraft*, warn for everything else;
  RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
  error as the only sink; a poisoned lock is tolerated
- the realtime audio callbacks do not log; a record holds the lock for
  one write of an already formatted line

The logger is installed first in main (before the panic hook) and the
file is opened after argument parsing (--help, --version and usage
errors leave no file). The start-up eprintln!s in main (auto-save
unavailable, open/recovery errors, no window) now go through the logger.
Documented in docs/contributing.md (environment variables, Logs).
2026-10-08 11:37:02 +02:00
Ahmed Hosny f14d8b7ec9 Merge branch 'main' into fix/linux-dev-desktop-icon 2026-10-08 11:37:31 +03:00
Ahmed Hosny 538a329935 linux: install a dev desktop entry so the taskbar shows the app icon
A dev run (cargo run) has no installed .desktop entry or hicolor icon for
the app id the window sets (ai.storyteller.filmcraft), so KDE (Wayland and
X11) falls back to the generic Wayland icon in the taskpanel and the
window topbar. Packaging installs both; development did not.

At startup on Linux, when no ai.storyteller.filmcraft.desktop exists in
any XDG data dir, install one into $XDG_DATA_HOME/~/.local/share
(applications/) plus the 256/512 hicolor PNGs, with Exec pointing at the
running binary. A packaged entry is never overridden; failures print a
warning and the app carries on (AGENTS.md §0).

🤖 Generated with [Kimi Code](https://github.com/storyteller/kimi-code)
Co-Authored-By: Kimi <noreply@storyteller.dev>
2026-10-08 11:37:31 +03:00
WavJaby aa66dd9c8d fix(import): use the open Project bin as destination
Resolve the shown Project bin for file-dialog and dropped imports. Capture the browser destination before asynchronous media reads so navigation cannot redirect an in-flight batch.
2026-10-08 16:27:48 +08:00
WavJaby 3e39952e0b fix(web): preserve distinct same-name media imports
Allocate an unused virtual path for every browser import so equal-size media cannot replace existing sources. Add an OPFS recovery regression for issue #194.
2026-10-08 16:18:07 +08:00
txiki739 4af4765278 Merge storytold/main into i18n-spanish-panels
Brazilian Portuguese (#176) moves to the catalog system as i18n/pt-br.tsv (the
menu entries unchanged) and joins the general.interfaceLanguage preference. The
new UI text from main is wrapped and translated into Spanish: the credits
window, Text Properties, H.265 export rows, Clip Speed / Duration, Color Matte
dialogs, the voice-over discard button, the time-left suffix and the audio
output status messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:59:32 +02:00
Claude 7fbb223707
#197, #193: web recovery retries failed snapshot writes and keeps skipped snapshots dirty
The OPFS recovery snapshot (apps/filmcraft-web) had two problems:

- #197: opfs::write never reported failures, and Autosave recorded the
  revision as snapshotted before the write ran. A failed write was only
  retried after the next edit.
- #193: the first tick of a clean session wrote {"dirty": false} to the
  meta. Starting with ?norecover or ?fresh therefore discarded a
  snapshot that was never reopened.

The decision of when to snapshot or mark clean moves to a pure module,
recovery_policy, tested natively in tests/recovery_policy.rs. Failed
writes (snapshot or clean meta) are retried after the 5 s interval
without another edit, and the meta is only marked clean to retire a
snapshot this session wrote. opfs::write_then reports whether a queued
write landed (coalesced writes report the newest one's result).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012HrAqZmrrDLRpxBJatxvaJ
2026-10-08 04:37:53 +00:00
Luna 5ee3ff64e9
Web: Link Media Locate… links the chosen file to the selected missing clip (#111) (#174)
* Web: Link Media Locate… links the chosen file to the selected missing clip (#111)

Link Media ▸ Locate…, `media.attachProxies` and `media.reconnectFullRes` all
need the chosen file's path back synchronously so they can call the engine
with `item` + `path`. The existing `pick_files` hook imports every chosen
file as a new project item, so on the web build (where the browser picker is
asynchronous and the hook returned `Vec::new()`) the command ran without a
path and the file silently landed as a new project item instead of being
relinked. On native the same hook worked because rfd returns paths
synchronously.

Add a separate `pick_file_for_relink` hook that returns the chosen file's
virtual path synchronously. Native hosts open an rfd dialog; the web host
registers the file in `/files/<name>` via a pending slot and runs
`media.relink` itself when the picker resolves. The three call sites prefer
the new hook and fall back to `pick_files` when the host has not installed
it (so the import flow used by every other dialog stays unchanged).

Fixes #111

Co-Authored-By: ninso112 <ninso112@pm.me>

* Co-ship: Luna161 ack'd and reviewed fix/111-link-media-locate

Reviewed the pick_file_for_relink hook routing, the take_files relink path,
and the regression test. Looks correct end to end; ready for upstream review.

Co-Authored-By: ninso112 <ninso112@pm.me>

* #111: relink hint names its command; no pending state after a cancelled picker

- RelinkHint carries the command (media.relink / attachProxies / reconnectFullRes), so the
  web host no longer runs media.relink for Attach Proxies and Reconnect Full Resolution.
- The web picker hands the hint to its own callback instead of a thread-local slot, so a
  cancelled picker can't turn the next ordinary import into a relink.
- Replace the hook-only unit tests with a UI test that drives Link Media ▸ Locate….

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

---------

Co-authored-by: ninso112 <ninso112@pm.me>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:35:58 -04:00
txiki739 b6cdc9dd7a i18n: Spanish for the whole interface, catalogs and a remembered language
Translations move from Rust tables to one catalog per language
(crates/ui-egui/src/i18n/<code>.tsv), looked up through HashMaps. UI code
wraps its strings in tl!("…") and tlf!("…{name}", name); names from
registries (effects and parameters, settings, commands, panels, workspaces,
export and effect presets) are translated where they are drawn, so command
ids, automation ids and preference values stay English.

Spanish now covers menus, panels, dialogs, the Settings pages, the Effects and
Effect Controls registry, the Keyboard Shortcuts dialog and status messages
(about 3,350 entries). Tests fail when a tl!/tlf! literal, a menu label or a
registry name has no Spanish entry, and check catalog syntax, duplicates,
placeholders and ellipses. Searches match the Spanish label as well as the
English source. Window titles keep their English egui ids.

The language is stored in the general.interfaceLanguage preference (also in
Settings > General) and restored on startup; a failed preferences write still
switches the interface and says it could not be saved. Template values are
inserted literally, so a file name containing braces is not re-substituted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 01:41:48 +02:00
cirocueto2013-wq 7151d329d6 fix: support integer CPAL devices and recover voice-over/audio failures
Co-authored-by: Codex <noreply@openai.com>
2026-10-07 20:33:33 -03:00
Brandon Thomas fcf1c45583 Merge pull request #141 from SaymonMaster14/feat/windows-media-foundation-hwdecode
Windows: Media Foundation/D3D11 hardware H.264 + HEVC decode

# Conflicts:
#	README.md
#	ROADMAP.md
#	crates/platform/Cargo.toml
#	crates/platform/src/lib.rs
#	docs/architecture.md
#	docs/performance.md
2026-10-07 17:48:06 -04:00
Brandon Thomas b5f197567b Merge pull request #186 from dcarnelutti/platform/videotoolbox-hevc-encode
platform: H.265 (HEVC) export with VideoToolbox

# Conflicts:
#	crates/export/src/settings_tests.rs
#	crates/ui-egui/tests/export_ui.rs
2026-10-07 17:47:10 -04:00
Dario Carnelutti 790b3a0697 platform: H.265 (HEVC) export with VideoToolbox
Adds `Format::Hevc` (Export > Format > H.265 (HEVC); `"format": "hevc"` in
`file.exportMedia`): HEVC Main, 8-bit 4:2:0, in MP4 (`hvc1`) or QuickTime, with AAC audio,
encoded by the macOS hardware encoder. There is no built-in H.265 encoder (one in pure Rust
is a project of its own, and x265 is GPL), so the format exists only where the OS has one.

- `videotoolbox_encode`: the session wrapper creates HEVC sessions too (`VtProfile::HevcMain`;
  the profile also says which codec). Keyframes are the HEVC random access points (NAL types
  16 to 21); the parameter sets are VPS / SPS / PPS; the `hvcC` record in the MP4 sample
  entry is the one VideoToolbox writes (sample description extension atoms), so profile,
  level and flags are the encoder's own. `VtEncoder::uses_hardware()` asks VideoToolbox
  whether the session runs on a hardware encoder (a test checks H.264 and HEVC), so a
  requirement dropped by accident could never become a silent software encode.
- `hardware_encode`: one adapter for both codecs. Choosing the format is the opt-in (the
  `hardware_encoding` setting is for H.264). `hevc_available()` (one small hardware session,
  created once) is registered with the new `filmcraft_export::register_format_probe`, so
  `available(Format::Hevc)`, the format list of Export mode and `exportFormats` follow the
  machine. `Format::has_builtin_encoder` says which formats need such a probe.
- `export`: `Format::is_h26x` where H.264 and H.265 behave alike (MP4 or QuickTime, AAC, size
  estimate, summary line). Two-pass VBR is refused up front ("H.265 export has no two-pass
  mode") and HDR sequences export as SDR, because there is no encoder to fall back to.
- Export mode: H.265 shows H.264's multiplexer, audio, metadata and bitrate controls, without
  profile, level, two-pass or the hardware checkbox, and says "Encoder: Hardware".

Apple M1 (8 cores), 1080p25, a 9:29 timeline (camera clip, ProRes 4444 overlays, AAC,
loudness): hardware H.265 at 10 Mb/s 195 s, hardware H.264 at 20 Mb/s 204 s (CPU 1029 s and
1042 s; the same H.264 export took 193 s and 200 s on other runs). It is not faster: the codec
that compresses further is the more expensive one (raw encoders: 166 and 189 frames/s), and
the export is bound by the CPU compositor, not by the media engine.

Quality per bit, 30 s of the same timeline against a ProRes 422 HQ export (average PSNR over
the three planes, SSIM): 20 Mb/s 46.88 dB / 0.9902 (H.264) and 46.91 dB / 0.9903 (H.265);
10 Mb/s 44.96 / 0.9863 and 45.09 / 0.9863; 6 Mb/s 43.72 / 0.9833 and 44.31 / 0.9843; 4 Mb/s
42.91 / 0.9807 and 43.64 / 0.9825; 3 Mb/s 42.37 / 0.9786 and 43.05 / 0.9807. The same picture
at 10 Mb/s and above; at 3 to 6 Mb/s H.265 needs 22 to 31 % less bitrate for the same PSNR.
Both formats therefore keep the same default bitrate. Details in docs/performance.md (HW3).

Tests: tests/hardware_encode.rs gets the HEVC counterparts of the H.264 ones (what is taken
and declined, a round trip through our HEVC decoder with luma PSNR above 30 dB, keyframes, MP4
and QuickTime exports with AAC, ffmpeg / ffprobe reading `hevc` / `Main` / `hvc1` /
`yuv420p` / BT.709, exact sizes, hostile configurations, encoders dropped at any point, the
format list agreeing with the probe, sessions on the hardware encoder); settings_tests.rs
checks names, ids, defaults, the summary, two-pass refusal and the probe; export_ui.rs the
controls H.265 shows and hides.

Stacked on the hardware H.264 encoder (the first commit of this branch).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 14:00:08 -06:00
RicSchonfelder 9a4a85d8e1 i18n: Brazilian Portuguese (pt-br) joins Edit > Language
Language::PtBr is persisted as pt-br and translated through a new
PORTUGUESE table with the same 347 menu labels as SPANISH, so every
translated key still resolves to a real menu item. The new
app.language.portuguese command checks, switches and restores the
language like the other three, and the native menu maps it back.
Cargo.lock is untouched.
2026-10-07 15:26:26 -03:00
Brandon Thomas b82825acb8 Web: window.filmcraft rejects with Error objects everywhere (#90)
readFile (missing path), importUrl and openProject (HTTP errors) and openProject (neither a File
nor a URL) rejected with plain strings, so e.message was undefined and e instanceof Error false,
unlike execute / request. Their promises now go through as_error, which wraps a string in an Error
and passes an Error through unchanged.

Checked in Chrome against the web build: all four cases reject with an Error carrying the message
("/files/nope.mp4: not found", "…: HTTP 404", "need a File or URL").

Fixes #90

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:57:48 -04:00
Brandon Thomas fa67dfa372 Docs: releasing guide, CLI export options, README and CLAUDE.md drift (#85, #86, #87, #88, #99)
- docs/releasing.md (#99): release.yml points readers to it twice and it didn't exist. Written from
  the workflow and packaging scripts as they are (macOS, Windows x64/x86/arm64, Linux x86_64/aarch64
  with the glibc 2.35 floor, web; draft release, secrets).
- filmcraft-cli help (#86): export lists --scale, --quality, --no-audio and --queue, and apv among
  the formats.
- README (#87): more than 650 engine commands (671 today), not about 135.
- README (#88): the web line says the browser app ships with every release and links docs/web.md.
- CLAUDE.md (#85): the Illustrator-class sibling is ../vectorcraft (formerly DrawCraft).

Fixes #85
Fixes #86
Fixes #87
Fixes #88
Fixes #99

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:49:08 -04:00
Brandon Thomas bd12dcae81 Bridge: a blocking export runs as an app job, so it neither times out nor freezes the app (#91, #92)
file.exportMedia with wait: true was forwarded to the app unchanged. The app then encoded on its UI
thread: it showed no progress and answered no other control request until the encode ended, and the
control server's 60 s reply limit reported "timeout" for any longer export while it went on and
succeeded.

BridgeClient::execute now starts the export without wait and polls jobs.list until the job
finishes, returning the same {job, path, result} (or the export's error). filmcraft-cli --bridge
exec and MCP bridge mode both use it, and MCP command_run in bridge mode now gets the same progress
notifications and cancellation as headless mode.

Tested against a fake app (wait: true never reaches it, one export started, result and error
returned) and end to end against the desktop app: a blocking demo export returned its 642-frame
result with exit 0 while ui.inspect was answered in ~0.05 s throughout.

Fixes #91
Fixes #92

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:42:28 -04:00
Davi Andrei 5e440a6607 Windows: Media Foundation / Direct3D 11 hardware H.264 + HEVC decode (#30)
New backend in crates/platform (media_foundation/): a Direct3D-aware decoder MFT is driven at the
level of single access units (Annex B), given the process's D3D11 video device through an
IMFDXGIDeviceManager so it decodes with DXVA, and its NV12 / P010 textures are read back through a
staging texture into planar Yuv8 / Yuv16. H.264 Baseline/Main/High and HEVC Main / Main 10, 4:2:0.

- Hardware is verified: non-D3D-aware or async MFTs, streams the GPU's DXVA decoder does not list,
  and system-memory output (Microsoft's MFT software fallback) are declined or fail the stream so
  HybridDecoder continues with our decoder.
- mfplat.dll is loaded at run time so Windows N editions still start.
- register() / registered() / hardware_decoder_for() cover Windows; perf.stats reports the backend.
- Tests (Windows): bit-exact parity with the software decoders at 640x360, 1080p and 2160p
  (resets, seeks, flush), forced mid-stream failure, damaged input, concurrency, repeated init.
- Bench: runs on Windows (ffmpeg on PATH, process/thread CPU clocks), HEVC Main 10 2160p row,
  hardware counters per row.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMorBHwct72udS2LiC3ZHp
2026-10-07 10:07:40 -03:00
Brandon Thomas 7916cfb80e
Merge pull request #131 from punkhop/fix/audio-plays-ahead
Audio: mix playback 200 ms ahead so a busy Mac doesn't drop sound
2026-10-07 07:08:29 -04:00
Brandon Thomas a4c4d38550
Merge pull request #123 from Luskish/fix/control-close-on-malformed-input
Control: close the connection on input that isn't a request (#119)
2026-10-07 05:57:55 -04:00
Brandon Thomas 98979fdf74
Merge pull request #127 from carlitosteso3/i18n-spanish
i18n: Spanish interface language (Español)
2026-10-07 05:57:31 -04:00
Brandon Thomas df3b4ecbde Control: a connection's slot is freed even if its thread panics or can't start
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 05:56:23 -04:00
Peet Guercio bb5d7ca0a6 Audio: mix playback 200 ms ahead so a busy Mac doesn't drop sound
Problem: playback decoded and mixed every ~10 ms device buffer inside the
cpal callback (AAC decode, effects, opening a clip's file at a cut, rayon,
locks). On a loaded Mac any stall missed the device deadline: static and
dropouts, different on every play.

Solution: play_ahead mixes on its own thread into a lock-free ring kept
200 ms ahead; the callback only copies. An underrun plays silence, is
counted, and the mixer skips the same span so sound stays locked to the
picture. Any device width plays the channels it shares with the mix.
perf.stats reports playback.audio (callbacks, underruns, missingFrames,
minLeadMs). The program mix moved to playback_mix so bench_audio can play a
real project through a simulated 48 kHz device and count dropouts.

Context: on a real 22-sequence project, load average 38-58, 15 s per cut:
mixing in the callback overran 8-170 times, mixing ahead 0 (ring never
below 149 ms). The web build keeps mixing in its callback (no threads).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 23:47:47 -07:00
carlitosteso3 ed535180cb i18n: Spanish interface language
Add Español next to English and 日本語 (Edit ▸ Language ▸ Español, also in the
native menu bar). SPANISH covers every menu, submenu and menu item label
(347 entries, Latin American Spanish); names, formats and percentages stay
as they are. A new test checks that every entry is a current menu label, so
a renamed command cannot leave a dead entry behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:06:02 -05:00
Luskish 023127e146 Control: close the connection on input that isn't a request (#119)
A line that is not a JSON object with a string `method` (an HTTP request
line, other non-JSON text, a JSON array, invalid UTF-8, a line over 4 MiB)
now gets one error reply and the connection is closed, so a browser's
cross-origin fetch can't smuggle a command in its body. Connections are
capped at 16. Same transport as LightCraft (storytold/lightcraft#129).

Fixes #119.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:32:13 -04:00
EthanSuquet 2b49201e84 codecs: video frames are looked up by the nearest timestamp unit, so a 1 ms WebM shows every frame
Problem (#73): a 30 fps WebM played and exported with every third frame
missing and the frame before it shown twice (20 unique frames a second).
The same happens at 29.97, 60, 59.94, 24 and 23.976 fps, and with MP4
files whose video track has a 1 ms timescale. 25 and 50 fps were fine.

Cause: Matroska stores block timestamps in TimestampScale units (usually
1 ms), rounded to the nearest unit, so at 30 fps frame 2 (66.67 ms) is
stored as 67. MkvSource::video_frame converted the requested time to track
units with a floor (66), and the lookup (last sample with pts <= target)
returned frame 1. Every frame whose timestamp was rounded up was skipped.
Mp4Source::video_at, and the web build's WebCodecs MP4 path, floored the
same way against the track timescale; normal MP4 timescales hold frame
times exactly, so only coarse (1000) timescales were hit.

Fix: new Tick::to_rational_round (nearest unit, halves up, total for zero
and negative timebases), used for the video lookup target and the
catch-up threshold in mkv.rs, mp4.rs and webcodecs.rs. A requested time
now matches a frame whose stored timestamp is within half a unit of it,
the same precision the timestamps have. Truncating muxers (stamps rounded
down) still work. Times on exact timebases (90 kHz, 15360, 30000/1001…)
convert exactly as before.

Test: crates/codecs/src/rounded_pts_tests.rs builds synthetic Motion-JPEG
streams in the test (each picture shows its index as black/white blocks),
muxed as WebM with 1 ms timestamps and as MOV with a 1000 timescale, at
30, 29.97, 60, 59.94, 24, 23.976 and 25 fps with nearest and truncated
stamps. Requesting every frame's start over 3 s must show every frame
exactly once, and every frame's midpoint must show that frame. Before the
fix both tests failed ("30 fps, Nearest ms stamps: 30 of 90 frames never
shown [2, 5, 8, 11]…, 30 shown twice [1, 4, 7, 10]…"). The time crate
tests cover the rounding, ties and hostile timebases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:16:37 -04:00
Brandon Thomas 5c8471c9f4
Merge pull request #41 from justjohn12345/pr/decode-memory
MEM1–MEM4 + HW1: clip memory on a timeline from 12 GB to 1.9 GB; hardware decode actually on
2026-10-06 11:38:03 -04:00
Brandon Thomas 37361900a9
Merge pull request #38 from midasdf/feat/japanese-interface-language
i18n: Japanese interface language (uses an installed system font)
2026-10-06 11:37:57 -04:00
Brandon Thomas 47c6b03681 filmcraft: --help, --version and argument errors show a message box on Windows
Windows release builds have no console (windows_subsystem = "windows", added on main after this branch), so --help printed nothing and an unknown option or a bad FILMCRAFT_CONTROL_PORT quit with exit code 2 and no visible message. The text is still printed, and on Windows release builds also shown in a message box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:05:59 -04:00
Brandon Thomas 39d81aee14 Merge remote-tracking branch 'origin/main' into pr-47-fix 2026-10-06 08:46:53 -04:00
midasdf bab130c358 i18n: Japanese interface language using an installed system font
Edit > Language switches English/Japanese and persists in UI state
(`app.language.english` / `app.language.japanese`, reachable through the
control channel). Core native and in-window menu labels are translated;
untranslated labels stay English. The in-window header fits the document
title beside the localized menus.

No font is bundled. Japanese text uses a Japanese font already installed on
the system (Hiragino, Yu Gothic, Meiryo, Noto Sans CJK JP, Source Han Sans,
IPA, … or any installed face covering the menus' characters), added to every
theme font family as the last fallback. Without one, switching to Japanese is
refused with a message and a saved Japanese setting falls back to English
(the web build cannot read system fonts). Titles already fall back to
installed fonts through the text engine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 08:41:17 -04:00
Brandon Thomas 7fee797ee7 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 FilmCraft 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:51:02 -04:00
punkhop 22229df105 filmcraft: --help prints usage and an unknown option is an error
Problem: `filmcraft --help` opened the app. Every argument the parser
did not know was taken as a file to open, so `--help`, `-h` or a
mistyped flag started a window (and tried to import "--help" as media).
`--control` with a missing or invalid port, and an invalid
`FILMCRAFT_CONTROL_PORT`, started the app without the control server and
said nothing, which leaves a script waiting for a server that never
comes.

Solution: argument parsing moves into its own module (`args.rs`,
`args::parse`), which runs before anything else starts. `--help` / `-h`
print the usage (the options the app parses: --control, --demo, --empty,
--recover, --no-recover, --data-dir, --version) and exit 0. An unknown
option, or `--control` / `--data-dir` without a usable value, prints the
error and the usage on stderr and exits 2. The whole line is checked, so
`--version --bogus` is an error too. A `FILMCRAFT_CONTROL_PORT` that is
not a port is the same error as a bad `--control` (exit 2), for the same
reason; an empty value counts as unset, and the value is not looked at
when `--control` is given or for `--help` / `--version`. `--` ends the
options, so a file whose name starts with a dash can still be opened; a
lone `-` and the `-psn_...` argument macOS adds to app launches are not
treated as options.

Tests (in args.rs): `help_and_version_do_not_start_the_app`,
`unknown_options_are_errors`,
`a_bad_port_in_the_environment_is_an_error_like_a_bad_control_flag`,
`known_options_and_files_parse_as_before`. docs/contributing.md
mentions `--help` and the errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:21:56 -07:00
justjohn12345 b999b69f07 HW1: register the hardware decoders in every desktop run
The desktop app called filmcraft_platform::register() as an argument of
log::info!. A log macro does not evaluate its arguments while no logger takes
its level, and the app installs none, so VideoToolbox was never registered:
perf.stats showed hardware decoding enabled with 0 sessions, 0 declined and
every frame decoded in software. The CLI and the bench register directly and
were not affected.

Registration is now a statement of its own, with a start-up test that runs
without a logger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:42:28 -04:00
Brandon Thomas c3ec0e85d3 HW1: platform crate + VideoToolbox H.264/HEVC hardware decode (#30)
- New crates/platform (filmcraft-platform, L5): OS media FFI only. The one
  crate allowed `unsafe` (own [lints] with unsafe_code = "deny",
  #[allow(unsafe_code)] only on the videotoolbox module, SAFETY comment on
  every block, safe Result-returning public API). AGENTS.md §0.3 names the
  exception; docs/adr/0001-platform-ffi.md records why and the rules.
- VideoToolbox decoder for avcC / hvcC, 8/10-bit 4:2:0 and 4:2:2: session from
  the sample entry's parameter sets with hardware required, asynchronous
  decode (2 in flight), biplanar CVPixelBuffer copied to planar Yuv8/Yuv16,
  reorder buffer of the stream's own depth, RASL skipped after a starting CRA.
  Output callback under catch_unwind.
- HybridDecoder: transparent mid-stream fallback to the software decoder
  (replays samples since the last restart point, drops already-returned
  pictures). New codecs::software_video_decoder (built-in factories only) and
  codecs::hw (switch, counters, NalStreamInfo shared with software decoders;
  vui_color / sar_par helpers now used by both).
- Settings ▸ Playback ▸ Hardware decoding: Auto / Off (engine applies it to
  the codecs switch); desktop app, CLI/MCP and bench call register().
- perf.stats decode.framesDecoded and decode.hardware counters.
- Tests: bit-exact parity with the software decoders (H.264 High, HEVC Main
  open GOP, Main 10; resets, reseeks, flushes), forced-failure fallback,
  mutation fuzz of samples and parameter sets, cross-platform fallback with a
  stand-in decoder, setting Off, HEVC 4:2:2 vs ffmpeg.
- Bench --hw auto|off; results in docs/performance.md (4K CPU/frame
  ~86-119 ms -> ~4 ms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 04:53:28 -04:00
Brandon Thomas 694e40546c
Merge pull request #27 from storytold/pr/never-crash-clean-crates
Never crash: deny the panicking lints in the already-clean crates and apps
2026-10-04 16:19:27 -04:00
Brandon Thomas b16e0889f3 Never crash: deny the panicking lints in the already-clean crates and apps
aac, bitstream, cfb, color, format, frame, geom, isobmff, media, scopes, speech, the desktop
app and the web app have no production unwrap/expect/panic/unreachable (the web app's two
`expect`s — frame-cache eviction and chunked file reads — become `let … else`); each now
carries `#![deny(clippy::unwrap_used, …)]` outside tests so it stays that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:08:23 -04:00
Brandon Thomas 5628fc55bc render, gpu, cli: never crash — no expect/unreachable, deny the panicking lints
- gpu: `composite` returns its output view by value (a cheap handle clone) taken from the
  render-target setup, so the accumulation/output views no longer `expect` their slots.
- render: lightning bolt subdivision, tracker pyramid and the Lumetri preset instance without
  `expect`.
- cli: dotted parameter insertion without `expect`; the render/mcp backend arms report a usage
  error instead of `unreachable!`.
- Each crate denies unwrap/expect/panic/unimplemented/todo/unreachable outside tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:04:42 -04:00
storybored379 27a1f78df7 Media: apply the container's display rotation (portrait phone video)
Phones record portrait video as landscape pictures plus a rotation in the
container: the MP4/MOV tkhd matrix (ISO/IEC 14496-12 §8.3.2) or the
Matroska Projection pose roll (RFC 9559 §5.1.4.1.28.46). The matrix was
parsed but never used, so every portrait iPhone clip imported sideways
at its landscape size.

- isobmff: Track::display_rotation() reads 0/90/180/270° from the matrix
  signs (mirrored / sheared matrices are left alone).
- matroska: parse Projection (type, yaw, pitch, roll);
  VideoInfo::display_rotation() for rectangular projections.
- frame: VideoFrame::rotated() turns every plane at its own resolution
  (4:2:2 chroma is widened to 4:4:4 for quarter turns) and swaps the PAR.
- codecs: Mp4Source / MkvSource report the displayed size and PAR, and
  GopCache rotates decoded frames before caching them.
- web: the WebCodecs source configures the decoder with the coded size
  and rotates its output the same way.

Tests: a one-frame ProRes MOV built in the test with 0/90/180/270°
matrices (reported size + which half ends up on top), plane rotation for
RGBA / 4:2:0 / 4:2:2, and a synthetic Matroska file with a -90° roll.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-04 02:50:16 -04:00
Brandon Thomas fafd82b6ec Crash and blank-screen fixes (desktop + web)
Desktop/shared:
- Frame workers catch panics per job: a failing decode/render no longer kills the worker
  or leaves its frame in flight forever (blank monitors). Counted as perf.stats failedJobs.
- UI pass catches panics and shows a "FilmCraft hit an error" window (Save Project /
  Continue) instead of closing the app.
- Panic hook writes <data dir>/Logs/crash-<day>.log with thread, location and backtrace;
  a window that can't start shows an error dialog instead of exiting silently.
- GPU compositor only on adapters that render/blend Rgba16Float with >= 4096 textures;
  GPU validation errors and oversize frames switch to the CPU compositor instead of
  wgpu's default panic.
- Dock layout and Media Browser splitter no longer panic on tiny panels/windows.

Web:
- Export mode / previews / voice-over / log reveal no longer call std::env::temp_dir
  (panics on wasm32): new filmcraft_engine::temp_dir(); default export dir /exports.
- Fatal-error overlay with Reload; WebGPU device failure retries on WebGL2 (?webgl);
  cache-busted wasm/glue URLs; webcodecs entries[0] guard.

Tests: robustness_ui (worker survives injected panics, UI panic recovery, tiny windows),
crash hook, dock split, GPU plan size, default export dir; web smoke test extended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:26:19 -04:00
Brandon Thomas 81873deedb Merge branch 'main' into worktree-agent-a861ca53f77717930
# Conflicts:
#	Cargo.toml
#	docs/architecture.md
#	xtask/src/main.rs
2026-10-03 08:55:10 -04:00
Brandon Thomas 9ec0c7213b Merge branch 'worktree-agent-a1a2bf10c26331f84' into worktree-agent-a861ca53f77717930
# Conflicts:
#	docs/architecture.md
2026-10-03 07:11:48 -04:00
Brandon Thomas 41942e17d8 Merge branch 'main' into worktree-agent-a3c3d94e29f8131bb 2026-10-03 07:11:09 -04:00
Brandon Thomas 09947712d0 M6.6: MXF OP1a / OP-Atom writer and MXF export formats
filmcraft-mxf gains a streaming writer (ST 377-1 partitions, primer, header
metadata, VBR index segments with temporal offsets, RIP; ST 378 OP1a
frame wrapping, ST 390 OP-Atom clip wrapping) for VC-3, ProRes, AVC byte
stream and PCM with start timecode and caller-supplied package UMIDs, plus
write_opatom_pcm. filmcraft-export adds mxf-op1a / mxf-opatom formats
(DNxHR, ProRes or H.264 + PCM; OP-Atom writes one mono file per channel),
presets, the engine mxfVideoCodec parameter and CLI .mxf inference.
Tests read our files back and check them against ffprobe / ffmpeg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 04:45:27 -04:00
Brandon Thomas 89c8565106 M9.15: filmcraft-cli probe reports MPEG TS/PS programs, streams and access units
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:57:23 -04:00
Brandon Thomas c1c846aaad M12.7: Project panel and Media Browser parity
List / Icon / Freeform views, Metadata Display, view presets, font size,
Preview Area, bin tabs and windows, hover-scrub In/Out; Media Browser tree,
Favorites, history, file types, thumbnails, Edit Columns, import and drag.
Engine: project_panel and media_browser modules, Services::list_entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:14:31 -04:00
Brandon Thomas 1fa560c1c7 M7.8: audio parity — 5.1 multichannel, voice-over record, Remix, Clip Mixer automation
5.1 / multichannel:
- audio-dsp::channels: layouts (L R C LFE Ls Rs), ITU-R BS.775 up/downmix, 5.1 Mixdown Types,
  equal-power 5.1 panner (puck, Center %, LFE).
- Mixer graph buses are 2 or 6 channels wide; 5.1 tracks/submixes/Mix; strips feeding a 5.1 bus
  use the 5.1 panner (lanes pan51.x/y/center/lfe stored in MixerStrip::lanes, no schema change);
  5.1 strips fold into stereo buses with BS.775; per-channel meters; clip effects on 6 channels.
- file.newSequence {mix, trackType}, sequence.settings {mix}; playback honours the 5.1 Mixdown
  Type preference on stereo devices and plays 6 channels on 5.1 devices.
- Export Audio Channels 5.1: WAV WAVE_FORMAT_EXTENSIBLE (mask 0x3F), QuickTime PCM with a chan
  atom, AAC channel configuration 6 (reordered to C L R Ls Rs LFE).
- Track Mixer: 5.1 panner puck with Center/LFE, N-channel meters, Show/Hide Tracks, Meter
  Input(s) Only; transport record button runs voice-over.

Voice-over: engine AudioInput trait + SyntheticInput, cpal input in the app, audio.voiceover.*
commands (punch-in, pre/post-roll, countdown cues, WAV next to project / scratch disk, one undo
step), track header mic button and Voice-Over Record Settings dialog.

Remix: beat tracking + chroma/cepstra self-similarity planner in audio-dsp, hidden `remix` clip
effect holding the plan, render::remix playback with equal-power crossfades, clip.remix.*
commands, Remix tool and Remix Properties dialog.

Clip Mixer automation: per-track Latch/Touch/Write (clipMixer.setMode/touch/release) heard live
and written as thinned clip Volume/Panner keyframes at the end of the pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:40:35 -04:00
Brandon Thomas 84f7df6479 Merge branch 'main' into worktree-agent-a7998c724fdfa5d6b 2026-10-02 20:09:15 -04:00
Brandon Thomas c59d21181f M6.5: export parity — presets, Export mode settings, queue, Quick Export, image sequences
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:27:19 -04:00
Brandon Thomas efa8167962 M9.14: MXF (OP1a/OP-Atom) and Ogg demuxers, image sequences, BWF timecode
- crates/mxf (L0): KLV walk, partitions, primer, header metadata, index tables, material ->
  file package resolution, AVC/VC-3/ProRes/MPEG-2 identification, PCM/AES3 (ST 331) sound,
  timecode; OP1a and OP-Atom (clip wrapping).
- crates/ogg (L0): RFC 3533 pages/CRC/packets, RFC 7845 Opus timing (granules, pre-skip, end trim).
- codecs: MxfSource (GOP cache, POC ordering for AVC without temporal offsets, MPEG-2 reported
  unsupported), OggSource (Opus with pre-roll seeking, Vorbis), Annex B H.264 decoder.
- media: image sequences (numbered stills, missing frames held, frame cache); BWF bext/iXML
  TimeReference -> start timecode.
- engine/UI: file.import {imageSequence}, auto-detect setting, file.importImageSequence,
  Media Browser "Import as Image Sequence"; CLI probe details for MXF/Ogg/BWF/sequences.
- Oracle tests vs ffmpeg for MXF, Ogg, image sequences, BWF; truncation/mutation tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:33:29 -04:00
Brandon Thomas 3b6ef97010 Release fixes: CLI --version, ALSA on Linux, web build via xtask
- filmcraft-cli: support --version/-V/version (the packaging smoke tests call it).
- Linux release job installs libasound2-dev for alsa-sys; deb/rpm depend on
  libasound2/alsa-lib; Flatpak gets --socket=pulseaudio for audio.
- packaging/web/package.sh builds with `cargo xtask web` (wasm-bindgen) and
  zips <target>/web/dist instead of assuming trunk; the release job installs
  wasm-bindgen-cli 0.2.129 to match the crate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 12:33:59 -04:00
Brandon Thomas feae349814 Merge remaining Premiere menu items (M3.11, schema v11) into integration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:47:51 -04:00
Brandon Thomas 0f8b03820a Merge branch 'worktree-agent-af22f22f99adc619b' into integrate 2026-10-02 11:11:15 -04:00
Brandon Thomas a69148d5e7 M12.5: Settings dialog with every Premiere category, wired to real behaviour
One Preferences window (app menu ▸ Settings ▸ <category>, Edit ▸ Preferences in-window, General =
Cmd+,): category list, schema-driven pages, Help / Reset… / Cancel / OK. Settings live in the
per-user preferences.json (version 2, v1 migrated, bad values repaired), reachable via
prefs.get/set/reset{category} and the new prefs.schema; app.settings.<category> opens a page;
every control has a settings.<key> automation id.

Wired: still/transition default durations, auto-scroll, snap playhead, return to beginning, play
after rendering, step many, selection-tool roll/ripple, theme/highlight/contrast, tooltips, at
startup + recent projects, label names/colours/defaults, indeterminate timebase, default media
scaling, media cache location/policy/clean, frame cache budget, cpal device/buffer/rate/output
mapping, transcription defaults + auto-transcribe on import, text smart quotes/ligatures/font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:10:46 -04:00
Brandon Thomas a34bc7f038 M3.11: remaining Premiere menu items — Scene Edit Detection, Normalize Mix Track, Simplify Sequence, Find / search bins, Automate to Sequence, Project Settings, ALE export…
- Scene Edit Detection: pure-Rust cut detection (render::scene: luma grid + RGB
  histogram difference, adaptive threshold with sensitivity, min shot length),
  background job with progress/cancel; applies cuts (linked audio too), clip
  markers and subclips in one undo step.
- Sequence: Normalize Mix Track…, Simplify Sequence…, Transcribe Sequence…,
  Captions ▸ Show Active Caption Tracks Only, Apply Default Transitions to
  Selection works on selected clips; Sequence menu in Premiere's order.
- Markers: Add Flash Cue Marker… (MarkerKind::FlashCue).
- File: New ▸ Search Bin (live saved queries), Close, Close All (Other)
  Projects, Save as Template… (+ new project from template), Import from Media
  Browser, Get Media File Properties for ▸ File…/Selection…, Project Settings ▸
  General…/Scratch Disks… (scratch disks drive previews, proxies, auto-save),
  Export ▸ Selection as FilmCraft Project…, Export ▸ Avid Log Exchange…
- Edit: Find… / Find Next (project columns/operators/all-any, timeline clips
  and markers), Edit Original (OS opener host hook).
- Clip: Edit Offline…, Source Settings…, Update Metadata… (XMP sidecars),
  Generate Audio Waveform, Restore Captions from Source Clip (disabled: no
  embedded caption reader), Automate to Sequence…
- View ▸ Dynamic Audio Waveforms; Help ▸ Reveal Log Files…, System
  Compatibility Report… (with the wgpu adapter).
- Dialogs for all of the above (panels::menu_dialogs, ui.set menuDialog).
- Project schema v11 (no-op v10_to_v11, fixture, docs row).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:08:58 -04:00
Brandon Thomas 4a931a3400 app icon: owl with ear tufts (owner's ArtCraft drawing), Dock/taskbar/launcher wiring, palette docs
- assets/app-icon/: canonical SVG + light SVG, 1024 PNG, macOS runtime PNG, .icns, .ico,
  hicolor theme, LICENSE.txt and README (palette, geometry, provenance, regeneration).
- packaging/icons.sh regenerates everything with resvg, iconutil and the new `cargo xtask ico`.
- Native app sets the window icon (with_icon) and the Wayland app id; build.rs embeds the .ico
  and VERSIONINFO into filmcraft.exe on Windows (winresource, Windows-host build-dep only).
- packaging/linux/ai.storyteller.filmcraft.desktop with Icon=ai.storyteller.filmcraft.
- Web app: favicon.svg replaced by favicon.png from the same artwork; sidecars and
  ATTRIBUTION.md updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:52:46 -04:00
Brandon Thomas e222d025cf Merge transcripts (M10.5) and clip/project commands (M3.10); clip schema renumbered to v10
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:34:12 -04:00
Brandon Thomas f5ac5989f0 Merge branch 'worktree-agent-a7d751de0d72abab7' into worktree-agent-a6d2cbb6d6b3e5d7a
# Conflicts:
#	crates/edit/src/lib.rs
2026-10-01 23:31:39 -04:00
Brandon Thomas c3d2f740d0 M3.10: Edit/Clip/File menu commands — labels, Paste/Remove Attributes, subclips, frame holds, time interpolation, audio options, Replace With Clip
Edit: Label ▸ 16 colours + Select Label Group, Paste Attributes… (⌥⌘V, with
Scale Attribute Times), Remove Attributes…, Select All Matching, Remove
Unused, Consolidate Duplicates. File: New ▸ Sequence From Clip, Bin From
Selection (⇧B), Offline File…; Close Project (⇧⌘W, asks to save), Save All.
Clip: Make Subclip… (⌘U, Restrict Trims), Edit Subclip…, Modify ▸ Audio
Channels… (⇧G) / Timecode…, Video Options ▸ Frame Hold Options…, Add Frame
Hold (now splits at the playhead), Insert Frame Hold Segment, Field
Options…, Time Interpolation (Frame Sampling / Frame Blending / Optical
Flow, blending rendered on CPU; optical flow falls back to blending),
Fit to frame / Fill frame; Audio Options ▸ Breakout to Mono, Extract Audio
(WAV next to the project, imported); Replace With Clip ▸ From Source
Monitor / Match Frame / From Bin. Hold Filters: effects animate through a
hold unless set. Menus support nested submenus (egui and native) and follow
Premiere's order. Dialogs in panels::clip_dialogs with automation ids and
ui.set {clipDialog}.

Project schema v9 (no-op migration v8→v9, v8-subclip fixture): clip
time_interpolation / hold_filters / field_options / source_channels,
Interpretation.audio_channels, Subclip.restrict_trims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:28:37 -04:00
Brandon Thomas fc18a6962e M10.5: Text-based editing / transcripts
- crates/speech (L2): Transcriber trait, FixedTranscriber, Whisper model catalogue (pinned,
  SHA-256 verified) with optional downloader (feature `download`: ureq + rustls + RustCrypto),
  pure-Rust Whisper inference on candle with word timestamps (feature `whisper`), log-mel, VAD
  word tightening, MFCC speaker clustering. Both features off by default and for wasm.
- project: per-media-item transcripts (Project::transcripts); schema v9 with a no-op v8->v9
  migration and a v8 fixture.
- edit::transcript: sequence transcript derived from clip transcripts, search, paragraphs,
  word ranges, pause/filler detection, ripple delete of many ranges, caption layout.
- engine: transcript.* commands (generate, set, delete, inspect, search, select, extract, lift,
  renameSpeaker, removeFillers, removePauses, createCaptions, models, downloadModel);
  Session::transcriber for hosts/tests; features `whisper` / `speech-download` (also on the
  desktop and CLI apps). Without whisper, transcript.generate fails with a clear error.
- ui: Text panel Transcript tab (Transcribe button, speaker paragraphs of clickable words,
  Shift+click selection -> In/Out, extract/lift/remove fillers/create captions, search) with
  text.transcript.* automation ids; headless UI test.
- docs/transcripts.md, crates/speech/README.md, architecture and project-files updates.
  whisper-tiny measures 12.2% WER over 797 words on local samples.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:25:49 -04:00
Brandon Thomas 2d5267a7df M12.4: agent-friendly CLI: exec/describe/inspect/import/export, run from stdin with JSON lines and --keep-going, --save/--save-as, --bridge to the live app, exit codes; tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:26:44 -04:00
Brandon Thomas ff07ed1dc8 Merge main into M13 (web app): community links and ArtCraft wordmark
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:54:09 -04:00
Brandon Thomas 5f613aff25 M13.2: FilmCraft web app (apps/filmcraft-web) with Blob media, OPFS recovery, WebAudio, WebCodecs
- eframe web runner on WebGPU (WebGL2 fallback; GPU compositor on WebGPU, CPU on WebGL2).
- fs: virtual file table of File/Blob handles, 1 MiB chunked async range reads with an
  LRU cache and read-ahead (pending + retry instead of blocking), downloads for written
  files, /opfs/ paths written to OPFS.
- import: File System Access picker / <input type=file>, drag-and-drop anywhere,
  container index prefetch (moov wherever it is), retried imports; project open/save.
- recovery: OPFS auto-save snapshot while dirty, media copies, reopened on next visit.
- audio: AudioWorklet output fed ahead from the UI thread; played-frame audio clock.
- webcodecs: H.264/HEVC/VP9/AV1 MP4/MOV decoded by the browser VideoDecoder via a
  reader opener (fallback to our decoders on any error), probed with isConfigSupported.
- api: window.filmcraft (execute/request/commands/screenshot/importFiles/importUrl/
  openProject/files/readFile/info).
- cargo xtask web [--dev] [--serve PORT] (wasm-bindgen CLI); xtask wasm also checks
  filmcraft-ui-egui and filmcraft-web; layer L6 for the web app.
- Original web icon (favicon.svg) with attribution sidecar; docs/web.md; headless-Chrome
  smoke test (tests/smoke.mjs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:52:35 -04:00
Brandon Thomas 9f687f7b44 Community links: header Discord button, Help menu (Discord, ArtCraft website, FilmCraft app page, GitHub, Report an Issue), Discord in the macOS app menu, About dialog with link buttons (centred, Escape closes), Community row on the Home screen, README links; help.* commands for agents; headless UI test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:25:46 -04:00
Brandon Thomas 7095a986ff fix: control channel never steals keyboard focus — UI requests and screenshots bring the window forward without activating the app (orderFrontRegardless); --control launches without activation; only ui.focus activates
Agents' ui.* requests used ViewportCommand::Focus, so the user's typing in another app landed in FilmCraft as shortcuts (stray Extract, Mark In/Out, markers…). Verified live: the frontmost app stays frontmost through launch, ui.click, ui.key and ui.screenshot, and the requests still take effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:53:19 -04:00
Brandon Thomas 9f4208bb08 Merge main into M11.7–9 (relink, proxies, project manager): GopCache keeps main's continuation algorithm with a same-thread reentrancy guard (nested rayon requests decode privately instead of deadlocking); ProRes export combines profile choice with HDR signalling; project schema v6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:19:19 -04:00
Brandon Thomas b98c886133 M11.7: offline media and relinking
- Missing media no longer fails: opening a project scans for missing files
  (`media.findMissing`, `file.open` → missingMedia). Missing clips render our own
  offline slate (render::offline: red striped field, warning triangle, "MEDIA NOT
  FOUND", file name, hint) with silent audio, and the Link Media dialog opens.
- Media identity: imports record the size and a fast content fingerprint (hash of
  size + first/last MiB) in MediaClip::identity (optional field, older builds
  ignore it, no schema bump).
- media.relink checks file name / extension / fingerprint ("Clip ID") / duration /
  media start / frame size+rate+channels, refuses a mismatched fingerprint unless
  forced, supports Align Timecode (Project::shift_media_time), and relinks the
  others automatically by the derived folder remap (Windows/macOS separators).
- media.autoRelink {from,to} | {folder}, media.search, media.replaceFootage,
  media.makeOffline {deleteFiles?}, media.offlineAll, media.status, media.linkMedia.
- Media pool caches sources per reference (path, offline flag), so relink, Make
  Offline and undo take effect at once; proxy-aware resolution and a full-res
  provider that export uses.
- codecs::gop no longer holds its lock while decoding: rayon decoders inside a
  parallel export could steal another frame of the same source and deadlock.
- UI: Link Media dialog (rows, match options, folder search with preview, Locate…,
  Link, Offline, Offline All, Cancel), Make Offline dialog, Project panel offline
  markers and context menu, media thumbnails keyed by media reference.
- Tests: moved media opens offline (slate rendered) and relinks others by folder,
  prefix remap and folder search, fingerprint mismatch refused, Make Offline,
  headless UI test of the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:00:35 -04:00
Brandon Thomas 4b83e088eb Merge main into the playback branch (mixer recordStart moves to the end of preroll; GopCache keeps main's random-access key walk-back)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:30:04 -04:00
Brandon Thomas 985a848c5e M3.11: keyboard shortcuts editor + presets
- Engine shortcut set (crates/engine/src/shortcuts.rs): bindings as data
  (command, canonical chord, optional panel), panel shortcuts override app ones
  while the panel has focus; per-OS modifiers (Cmd = Cmd/Ctrl, Ctrl = macOS
  Control, folded into Ctrl elsewhere and reported as conflicts); conflict
  detection, reassignment, undo/redo, Cancel restores; frontend commands
  registered so tools/transport/panels are bindable too.
- Presets: FilmCraft Default, Premiere Pro / Final Cut Pro / Avid Media
  Composer Compatible (key tables mapped onto FilmCraft command ids); custom
  presets as JSON in <data dir>/Keyboard Shortcuts/, active set persisted,
  Save As / Delete / Export / Import (Windows-notation files converted).
- shortcuts.* commands for agents/MCP (list/get/set/clear/undo/redo/conflicts/
  forKey/resolve/presets/loadPreset/savePreset/deletePreset/export/import/audit).
- Premiere-default audit: commands without a shortcut get Premiere's key when
  free (Shift+D Apply Default Transitions, Shift+J/L slow shuttle, Shift+K Play
  Around, Project > Shift+O Open in Source Monitor); Audio Clip/Track Mixer
  window shortcuts corrected (Shift+9 / Shift+6).
- Edit > Keyboard Shortcuts... (Cmd+Alt+K): keyboard drawn in code with
  app/panel/both colouring and modifier filter, searchable command list with a
  record-on-click Shortcut column and +, Key: detail list, conflict warnings,
  Undo/Redo/Clear/Cancel/OK; automation ids shortcuts.*.
- Menus (in-app and native macOS key equivalents), command.list and the input
  loop follow the active bindings live.
- Tests: 7 engine tests; scripted kittest test (record keys, live menu update,
  reassignment, undo/redo, cancel, OK, panel-specific Left in History).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:56:47 -04:00
Brandon Thomas 5110b694d8 M4.5: fix UI hang after preview render (macOS App Nap starved the hidden app; ui.screenshot waits forever)
Root cause: not a lock. When the window is hidden or behind others (always when the app is
driven over the control channel), macOS App Nap drops every thread of the process to background
priority 4 and defers its timers. On a loaded machine (load avg ~150) a priority-4 process gets no
CPU: after Render In to Out + play the UI thread stayed runnable inside the run loop's timer
callout, every thread at PRI 4 (`ps -M`), 0 % CPU, control channel silent. Relaunched with App Nap
off the same script ran through: render 2–13 s instead of 15 s, every reply immediate (2/2 runs).

- apps/filmcraft/src/app_nap.rs: hold a user-initiated, latency-critical NSProcessInfo activity
  for the life of the process (= NSAppSleepDisabled for a bundle; idle system sleep allowed).
- ui.screenshot: a hidden window or sleeping display never presents, so the screenshot event
  never came and the UI repainted at full speed forever (100 % CPU). It now fails after 10 s with
  "no frame was presented (window hidden or display asleep)" and polls at 60 Hz meanwhile.

Regression test: app_nap::tests (the activity is taken on macOS). The starvation itself needs a
hidden window on a loaded machine and is checked with the control-channel script in the commit
notes (captions.newTrack/add, markIn/Out, Full, renderInToOut wait, stop, playhead.set,
renderBar, ui.screenshot): all replies within 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:17:13 -04:00
Brandon Thomas 34f53fe9cf Merge main into M11.1–2 (autosave/recovery): previews follow save/open/recover; bare pre-envelope projects with version 1 or 2 load as schema v1 (regression test)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:23:01 -04:00
Brandon Thomas 516978b4d4 M11.2: auto-save ring + crash-recovery journal
- Engine autosave module: Preferences (autoSave.enabled/intervalMinutes=5/maxVersions=20/
  saveCurrentProject/recoveryJournal/recoveryIntervalSeconds), persisted in the per-user data
  dir; prefs.get/set/reset commands.
- Background worker (filmcraft-autosave thread): the UI thread only hands over the Arc<Project>
  snapshot; JSON encoding and atomic writes happen on the worker. Premiere-style auto-saves to
  <project dir>/Auto-Save/<name>-YYYY-MM-DD_HH-MM-SS.fcproj (local time), only when changed,
  rotated to Maximum Project Versions, optionally also saving the project.
- Recovery journal: debounced snapshot of unsaved changes in <data>/Recovery/<session>/ guarded
  by an OS file lock; on launch, sessions whose lock is free and that left a snapshot are offered.
  Clean quit removes the journal (or keeps it, marked cleanExit, if changes were unsaved).
- Commands: file.recover, file.discardRecovery, file.recoveryList, file.autoSaveNow,
  file.autoSaveStatus, file.listAutoSaves.
- UI: Preferences ▸ Auto Save page (Edit ▸ Preferences, Cmd+,; FilmCraft ▸ Settings… on macOS),
  "Recover Unsaved Changes" dialog at startup, Revert confirmation; all with automation ids.
- Desktop: --recover / --no-recover / --data-dir; local-time offset via chrono (clock).
- Verified in the app: edits, kill -9, relaunch, dialog, Recover restores the edits (unsaved, original path).
- docs/project-files.md: auto-save, recovery and measured costs (2,000 clips: 2.5 ms encode,
  1.4 MB, ~30 ms atomic write+fsync, all off the UI thread). ROADMAP M11 updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:10:23 -04:00
Brandon Thomas 098dcc8a61 M10.4: caption UI — caption track rows above the video tracks (select, drag to move/trim, eye/lock headers), Text panel Captions tab (segment list with editable in/out/text, add/split/merge/delete/export, track picker, style strip), Burn Captions Into Video in Export mode, caption file dialogs; docs/captions.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:06:29 -04:00
Brandon Thomas efc617cb97 M6.2: own AAC-LC decoder replaces the symphonia bootstrap for AAC; AAC encoder for MP4 export
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:38:47 -04:00
Brandon Thomas 627931fc72 UI fidelity pass from the Premiere 26 black-box reference: measured palette and label colours, square panels with 4 pt gutters, tab strips with underline + menu glyph, header layout, native macOS menu bar (muda), status/hint bar, Properties panel, timeline restyle (clip bodies, name band, fx badge, head thumbnails, rectified waveforms, hatched transitions, track header layout with patch/target buttons, markers row, 30 pt toolbar, zoom bar knobs), monitor controls, meters, tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:37:38 -04:00
Brandon Thomas 3696e4ee80 cli: bench-decode 2026-09-30 07:22:16 -04:00
Brandon Thomas b7b7042b87 M5.8: wgpu compositor — frame plans (render crate), YUV/RGB layer sampling with footprint supersampling in WGSL, linear-light premultiplied compositing, upload cache; Program monitor composites on the GPU (FILMCRAFT_CPU_COMPOSITE=1 to disable)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:16:32 -04:00
Brandon Thomas 3eac0a2ee7 M14: MCP server (headless + bridge to live app), filmcraft-cli (probe/commands/render/run/mcp), .mcp.json, control protocol docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:50:31 -04:00
Brandon Thomas 235c8a9bbd M0.10/M0.11: egui shell — docking workspaces, header/menus, Project, Source/Program monitors, Timeline with all edit tools, Tools, Effects, Effect Controls, Lumetri, meters, mixer, control channel, desktop app with cpal audio
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:29:18 -04:00