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>
Problem: `--gpu-rendering` was missing from the CLI's list of
value-taking options, so `export --gpu-rendering off out.wav` stored the
option without a value and turned `off` into the output path (or dropped
the setting silently when the option came after the filename).
Fix: list `--gpu-rendering` among the valued options, as documented in
the CLI help.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: every link (Help menu, About dialog, header Discord button, Import
screen, Settings and Keyboard help) went through egui's `ctx.open_url`. The
workspace builds eframe without its `links` feature, so egui-winit only logs
"Cannot open url - feature links not enabled" and nothing opens on Linux,
Windows or macOS.
Fix: add a `HostHooks::open_url` hook, as PhotoCraft does. `links::open` now
takes the app and calls the hook, falling back to `ctx.open_url` when it is
unset or fails (the web build keeps opening a new tab). The desktop app sets
it to `open::that_detached` (open 5, MIT), which does not block the UI
thread. Test: every Help link reaches the hook, and a failing hook falls
back to `ctx.open_url`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Language::De is persisted as `de` and translated through a new de.tsv
catalog that covers every menu label and the native macOS Settings menu,
written from the plain meaning of the English labels with informal "du"
and infinitive commands. The new app.language.german command checks,
switches and restores the language like the others, the native macOS
menu maps it back, Settings > General offers Deutsch, and System Language
picks German for any de-* locale (de-DE, de-AT, de-CH ...).
A new test, built like the Ukrainian one, fails when German misses a core
menu label (the Brazilian Portuguese entries, the top-level menus, the
macOS Settings menu) or keeps an entry that is no longer a menu label;
menu labels added later use English until they are translated. The
System Language test no longer uses `de` as an unsupported example.
Closes#490
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ctrl+V with a screenshot or an image copied in another app, or with files
copied in Explorer / Finder, now pastes them. In the Timeline they are
imported and placed at the playhead, end to end, without overwriting
anything: each clip goes on the first free track from the targeted one
outward (up for video, down for audio), and a track is added when every
track is busy there. Ctrl+Shift+V inserts them on the targeted tracks, as
Paste Insert does. In the Project panel Ctrl+V imports into the shown bin.
One undo step takes the paste back.
Copying clips already puts their names on the system clipboard as text, so
media on the clipboard was copied after them; without media, Paste pastes
the copied clips as before.
- engine: edit.pasteMedia {paths, insert, place, bin}; paste_media::
save_pasted_image writes "Pasted Image <n>.png" where voice-over takes and
narrations go (voiceover::media_dir: Scratch Disks > Captured Audio and
Video, else next to the project, else the data directory), trying a
bounded number of names as voiceover::unique_wav_path does.
timeline.place's default length moves to commands::full_duration so both
share it.
- ui-egui: HostHooks::clipboard_media reads the clipboard (ui-egui stays
OS-independent); menus::invoke turns edit.paste / edit.pasteInsert into a
media paste when the Timeline or Project panel has focus. egui-winit drops
the Ctrl+V press when the clipboard holds no text but passes the release,
so a V release without its press puts the press back. That also makes
Ctrl+V paste copied clips when the system clipboard is empty.
- filmcraft (desktop): the hook, with arboard (already in the tree through
egui): copied files first, else an image.
Not covered: the web build, whose browser clipboard works differently.
Tests: paste_media_tests (5: image above the footage with nothing
overwritten and one undo step, tracks added when every track is busy,
Paste Insert, import only, saved image names) and clipboard_paste_ui (4:
an image pasted from a key release with no text, copied files and Paste
Insert, the Project panel imports, copied clips still paste and a plain V
pastes nothing).