A PC whose GPUs were installed from different driver packages of one vendor
(an ASUS G513QY: the integrated Radeon on the 2021 package, the RX 6800M on a
2026 one) gives the Vulkan loader two versions of that vendor's driver, and
the RX 6800M is listed once through each. wgpu's request_adapter takes the
first discrete entry, the 2021 driver's, and the window drawn through it dies
inside amdvlk64.dll (0xc0000005) before it paints: the main thread is in the
2021 driver, the fault on a thread of the 2026 one, no Rust frame anywhere.
Left to the #820 ladder, two crashed launches end in DirectX 12 only.
filmcraft_gpu::adapter::choose is wgpu's own rule (the adapters that can draw
to the surface, by device type for WGPU_POWER_PREF, then as enumerated) with
one addition: when the adapter that rule picks is listed again by the same
driver (same backend, device type, PCI vendor and device and driver name; the
same bus id when both report one), the entry exposing the most wgpu features
is used, i.e. the newer version (68 against 60 here, a strict superset).
Without such a duplicate the choice is wgpu's own, and entries of one GPU from
different drivers (RADV and AMDVLK, a vendor's driver and Dozen) are left
alone.
graphics::apply installs it as egui-wgpu's native_adapter_selector in the
default mode on Windows, as #609 was asked to be rebased onto the #827
start-up. DirectX 12 only, software mode and the other platforms keep their
adapter choice, and the ladder is untouched. The adapters and the choice go
to the log.
Tests: the laptop's listing (wgpu's rule picks the entry that crashed, choose
the other one), listings without two versions of one driver over every power
preference (choose equals wgpu's rule), surface, bus id and driver cases, and
one against the adapters of the machine running the tests (the rule is what
request_adapter returns there).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds Korean as an interface language: Edit ▸ Language ▸ 한국어, Settings ▸
General ▸ Interface Language, and System Language for ko / ko-KR locales.
- crates/ui-egui/src/i18n/ko.tsv: 3,573 entries, the Spanish catalog's sources
plus the macOS Settings item, written clean-room from the plain meaning of
the English text (sidecar ko.tsv.attribution, ATTRIBUTION.md row).
- Hangul is drawn with the installed system face cjk.rs already adds (Malgun
Gothic, Apple SD Gothic Neo, Noto Sans CJK KR…); switching is refused with a
message when there is none, like Chinese.
- Test: korean_covers_the_menus_and_has_no_dead_entries.
- Docs: localization-parity, ROADMAP, ui-egui README.
Native-speaker review welcome.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013XWUReif4gqcjU5GsjYioc
wgpu validates indirect draw and dispatch arguments with a compute shader it
compiles when the device is created. Metal on an Intel Iris Pro (MacBookPro11,3,
macOS 12.7.6) fails to compile it ("Compiler encountered an internal error" in
MTLCompilerService), the device is lost, and the window never opens.
FilmCraft draws and dispatches nothing indirectly, so leave the check out of the
instance flags. WGPU_VALIDATION_INDIRECT_CALL=1 turns it back on. VectorCraft
does the same (storytold/vectorcraft#651).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#260 moved Linux file dialogs to a worker thread (run_dialog_off_thread),
which built its rfd filters from the plain extension lists. The
case-insensitive patterns from file_filters::extensions (#262, #390) were
only applied in the synchronous pickers, so on Linux every dialog hid
CLIP.MP4, clip.Mp4 and EDIT.FCPROJ again: import, relink, open file,
open/save project and save as.
prepare_dialog now turns every extension list into those patterns (and
translates the filter names, as before); the project dialogs use
project_patterns(). The literal extension stays first for save suffixes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Quick Export path field was refilled from the stored path every frame,
so typing into it was overwritten. It is now a file name field that keeps
what is typed while it has focus and applies each non-empty value; a typed
or pasted full path replaces the folder too.
Under it the folder is shown as an accent-coloured, underlined link with a
folder icon. Clicking it opens the save dialog in the current folder with
the current file name; a chosen path is applied and shown, cancelling
changes nothing, and Export writes there. A preset change now swaps only
the extension, so a chosen name is kept.
Export mode's File Name and Location fields had the same refill problem
when emptied and use the same draft handling.
The desktop save dialog hook accepts a full path and starts in its folder.
About FilmCraft and Join the ArtCraft Discord… in the macOS app menu take
the translated labels of the same Help menu commands and are updated on
a language switch. Hide, Hide Others and Quit get their text from the
catalogs instead of muda's English defaults and keep their native
actions. menus::NATIVE_APP_MENU lists these native-only labels together
with the Settings submenu, so the app and the tests use the same keys.
German rows for the three new keys; "Quit FilmCraft" is already
translated in es, ja, zh-cn and fr (the app.quit shortcut), the other
languages show English until they have translations. The German menu
test accepts and requires the native app menu labels.
Closes#1145
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The macOS menu bar built every item enabled and its updater never applied
enablement, so Edit > Undo and Redo stayed selectable with empty history.
Items are now created with their computed state, and the frame loop sends
the menu tree to the native menu whenever it changes; the updater applies
only the labels, shortcuts and enablement that differ.
Fixes#902
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Exports and rendered frames now record which offline items (missing,
made offline, unreadable) they drew the placeholder slate for. The engine
reports them as `offlineMedia` in file.exportMedia (wait), jobs.list
export entries and export.queue items; the bridge and MCP long exports
pass it through. filmcraft-cli export and render name each item on
stderr and exit 1, unless --allow-offline accepts the placeholders.
Fixes#1054
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review on #827: a start marker left pending by any early exit (force-quit,
hang, unrelated crash, two launches racing) moved the user down a rung for
good, with no way back but deleting a file.
- Each start writes its own attempt file (graphics-start/<pid>-<n>.json)
that is removed after two painted frames, on a normal exit, or 15 s after
launch whatever happened. A later launch only counts attempts that are
older than that window, so a hang, a later crash or force-quit, and an
instance that is still starting are never failures.
- graphics-start.json now holds {mode, failures}: two failed starts in a row
in the same mode move on to the next one; a start that paints resets the
count. A wgpu start-up error still moves on at once.
- All files are written to a per-process temp name and renamed into place,
so concurrent launches never see or leave half a file.
- A fallback mode shows a notice (graphics.notice) with Use Default Graphics
(graphics.notice.reset) and Close; es, fr, ja and zh-cn strings.
- --graphics default|dx12|software picks a mode by hand and keeps it;
`--graphics default` undoes a fallback. Modes this platform lacks are
refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict in apps/filmcraft/src/main.rs: kept the graphics start loop and
app_creator, and carried over --control-input-only (#881) into them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
file.reveal is enabled when a selected clip has a local path, greyed out
with no selection, and the OS opener reveals the file (xdg-open of the
parent folder on Linux).
Problem: Indonesian, one of the 12 key languages in
docs/localization-parity.md, had no catalog (0%), so Indonesian users got
the interface in English and System Language never picked Indonesian.
Fix: add crates/ui-egui/src/i18n/id.tsv, clean-room translations of every
entry in the Spanish catalog plus the native macOS Settings menu (3,541),
with a glossary in its header. Language::Id ("Bahasa Indonesia") is
persisted as `id`; it appears in Edit > Language (also the native macOS
menu), Settings > General, and System Language picks it for `id-*` locales
and the legacy `in-*` code older Java/Android runtimes report. Tests cover
the core menus, reject entries without a Spanish counterpart, check glyph
coverage with the bundled fonts, switching/persistence and locale
matching. Attribution sidecar, ATTRIBUTION.md row, docs (gaps.md G14,
localization-parity, ROADMAP, ui-egui README) updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: the desktop app picked the project among its launch files with a
case-sensitive ends_with(".fcproj"), so CUT.FCPROJ opened through a Windows
file association or the Linux MIME glob was imported as media. Relative
launch paths were stored as given and went missing from another folder.
std::env::args panicked on a non-Unicode argument. filmcraft-cli import
used canonicalize, which stores \\?\ verbatim paths on Windows.
Fix: args::project_and_media finds the project by a case-insensitive
extension and makes every launch path absolute with std::path::absolute
(no verbatim prefix, symlinks kept). Both apps read args_os; the desktop
app keeps --data-dir exactly. filmcraft-cli import uses std::path::absolute.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: the cpal error callback marked the stream failed on its first
error of any kind, so the UI stopped audio and played the rest of the
playback without sound. cpal's ALSA backend reports transient errors
(POLLERR after an xrun, spurious poll returns, short writes) that way
and keeps the stream alive; after POLLERR it no longer calls back.
Reports: a second or two of audio, then silence while meters move (#23).
Fix: AudioOut::recover, called every playback frame, lets CpalOut
restart the stream: at once when the device is gone, or when an error
was reported and no samples were consumed for 300 ms. The restarted
stream reuses the shared play-ahead mixer and played-frame clock and
must keep the sample rate and channel count; at most 3 restarts in
10 s, then playback falls back to the wall clock as before. Errors
while samples keep flowing no longer silence playback. The device
callback runs the mixer under catch_unwind: a panic plays silence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: no test did a real editing job end to end. Codec and container
oracles exist, but nothing imported phone- or camera-like media, edited
it through the command layer and checked the exported file (G6).
Fix: apps/filmcraft-cli/tests/workflows.rs drives the `filmcraft-cli mcp`
binary over stdio on media generated with ffmpeg into target/fixtures:
- a VFR H.264 + AAC MP4: sequence from clip, extract, -6 dB audio gain,
title, H.264 MP4 export;
- a long-GOP H.264 MKV with AAC + AC-3 tracks: ripple trims, colour matte,
centred cross dissolve, save; a new CLI process exports ProRes.
ffprobe / ffmpeg check streams, frame count, duration, which source frame
lands where, A/V sync across the cut, title pixels, the dissolve mix and
audio levels. The tests skip without ffmpeg (testkit oracles).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: a graphics driver that crashes inside wgpu instance or device
creation (Intel Vulkan igvk64.dll #512#413#793, AMD atio6axx.dll #477)
killed every launch the same way until the user set WGPU_BACKEND by hand;
a start-up error wgpu did report ended in an error dialog.
Fix: each start leaves a marker in the data folder (graphics-start.json),
cleared once the window has painted two frames. A marker still pending at
the next launch moves on along the platform's ladder (Windows: Vulkan+DX12,
DX12 only, software/WARP; Linux: default, software/lavapipe or llvmpipe)
and keeps the mode that works. A wgpu start-up error moves on within the
same process (eframe reuses its event loop). Fallback modes don't register
the GPU export renderer, whose own instance would load the failed driver.
An explicit WGPU_BACKEND leaves the marker alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: Premiere's "AAC Audio" format has no FilmCraft equivalent. AAC
was only written inside H.264 / H.265 / AV1 movies; the only audio-only
exports were Waveform Audio and AIFF.
Fix: a new `aac` export format ("AAC Audio") that encodes the sequence
mix with the existing AAC-LC encoder into an MPEG-4 audio file (.m4a,
encoder delay in an edit list), or a raw ADTS stream when the path ends
in .aac. Bitrate, sample rate, channels and loudness normalisation follow
the audio settings. Adds an "AAC Audio 48 kHz 320 kbps" Audio Only
preset, CLI extension guessing (.m4a / .aac), es/fr/ja/zh-cn strings, and
updates G13 (also noting ProRes 4444 / XQ is already in the export UI).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: French, one of Premiere's interface languages and one of the
12 key languages in docs/gaps.md G14, had no catalog; #498 asked for it.
Fix: a new fr.tsv catalog with every entry Spanish has (menus, panels,
dialogs, Settings pages, the Effects / Effect Controls registry, the
Keyboard Shortcuts dialog, status messages) plus the native macOS
Settings item, written from the plain meaning of the English text with
ordinary French editing vocabulary (infinitive commands, "vous", French
sentence case and spacing). Language::Fr is persisted as `fr`;
app.language.french joins Edit > Language (checkmark, native macOS menu),
Settings > General offers Français, and System Language picks French for
any fr-* locale. Like Japanese, tests require only the core menus, so
later strings show in English until translated; a French entry without
a Spanish one fails. A new test checks the bundled fonts cover every
French letter (the glyph check is shared with Ukrainian). Docs: G14,
localization-parity, ROADMAP language row, ui-egui README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: `filmcraft-cli --demo --version` (or `--compact -V`, `--data-dir d
--version`) failed with "missing subcommand" and exit 2. The version check only
looked at the very first argument, so a preceding global option left
`--version` to the option parser and no subcommand behind.
Fix: parse the arguments first and treat `--version` anywhere, or `-V` in the
subcommand position, as a version query (`Args::wants_version`), still before
the hardware decoders are registered. `--help` keeps priority.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>