47 Commits
Author SHA1 Message Date
Vikram Bhaskaran c63d9766e9 Scope the Rgba32Float skip to the effect-chain parity test.
Main now falls back to CPU effects when an adapter cannot render to
Rgba32Float, so the scene, blend and transition parity tests still run
on such adapters. Only gpu_effect_chains_match_cpu_render needs a float
render target, and it is the one test that skips without it. Also revert
the import reorder, which failed cargo fmt --check on edition 2024.
2026-10-15 22:53:52 +11: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
Vikram Bhaskaran 5a4bbc5916 Stop Linux H.264 export hanging when NVENC is absent.
AMD and Intel GPUs expose VA-API EncSlice, not NVENC. The export path
still opened NVENC first and then waited forever on wgpu map_async
(radv). Probe EncSlice before NVENC, fall through to the software
encoder, and bound GPU readback waits to eight seconds so a wedged
device fails the GPU path instead of blocking the export.
2026-10-12 00:09:32 +11:00
Vikram Bhaskaran 9891fd11a4 Keep timeline clips when Project Clear removes used media.
Clear used to strip every track item that referenced a deleted Project file. Those clips now stay on the sequence as Media Offline, and media.relink still finds the item. Unused media, bins, and generators are still removed.
2026-10-11 22:59:16 +11:00
Vikram Bhaskaran b082d6ab0b Honor frame/seconds/timecode on Source Mark In/Out and Mark Split (#920)
Source marks only read `time` (ticks) and otherwise used the Source playhead,
so agents passing `frame:24` marked frame 0. Parse the same time formats as
Program, using the Source item rate.
2026-10-11 22:49:23 +11:00
Vikram Bhaskaran 66c2e63092 Draw underlines for vertical graphic text.
The vertical layout path never emitted underline rectangles, so layer and
run underlines were a no-op. Place a tall strip to the right of each
underlined cell (vertical-rl) and compare horizontal vs vertical "A" at 60px.
2026-10-11 22:49:08 +11:00
Vikram Bhaskaran 6251b39b8f #907: apply Median radius in source pixels without a 4px cap
Radius was clamped to 4 working pixels, so values above 4 matched radius 4
at full resolution. Scale by px_scale and cap only to the image size.
2026-10-11 22:48:24 +11:00
Vikram Bhaskaran 3fd70ff774 Shift whole-style underlines with baseline_shift.
Plain layout() underlines sat on the unshifted baseline while layout_rich()
runs already subtracted baseline_shift. Match the two so underline y tracks
the glyphs for a full-paragraph style.
2026-10-11 22:44:29 +11:00
Vikram Bhaskaran 82609afec9 Fix Automate to Sequence dissolve duration when overlap is clamped.
Placement already limited overlap to half of each clip, but Cross Dissolve
still used the requested overlapFrames, so a 30-frame dissolve on two
20-frame clips started before the first clip. Apply the clamped per-cut
overlap as the transition length.
2026-10-11 17:56:18 +11:00
Vikram Bhaskaran b388c61684 Keep New Sequence open when the engine rejects the frame size.
OK used to close the dialog even after file.newSequence failed, so
reopening reset the name and settings. Stay open on validation
errors so one field can be fixed.
2026-10-11 17:52:32 +11:00
Vikram Bhaskaran 93be6e7da1 cli: exit 2 for invalid mcp --bridge address
`mcp --bridge` treated a non-loopback address as a command failure (exit 1)
while `exec` already mapped the same parse error through usage (exit 2).
2026-10-11 17:50:07 +11:00
Vikram Bhaskaran 82c318ed5a #915: Match Frame replacement maps source frames on reversed clips
Replace With Clip ▸ Match Frame used a forward-only offset, so a reversed
clip lined the Source monitor up with the wrong media time (source 50 at
sequence 20 became 69). Align source_in from reverse-aware source mapping.
2026-10-11 17:46:35 +11:00
Vikram Bhaskaran df282bcdc1 #918: keep fade-out on the clip end after Speed/Duration
Non-ripple clip.speedDuration shortened the clip but left one-sided
out-edge transitions at the old timeline range. Reposition them with
the same edge-follow used for a regular trim.
2026-10-11 17:14:16 +11:00
Vikram Bhaskaran 361ba9d58c #914: one undo step for a multi-point Trim by Frames.
Selecting two clip edges and trimming by frames applied each edge as its own
timeline.trim, so Undo restored only the last clip. Collapse those edits (and
extend-to-playhead / apply-default-transition) into one history snapshot so
Undo and Redo cover every selected point.
2026-10-11 17:13:54 +11:00
Vikram Bhaskaran d79248489b Refuse timeline.move when the clip's source track is locked.
Moving off a locked track used to skip delete_items and overwrite a
second item with the same clip id (#917).
2026-10-11 17:12:33 +11:00
Vikram Bhaskaran 53b99ae335 Keep linked rate-stretch partners at one speed.
A neighbour on only one track used to clamp that partner alone, so picture
and sound stayed linked at different rates. The tightest room now limits
the whole group.
2026-10-11 17:11:52 +11:00
Vikram Bhaskaran eea3afa8be Essential Graphics: an Install refused shows why on the status bar (#611).
The Browse panel's Install… button calls the module's route directly and drops its
result, while only menus.rs surfaced a refused file — so installing another
application's template package (an EffectCraft .ectemplate ZIP renamed to .fcgt,
the case in the report) looked like nothing happened. The engine has refused ZIP
archives with a clear message since M10.7; the route now puts that message on the
status bar itself, whichever caller arrives.

Headless: clicking Install with the picker pointed at a ZIP-named file requires
the status bar to name the ZIP archive; without the surfacing the status stays
empty — the reporter's exact symptom.
2026-10-11 15:03:16 +11:00
Vikram Bhaskaran 3da5dec8d4 Export FCP7 XML master-clip media markers (xmeml 4/5).
Timeline clipitem markers already round-tripped; source-media annotations on
master clips were omitted with an empty export report. Write those markers on
<clip> so re-import keeps them.

Fixes storytold/filmcraft#900.
2026-10-11 15:03:07 +11:00
Vikram Bhaskaran 50f9cfecc0 Fix OTIO nested sequence vs clip instance markers (#901)
Export was overwriting Stack markers with the using clip's markers, so a nest with no instance markers lost its sequence markers, and instance markers were imported onto the nested sequence. Keep sequence markers on the Stack and store clip instance markers in metadata.filmcraft.clip.
2026-10-11 15:02:25 +11:00
Vikram Bhaskaran b13567439b Fix FCPXML one-frame markers importing as ranges
FCPXML writes point markers as one frame at the sequence rate. Import
compared duration to 1 tick, so a 24fps one-frame marker became a
range. Treat duration ≤ one sequence frame as a FilmCraft point.
2026-10-11 15:01:54 +11:00
Vikram Bhaskaran 7fef64de6b #911: refuse timing edits on locked tracks
Trim, roll, slip, slide, rate stretch and Speed/Duration now fail with
"track is locked" instead of changing clips on a locked track, matching
same-track move. Linked partners on locked tracks are left alone.
2026-10-11 14:09:05 +11:00
Vikram Bhaskaran 0a4be7b968 Clear the saved path when opening the demo project.
file.openDemoProject left Session.path pointing at the previous
.fcproj, so File ▸ Save overwrote that project with the demo.
Match New Project: drop the path (and the associated preview dir)
so Save requires Save As and the original file stays intact.
2026-10-11 14:04:39 +11:00
Vikram Bhaskaran 8d62b7fe1a Keep recovery snapshots when session.json is missing or corrupt.
Startup scan used to delete an unlocked recovery session whenever
session metadata could not be parsed, even if snapshot.fcproj was
intact. Offer that snapshot for recovery instead of removing it.
2026-10-11 14:03:25 +11:00
Vikram Bhaskaran ba4dacdeff #887: coalesce Scale (and similar) hot-text drags into one undo
A drag of Effect Controls / Properties numbers already used merge+begin, but
the press-start memory was only written on frames that emitted setParam.
egui drops unused temp data after a quiet frame, so a Scale scrub that
paused between percents began a new undo step for every 1%. Refresh the
drag session on idle frames while the button is down; still begin a new
step on the next press. Same keep-alive for graphics property drags.
2026-10-11 13:05:18 +11:00
Vikram Bhaskaran 488259414b Enable Project panel Reveal in Finder for clips with a media file.
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).
2026-10-11 13:02:55 +11:00
Vikram Bhaskaran f733230b9f #823: import every MPEG audio stream, not only the first PID
Transport and program streams listed a single audio stream, so file.import
and New Sequence From Clip kept one clip. Probe every audio PID (capped),
decode each independently, and place linked clips per stream. MP4/MKV
already did this; MXF same-rate PCM is still interleaved as one stream.
2026-10-11 13:01:20 +11:00
Vikram Bhaskaran f9f7ea4666 #848: LongGOP seek / time-to-first-frame, not decoder throughput
Pin GOP-cache eviction on the requested pts so a burst past the playhead
does not drop the target and walk the GOP again. Preroll only schedules
the frames that gate clock start. bench_playback no longer meters preroll
jobs as on-clock latency.

This is the seek stall from #848, not the ~3× per-core gap vs ffmpeg.
2026-10-11 11:35:59 +11:00
Vikram Bhaskaran 111991591b Roll linked audio with the picture cut (#855).
timeline.roll follows linked partners at the same through-edit when linked
selection is on, so a +12 frame roll on V1 also moves A1. The command
reports linked:false when the cut is not followed as a pair. Reversed
clips keep the unmoved-edge media mapping (#526/#558).
2026-10-11 11:17:47 +11:00
Vikram Bhaskaran b964b9970a #856: Reject negative times on timeline.place and markers.add
Clips and markers before sequence start were accepted, then unreachable
in the GUI and cut off on export. Time, frame and seconds before 0 now
return a parameter error; zero remains valid.
2026-10-11 11:16:50 +11:00
Vikram Bhaskaran 199223f3b9 #697: Paste cut clips from the keyboard even when old OS files linger
Copy and Cut snapshot files or an image already on the system clipboard.
Paste ignores that same media so Cmd+V and the Edit menu paste the clips
instead of re-importing stale files the platform left beside the clip names.
2026-10-11 10:16:50 +11:00
Vikram Bhaskaran 03bf8b1f33 Fix OS drops on an empty Timeline creating a sequence.
Dragging files from the explorer onto the Timeline imported them into the
Project bin but never placed them when no sequence was open, because only
the clip-area interact path consumed pending_timeline_drop. The empty
Timeline now creates a sequence from the first imported item and places
any further items after it, matching the existing Project-panel drop.
2026-10-11 10:09:44 +11:00
Vikram Bhaskaran 995053922e Show Parametric EQ in Effect Controls on linked A/V clips.
Audio effects applied to the video side of a pair now land on the linked audio, and Effect Controls lists that clip's parameters and Custom Setup while the picture is selected.
2026-10-11 10:09:36 +11:00
Vikram Bhaskaran d3444534a6 Fix Clear on Close Sequence also dropping File Close (Cmd+W).
File ▸ Close aliases Close Sequence. The shortcut editor targeted
sequence.close while Cmd+W lived on file.close (and Timeline), so Clear
left the chord bound. Treat the pair as one shortcut family.

Fixes storytold/filmcraft#773
2026-10-11 10:04:44 +11:00
Vikram Bhaskaran d4ec47a4a3 Clear leftover Project item selection when making a new bin.
New Bin only selected the folder and started rename, so Clear still targeted clips that were selected before. The trash button and Delete then removed those items and left the bin. Clicking a bin already deselects items; creating one now does the same, and Clear drops the rename field so it does not keep editing a bin that is about to go.
2026-10-11 09:39:29 +11:00
Vikram Bhaskaran 97243984d9 #496: Keep Link Media actions accessible for large lists and long paths. 2026-10-11 03:41:59 +11:00
Vikram Bhaskaran ff171b9c8c #680: Preserve individual linked-clip selections when deleting media. 2026-10-11 03:41:52 +11:00
Vikram Bhaskaran 9e77d9d786 Apply Transform shutter angle when the override is on.
The Transform effect listed a shutter angle but had no override, so motion blur never used it. Checking Use Effect Shutter Angle now samples the animated transform across that angle.
2026-10-11 02:48:52 +11:00
Vikram Bhaskaran ec7c43eea2 Treat media extensions as case-insensitive on import.
Camera files such as CLIP.MOV were hidden or skipped on Linux because sibling matching and tests assumed lowercase suffixes. Import, the media browser, and image-sequence numbering now accept mixed-case extensions.
2026-10-11 02:39:53 +11:00
Vikram Bhaskaran 0a1f9730c8 Add file.import replace mode for empty-project round-trips.
Headless import merged into the current project, so a demo or leftover timeline mixed into export. replace:true starts from file.newProject with the same name, then imports, which is the documented empty-project-start workflow.
2026-10-11 02:36:46 +11:00
Vikram Bhaskaran 80db16ebd5 Apply Ultra Key Setting as a parameter preset.
Relaxed and Aggressive previously only scaled two internal multipliers, so the matte stayed at Default. Switching Setting now writes Premiere-like matte values and the renderer uses that set, including Custom for hand-tuned keys.
2026-10-11 02:34:08 +11:00
Vikram Bhaskaran 6d1c4fdb84 Pass Hard Limiter look-ahead into the DSP limiter.
The project Look-Ahead Time parameter was stored but never applied, so 0 ms and 30 ms mixed the same clip. The limiter now sizes its look-ahead from that parameter and pre-rolls for the chosen window.
2026-10-11 02:28:52 +11:00
Vikram Bhaskaran 170852d8db #533: Preserve explicit export sample rates to avoid silent substitution. 2026-10-11 02:00:58 +11:00
Vikram Bhaskaran ac83bae223 Blend graphic gradients in linear light and keep per-character fills solid.
Stops were mixed in encoded sRGB, and any run with its own fill turned the whole layer into a solid colour. The ramp now blends in linear light, turns with the layer, and leaves a per-character fill solid.
2026-10-10 13:18:45 +11:00
Vikram Bhaskaran d55ebe94e5 Fill graphic shapes and text with a linear gradient.
Appearance › Fill Type paints a ramp across the layer bounds, and the ramp turns with the layer. A per-character fill colour still paints those characters as a solid.
2026-10-10 12:05:03 +11:00
Vikram Bhaskaran c855c50ba9 Export sequence markers to a spreadsheet-safe CSV.
The report is sorted, uses the sequence timecode, escapes formula-like text, and does not change the edit.
2026-10-10 04:37:44 +11:00