Commit Graph
2082 Commits
Author SHA1 Message Date
CokeRoachandClaude Opus 5.5 b97bb74330 i18n: Korean (ko) interface catalog (#508)
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
2026-10-13 08:44:01 +09:00
Marco Arnulfo 95297477fd timeline: a middle-button drag pans, whatever the tool (fixes #1490)
The monitors already pan with the middle button (#824). In the Timeline a middle-button drag went
down the left button's path and selected, moved, marqueed, scrubbed or cut, depending on the tool.
It now starts the Hand tool's pan from where the button went down.
2026-10-13 01:31:43 +02:00
Marco Arnulfo c1b1e86046 fix(codecs): in-band parameter sets compare without trailing zero bytes (fixes #1483)
ffmpeg keeps a trailing zero byte after the hvcC PPS that the in-band PPS lacks, so the byte-for-byte comparison read it as a parameter-set change and sent the stream to the software decoder from its first sample. A NAL unit never ends with 0x00 (H.264 7.4.1, H.265 7.4.2): those bytes are trailing_zero_8bits, so both sides are compared without them. The platform fallback test used a trailing zero byte as its changed SPS; it now changes nal_ref_idc.
2026-10-13 01:16:52 +02:00
Marco Arnulfo bef9a6e127 fix(ui): Space and other shortcuts keep working after dragging a pane divider (fixes #1482) 2026-10-13 01:12:57 +02:00
fabian-coandClaude Opus 5.5 eb81d531eb macOS: open the window on Intel Metal by skipping indirect-call validation
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>
2026-10-12 17:45:45 -05:00
sanyamsingh001andCodex fa7c6ff8ab ingest: preserve same-named camera takes during ingest
Co-authored-by: Codex <codex@openai.com>
2026-10-13 08:42:29 +10:00
Marco Arnulfo e22a49db1c fix(audio): crossfade audio transitions through the clip handles (fixes #1473) 2026-10-13 00:25:27 +02:00
Fabio LussiandClaude Opus 5.5 ddaf78c221 Keep transform handles in reach when the picture is past the monitor edge
The Program monitor's transform box drew and hit-tested its handles at
their true positions only, and the painter and the ui clip stop at the
picture area. A still moved to or past the frame edge left its resize
handles off the monitor. Handles beyond the monitor now stop at its
edge (the picture itself is not moved), and the box is drawn over the
whole monitor rather than only the picture.

Fixes #1393

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:21:48 +02:00
sanyamsingh001andCodex d91a7b3122 ui: keep Metadata and Info on the selected source item
Co-authored-by: Codex <codex@openai.com>
2026-10-13 08:11:35 +10:00
txiki739andClaude Opus 5.5 55c583f62b #262: Linux file dialogs shown off the UI thread keep case-insensitive filters
#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>
2026-10-13 00:08:20 +02:00
Marco Arnulfo 59506d9b4a fix(home): list recent projects on Home and in File ▸ Open Recent (fixes #1461) 2026-10-12 23:59:49 +02:00
Marco Arnulfo e5b1ed90a9 fix(dock): dock a panel along the edge of the whole workspace (fixes #1463) 2026-10-12 23:55:59 +02:00
bfenty 1ef2960514 h264: validate PPS fields before arithmetic; conceal weighted_bipred_idc 3 (#1441) 2026-10-12 21:15:13 +00:00
vangel76andClaude Sonnet 5.5 d034c58edd #1450: cargo fmt for the new mpegts tests and window field
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:05:40 +02:00
vangel76andClaude Sonnet 5.5 5198059a7c #1450: borrow program stream packets from the window instead of copying them
scan and read copied the 32-byte head of every packet and every pack, PSM
and PES packet (up to 64 KB) with to_vec before looking at it. They now
borrow the window; the borrows end before the next window access. Output is
unchanged: the new large-stream test (two streams, over 2 MiB, MPEG-1 and
MPEG-2 packs, cuts inside the last packets) passes on the old and the new
code, as do the existing round-trip and truncation tests. The allocation
saving follows from the removed to_vec calls; it is not measured (the
workspace forbids unsafe, so there is no counting allocator).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:05:29 +02:00
vangel76andClaude Sonnet 5.5 afc54a5f38 #1450: do not zero-fill the program stream window past the end of the file
A window refill resized the buffer to at least 1 MiB although read_some can
only fill what the file still holds. Near the end of the file, where the
previous window was shorter, that zeroed about a megabyte for every packet
whose length ran past the end. The buffer is now capped at the bytes left.
Window contents are unchanged: proved against the old refill for many
lengths, positions and sizes, and the zeroed byte count is asserted (at most
1000 against about 500 MiB for the old refill in the tail scenario).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:04:44 +02:00
vangel76andClaude Sonnet 5.5 da13964a82 #1450: table-driven CRC-32 for PSI sections
One table lookup per byte instead of eight shift steps. Proved equal to the
old bitwise loop (kept in the test as the reference) for every single byte,
random inputs of 0..4096 bytes, the CRC-32/MPEG-2 check value and the
section-plus-own-CRC-is-zero property.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:04:44 +02:00
vangel76andClaude Sonnet 5.5 1990bde6d3 #1450: fix two stale doc comments in mpegts
Unit.pos for transport streams is a byte offset (scan stores off + k *
packet_size), not a packet index; frame_bytes carried the doc line of
frame_info above its own.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:02:55 +02:00
vangel76andClaude Sonnet 5.5 5b76035c3d #1450: drop the unread PesHeader.stream_id and packet_length
Nothing outside one test read them. No behaviour change; the existing
header tests cover parse.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 23:02:55 +02:00
Marco Arnulfo 4d58c67745 fix(bitstream): map se(v) through the 64-bit codeNum so i32::MIN round-trips (fixes #1428) 2026-10-12 22:48:18 +02:00
MarekSpodBiedry 542300e911 fix(media-browser): drag every selected file to the Timeline, not just one (#1360) 2026-10-12 22:30:00 +02:00
vangel76andClaude Sonnet 5.5 393284d78f #1430: mpegts: resync inside the loaded block, bad adaptation field is not lost sync
Problem: in ts::scan every packet-parse failure re-read a whole 4096-packet
block from an offset that advanced about one packet. packet() returned None
both for a bad sync byte and for an adaptation_field_length that overruns the
packet, so aligned packets with a bad adaptation field cost one ~770 KB read
each (a 564 KB file made ByteSource::read_at fetch 846 MB). The fallback
offset (`pos + got`) also overshot by k packets, skipping unread data, and the
five-packet sync window only looked at the first packet_size start positions.

Fix: packet() distinguishes Bad::Sync from Bad::Adaptation. A bad adaptation
field means "no payload, grid intact": count a warning and go on with the next
packet. A real sync loss is repaired inside the loaded block (resync(): first
start whose five sync bytes line up, any distance); the block is refilled
from the file at the exact new offset only when it is used up. read() skips a
bad-adaptation packet instead of ending the unit.

Tests: read-volume tests with a counting ByteSource (bad adaptation fields,
sync byte every 189 bytes), and a resync test with a garbage prefix and
mid-stream garbage around the block boundary for 188- and 192-byte packets.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:09:27 +02:00
vangel76andClaude Sonnet 5.5 c6b5943e7e #1432: mpegts: bounds-check frame_info, cap chunks, units and allocations, drop non-PES data
Problem: frame_info indexed byte 6 of an AC-3 header that is only guaranteed
6 bytes long (panic), and gave E-AC-3 fscod2 3 a sample rate of 0. The PES
modes of Splitter never pruned their chunk list. read_unit reserved up to
4 GiB up front, the unit table was uncapped and 4-byte E-AC-3 "frames"
amplified input 16x. PesAsm kept passing continuation packets of a non-PES
unit start, and an adaptation-field-only unit start destroyed the PES in
progress.

Fix: b.get(6)? and None for the reserved rate; no chunk bookkeeping where
positions come from feed(); EAC3_MIN_FRAME = 8; MAX_UNITS (2^23) per stream
with a warning; read_unit preallocates at most 1 MiB and refuses units over
128 MiB; PesAsm gets a dropping state and ignores payload-less unit starts.
Regression tests for each.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:08:40 +02:00
vangel76andClaude Sonnet 5.5 cf9ad66732 #1429: MPEG-1 program stream cut inside a pack header no longer panics
Problem: packet_len accepted an MPEG-1 pack header (b[4]>>4==2) with
only 6 bytes available, but scan reads the SCR from head[4..9]. A file
ending inside the last pack header (00 00 01 BA 21 00 00) panicked with
"range end index 9 out of range".

Fix: packet_len requires the full 12-byte MPEG-1 pack header; a shorter
tail is not a packet and takes the normal resync path. The MPEG-2 branch
already needs 14 bytes (b.get(13)) before scan reads 10, so it is fine.
Tests: truncate a valid MPEG-1 and MPEG-2 program stream at every byte
length, plus the minimal 7-byte input; both panicked before the fix.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:07:25 +02:00
bfenty db6f5194fe Add edit.rippleDeleteHead (Ripple Delete Head Frame)
Remove the selected clips' heads - from each in point through the
playhead - and ripple the sequence closed. Linked clips act as one
group through edit::ripple_trim_group; a playhead past every member's
out point deletes the group whole via edit::ripple_delete_items.
Refused at or before a member's in point, and on locked members.

Tests: crates/engine/src/ripple_head_tests.rs (4 tests, red on main,
green with the patch, negative control by stash round-trip).

Fixes #1357
2026-10-12 19:52:29 +00:00
vangel76andClaude Sonnet 5.5 8457e7bf31 #1322: the Properties panel scrolls
Problem: the Properties panel laid its sections out in a plain child ui, so
when the panel was shorter than its content (Transform, Crop, Audio, the
speed button) the lower part was cut off and the wheel did nothing.

Fix: put everything below the clip header in a vertical ScrollArea, keeping the
rows 14 px clear of the scrollbar so the keyframe arrows at the row end stay
clickable. The speed button gets the automation id `properties.speed`.
Regression test properties_scroll_ui scrolls a short panel and checks the
speed button moves; it fails without the fix.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:19:59 +02:00
vangel76andClaude Sonnet 5.5 595f94f303 #1407: import Radiance HDR stills and image sequences
Problem: Premiere reads Radiance HDR (.hdr) pictures; FilmCraft listed
the extension nowhere and could not open them.

Fix: clean-room RGBE decoder in filmcraft-media from the public format
description: header with FORMAT, all eight axis orders, flat, old
run-length and new per-channel run-length scan lines. Frames are linear
float (Rec.709), like EXR. Allocations are bounded by the data present;
hostile headers and truncated data return errors. "hdr" joins the
importable still extensions; stills and image sequences share the decoder.
Output equals ffmpeg's decode exactly for flat and RLE files; EXPOSURE and
PRIMARIES lines are ignored and XYZE is refused.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:12:44 +02:00
vangel76andClaude Sonnet 5.5 9deba4a830 #1408: Shift constrains mask vertex and whole-mask drags to 45 degrees
Problem: Shift snapped pen segments (#853) but dragging an existing mask
vertex or the whole mask still moved freely.

Fix: while Shift is held the movement since the press is constrained to
horizontal/vertical/diagonal steps (accumulated raw vs applied totals per
gesture, so each frame's delta stays a single undo step). Unit test for
the pure step function; gaps.md G18 updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:12:19 +02:00
vangel76andClaude Sonnet 5.5 af5d29310e #828: import PXR24-compressed OpenEXR
Problem: OpenEXR files with PXR24 compression (a common lossy 24-bit
float format from renderers and compositors) were refused with "not
supported yet".

Fix: decode PXR24 chunks (16 lines, deflated byte planes of per-line
sample differences; floats keep their top 24 bits) into the existing
scan-line pipeline. Bounds-checked, no panics on damaged data. Tests:
hand-built chunks with half/float/uint channels and a partial last
chunk, damaged-file cases, and an OpenImageIO-written oracle comparing
our decode with OpenEXR's own (skips without oiiotool). Docs updated;
stale AVI / FLAC-in-MP4 entries removed from G10.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:56:26 +02:00
vangel76andClaude Sonnet 5.5 3516207de7 #1402: import MP1 (A_MPEG/L1) audio from Matroska
Problem: the Matroska demuxer mapped A_MPEG/L2 and A_MPEG/L3 only, so a
Layer I track was reported as an unsupported codec even though the MP1/MP2
decoder (#809) reads Layer I.

Fix: add Codec::Mp1 for A_MPEG/L1 and route it through the same packet
duration and decoder path as Mp2. Test remuxes synthetic Layer I frames
into Matroska with ffmpeg and compares our decode (max error 3e-5).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:55:35 +02:00
webdevtodayjason 20d196401a Captions: preserve tab-separated WebVTT voices 2026-10-12 13:51:26 -05:00
Marco Arnulfo 6192214def fix(previews): a nest's audio preview follows the sound of its sequence (#1370)
The content hash of a nested sequence covered only its video tracks, for
audio segments too. Changing the sound inside a nest (a clip's gain, a
muted track, a new clip) left the outer sequence's rendered audio preview
valid, so playback kept the old mix, or silence. Audio segments now hash
the nested sequence's mix (audio tracks, their clips recursively, master
and submixes) instead of its picture, so editing the picture inside a nest
no longer invalidates its sound either.
2026-10-12 19:45:00 +02:00
vangel76andClaude Sonnet 5.5 5553e26e12 #1371: export preset query also matches the format id
Problem: `export --list-presets h264` returned nothing because the query
only matched name, description and category, while `h264` is the format
id the CLI takes everywhere else.

Fix: also match the preset's format id and label, compared with
punctuation stripped, so `h264`, `h.264` and `H.264` are equivalent.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 19:39:44 +02:00
vangel76andClaude Sonnet 5.5 1d62db0172 #1368: nudge clip selection up/down no longer fails for linked video+audio
Problem: timeline.nudgeUp/nudgeDown returned an error for the whole selection when any selected clip was already on the outermost track in that direction. A video clip with its linked audio (A1 has no track above) therefore could never be nudged.

Fix: clips with no destination track stay where they are; the command only errors when nothing could move. Regression test covers a linked selection.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 19:35:54 +02:00
Nai-ITA 88675faf58 Merge pull request #1 from Nai-ITA/Nai-ITA-patch-1
Add files via upload
2026-10-12 18:57:14 +02:00
Nai-ITA d2ae945c30 Add files via upload 2026-10-12 18:56:50 +02:00
Marco Arnulfo c580406234 fix(masks): Delete / Backspace and Cmd+Z take back the last pen point while drawing (fixes #1345) 2026-10-12 18:45:56 +02:00
jahvariandCodex 44baf6c0f4 WIN-03: Make AVI oracle file reads portable
Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
2026-10-12 11:43:18 -05:00
Brandon ThomasandClaude Opus 5.5 71438c627b Release 0.7.2: install the wasm-bindgen CLI for the web release build
The shared release workflow installs trunk, but FilmCraft's web build
runs the wasm-bindgen CLI directly (cargo xtask web), so the 0.7.1 Web
job failed with "wasm-bindgen CLI not found". In CI, package.sh now
installs the CLI at xtask's WASM_BINDGEN version, as the per-app
release.yml did before the move to craft-common-actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.7.2
2026-10-12 12:37:09 -04:00
NetterSilver a6a7f95579 Docs: update the progress docs for this change 2026-10-12 18:36:19 +02:00
Marco Arnulfo 67f1ea1ae3 render: Sharpen stays visible at reduced playback resolution (fixes #1351) 2026-10-12 18:28:53 +02:00
Marco Arnulfo dadbfe0bf8 fix(masks): hide the mask handles while the clip is not selected (fixes #1341) 2026-10-12 18:17:42 +02:00
Marco Arnulfo 528e525d67 fix(shortcuts): Clear and reassign also drop a command's panel copy of its key (part of #1333) 2026-10-12 17:44:34 +02:00
Brandon ThomasandClaude Opus 5.5 0879bd7a7e Release 0.7.1: rebuild with the fixed shared release workflow
The previous release build failed in craft-common-actions, not in this
repo: riscv64 packaging got --formats deb,rpm,tar (fixed in
craft-common-actions#3), Linux jobs lacked the ALSA headers
(craft-common-actions#5), and Windows signing needed the AZURE_* secrets
listed in the caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:11:10 -04:00
Brandon ThomasandClaude Opus 5.5 84518da96f Release workflow: pass the Azure signing secrets so Windows builds are signed (#1169)
Since the release workflow moved to storytold/craft-common-actions, it has
passed only the Apple and WINDOWS_CERTIFICATE secrets. The signing job reads
values from the release environment, but only for names the caller lists, so
the AZURE_* names that Trusted Signing uses came through empty and Windows
builds would ship unsigned. Same fix as storytold/craft-launcher#174.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:08:21 -04:00
Marco Arnulfo 3f61c036ff codecs: MP4 frames stamped just after the frame grid show on their own frame (fixes #1282)
Phone footage stamps its frames up to a millisecond after the frame grid
(a first frame 34.1 ms long at 30 fps). The frame shown at a time is the
last one starting at or before it, so a sequence frame asked at its exact
start got the picture before: the clip ran one frame behind and showed
frame 0 twice. The request is already rounded to the track timescale
(#73, as WebM in #83), but at 90 kHz a millisecond is 90 units.

When opening an MP4, the video samples of a file that is a constant rate
gone slightly off its grid are put back on it: the grid starts at the
first picture and steps by the nominal frame duration, and the file is
snapped only when every picture is less than a quarter of a frame from
its own grid point and no two pictures share a grid point. Anything
further off is variable frame rate and keeps all its times; a picture one
unit off is left where it is, since that can't be told from timescale
rounding. Only the video sample times move: the audio, the first picture
and the clip duration are unchanged.
2026-10-12 16:50:49 +02:00
Bart BoonstraandClaude Opus 5.5 6bc526b5e1 Adjustment layers: a transition fades their effects in and out instead of cutting them in after it
During a transition on its track an adjustment layer rendered as nothing, because it has no picture
of its own: Cmd+D at its start left the effects off for the whole dissolve and then cut them in.
In a transition the layer is now the frame below with its effects (opacity, masks and Motion region
included), so a dissolve fades the effects. A fade from or to nothing keeps the layer's blend mode.
Frames where a transition touches an adjustment layer render on the CPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:28:00 +02:00
Vikram Bhaskaran 31539f1b84 Skip GPU golden tests when the adapter cannot render to Rgba32Float. 2026-10-13 00:40:09 +11:00
Vikram Bhaskaran b5e05a6501 Register .fcproj as a document the macOS app can open from Finder. 2026-10-13 00:39:15 +11:00
Vikram Bhaskaran 7fdccec8d7 Keep the project-panel sort arrow from covering a narrow column name. 2026-10-13 00:39:09 +11:00