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 <[email protected]>
Claude-Session: https://claude.ai/code/session_013XWUReif4gqcjU5GsjYioc
German (de) landed in #630: the localization parity table and the
ROADMAP language table now list it as menus only, 371 of 3,498 strings
(10.6%), native-reviewed. The localization dimension counts 2
menus-only and 5 none, and 5 of Premiere's 10 languages well and 2
partly.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Problem: the Portuguese (Brazil) catalog, one of Premiere's interface
languages and one of the 12 key languages in docs/gaps.md G14, covered
only the menus (348 of ~3,540 strings); panels, dialogs, Settings pages,
effect names, the Keyboard Shortcuts dialog and status messages showed
in English.
Fix: pt-br.tsv now has every entry Spanish has plus the native macOS
Settings item, written from the plain meaning of the English text with
ordinary Brazilian video-editing vocabulary (infinitive commands,
polite imperative instructions, sentence case); the header records the
conventions and a term glossary. Like Japanese and French, tests
require only the menus (now every menu label, not just the core set),
so later strings show in English until translated; a Portuguese entry
without a Spanish one fails, and a new test checks the bundled fonts
cover every Portuguese letter. The core-menu set that Ukrainian,
German, Russian and French must cover moves from pt-br.tsv (no longer
menus-only) to the menus-only Ukrainian catalog, unchanged in content
for those tests. Attribution sidecar and ATTRIBUTION.md entry added.
Docs: G14, localization-parity, ROADMAP language row, ui-egui README.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, hardware, UI and localization parity docs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Settings > Media > Automatically refresh growing files and Refresh
growing files every were listed but not wired. The desktop app now
stamps each file media item's file (size + modification time) on a
worker thread every N seconds and as soon as its window comes back to
the front, and reads changed files again the way import opens them: the
item gets the new MediaInfo (length, frame size) and identity, and the
media pool swaps in a new source (the old one indexes the file as it
was). Not an undo step and a clean project stays clean (bump_view). This
also covers a render written over the file a clip uses (an EffectCraft
or After Effects round trip). A file that can't be opened yet is tried
again. media.refreshChanged runs one look (CLI, MCP).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- GpuRendering defaults to Off (opt-in per export) until measured on Windows and macOS;
docs and ROADMAP say so.
- The shared export device installs an uncaptured-error handler and a device-lost callback
that log once and retire GPU export for the session (frames go to the CPU) instead of
wgpu's default panic.
- RendererPool drops a renderer that panicked and retires the pool, so the rest of the
export renders on the CPU (regression test in gpu_hook_scenarios); the duplicate
hostile-size test that raced on the global registry is folded into it.
- Rebased onto main's render_plan/transitions: render_export_prepared reads the linear
accumulator after render_plan; transition (Composite) plans fall back to the CPU.
- es/ja rows for the new Export strings; web_time::Instant in the export pipeline.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- One code everywhere: Language::ZhCn, persisted as `zh-cn`, catalog zh-cn.tsv.
- general.interfaceLanguage accepts and lists zh-cn (Settings > General).
- macOS native menu follows app.language.chinese.
- System Language picks Simplified Chinese only for zh, zh-CN, zh-SG and zh-Hans
(not zh-TW / zh-HK / zh-MO / zh-Hant).
- Drop the second CJK font loader: cjk.rs already installs the Chinese fallback,
so switching needs only cjk::available(); without a face the switch is refused
and a saved zh-cn preference falls back to English at startup, like Japanese.
- Remove the fork's build-zh.yml workflow.
- Tests: Chinese covers every menu label and tl! literal; switching persists or is
refused without a font; locale mapping. New strings get es/ja/zh rows.
Plumbing from #389 by @demon820308.
Co-authored-by: demon820308 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Translate all 347 Spanish/Portuguese menu keys plus Clip, Audio and Settings.
Add the Ukrainian language command, serialized UI state, native macOS
menu updates, and coverage and Cyrillic glyph tests.
Co-Authored-By: Codex <[email protected]>
ja.tsv now has the same 3,466 entries as es.tsv (menus, panels, dialogs,
the Settings pages, the Effects registry, Keyboard Shortcuts, tooltips and
status messages) instead of 89 menu-only entries.
The 46 old rows that came from PhotoCraft/PDFCraft and match no FilmCraft
string are dropped. Five rows that were wrong for a video editor are
fixed: Horizontal/Vertical are 水平/垂直 (every use is geometry, not
writing direction), Orientation is 向き, Type is 種類 and Effect is
エフェクト. The other 38 rows that were already in use are unchanged.
ROADMAP.md and crates/ui-egui/README.md now list Japanese next to Spanish
as covering the whole interface.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
main gained NVENC H.265 Main / Main 10 (#328, #360), export stage timings
(#370) and VA-API decoding (#358). Resolution: main's NVENC session, FFI and
export factory, with this PR's changes ported onto them:
- ffi: the portable Guid (now also for the HEVC GUIDs), NV_ENC_DEVICE_TYPE_CUDA;
- session: device.rs (Direct3D 11 / retained CUDA primary context), the
Linux libnvidia-encode.so.1 loader, Device::KIND;
- export: factory_with and its tests, the even-size check, the saturating
max bitrate; H.265 through NVENC stays Windows-only (the factory declines
it on Linux, where nothing probed or tested it);
- Cargo.toml: main's Linux libloading dependency covers both users;
- docs: README / ROADMAP / architecture now say NVENC H.264 runs on Windows
and Linux; ADR and platform README keep both addenda / test rows;
- abi_tests: note why the MSVC-generated expectations hold on LP64 Linux.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Move Video Limiter from CPU (crates/render/src/vfx/color.rs) to the GPU
compositor (filmcraft_render::gpufx::FxOp, crates/gpu/src/fx.rs, crates/gpu/src/fx.wgsl).
Parity matches CPU reference within 9.28e-6 across all axis modes, clip levels,
compressions, and gamut warning color.
🤖 Written by agy (Antigravity Agent, Gemini 3.8 Flash)
Add Vignette effect to the GPU effect stage (render::gpufx, gpu::fx,
fx.wgsl). Evaluated parameters are shared between the CPU reference and
GPU compute passes. Replaces old CPU vignette body in vfx::color with
gpufx::FxOp::eval and gpufx::FxOp::apply.
Gates: fmt, clippy, test -p filmcraft-render, test -p filmcraft-gpu,
layers, wasm all verified.
🤖 Written by agy (Antigravity Agent, Gemini 3.8 Flash)
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 <[email protected]>
HDR sequences export as real 10-bit HEVC Main 10 through NVENC where the GPU
reports 10-bit HEVC: float BT.2020 R'G'B' -> rgbf_to_yuv420_10 -> P010 input;
VUI BT.2020 + PQ/HLG; HDR10 mastering-display / content-light as SEI on every
IDR (PQ); colr/mdcv/clli in the sample entry. New register_hdr_probe /
hdr_available in the export crate; macOS and GPUs without 10-bit keep
tone-mapping HDR sequences to 8-bit SDR HEVC. ABI asserts extended and
re-verified against nvEncodeAPI.h 12.1 (0 drift). 8-bit SDR HEVC unchanged;
the two #328 tests that asserted HDR is declined now expect Main 10.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
HEVC through VA-API the same way as H.264: the software HEVC decoder's
parsers and DPB (now generic over the picture type in filmcraft-hevc:
POC, reference picture sets, reference lists, output order, RASL
handling) drive the stateless hardware. Main, Main 10 and Main Still
Picture, 4:2:0 8/10-bit (P010 read-back); scaling lists, tiles, WPP,
dependent slices, weighted prediction. Missing references and range
extensions go to the software decoder.
Tests: hardware parity on HEVC Main / Main 10 incl. open GOP, scaling
lists, slices+WPP, weighted prediction, tskip+AMP, 1080p/2160p (streamed
comparison to stay within memory); HEVC front end against a recording
stand-in on every OS; ABI checks extended to va_dec_hevc.h. Benchmark on
Iris Xe: 4K HEVC 203 -> 10 ms CPU per frame, 4K Main 10 212 -> 18 ms.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Play source video and audio, drag marked ranges as video, audio, or a linked pair, and route Source commands to clip marks and markers. Add shared draggable In/Out handles and range movement, preserving scrubber priority and explicit-only Program marks.
Include original code-drawn controls, documentation, attribution, and regression coverage for playback, placement, routing, undo, cancellation, and hostile parameters.
Assisted-by: Codex
`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 <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
One NVENC session, ring and NV12 path now serve H.264 and HEVC (Codec enum,
Profile::HevcMain). HEVC Main 8-bit 4:2:0 SDR BT.709, MP4/MOV hvc1, parameter
sets only in an hvcC built from the SPS the encoder wrote. The H.265 format is
available through a cached NVENC probe; choosing it is the opt-in, declines are
counted errors. ABI asserts regenerated from nvEncodeAPI.h 12.1 (no drift) and
extended for HEVC; tests, docs and roadmap updated.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
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 <[email protected]>
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 <[email protected]>
Merge origin/main into the NVENC branch. #183 already provides the
HardwareEncoding enum, ExportSettings.hardware_encoding, the
hardwareEncoding export param and the Export > Video > Hardware Encoding
checkbox, so the duplicates from this branch are dropped and NVENC uses
them. filmcraft-export is now an all-platform dependency of
filmcraft-platform (VideoToolbox and NVENC both register encoders).
Never-crash fixes in the NVENC backend:
- submit() rejects a driver input pitch narrower than a row (and unlocks
the buffer); fill_nv12 uses get_mut instead of slicing rows.
- composition offsets use saturating math and i32::try_from; frame-rate,
size and timestamp casts are checked; sizes above u16::MAX decline.
- Annex B scanning and NAL type checks use get()/first().
- A failed nvEncOpenEncodeSessionEx that returns a handle destroys it.
ffi.rs carries NVIDIA's MIT notice for nvEncodeAPI.h, listed in
ATTRIBUTION.md under a new "Third-party source code" section.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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 <[email protected]>