* M3: Add shared custom colors and complete marker editing
* #1435: refine native colors and range endpoint flags
Use the macOS Colors panel for custom label colors and reuse the established egui picker on other hosts. Preserve draft confirmation, exact sRGB values, native text shortcuts and project ownership. Compact the swatches and center the add control, split range glyphs across their endpoints, localize the new controls, protect newer marker edits from stale dialogs, and cover the behavior with rendered UI and hit-test regressions.
Co-authored-by: Codex <noreply@openai.com>
* #1435: preserve imported palettes and marker double-click ownership
Union saved OTIO palettes across timelines with deduplication, bounded capacity,
first-name preservation and explicit overflow warnings. Keep null authors
consistent with omitted fields, and consume marker double-clicks before the
work-area gesture so opening the editor does not alter project history.
Correct the CSV URL column and schema documentation. Add six regressions for
palette retention/capacity, author handling, and physical overlapping gestures.
Validation: full cargo xtask ci (3666 passed, 45 skipped), 42 rendered UI tests,
and strict workspace/all-target Clippy on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: retain OTIO swatch names and generator labels
Ignore orphan name entries when retaining saved palette names so input ordering
does not hide valid names after the first 64 entries. Keep names bounded by the
retained palette and preserve existing valid names.
Include generator preset labels alongside custom label colors in OTIO metadata.
Add regressions for orphan-prefixed name maps and three generator kinds with
preset/custom colors through actual export/import round trips.
Validation: both regressions failed before fixes; all 72 interchange tests and
full cargo xtask ci pass (3668 tests, 45 skipped), plus strict workspace/all-target
Clippy on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: preserve distinct OTIO generator item identity
Use exported FilmCraft item IDs for generator media identity so identical
content can retain distinct source names, labels and custom colors. Repeated
references to one source item still share a single imported media entry.
Preserve content-based fallback for missing or invalid item IDs. Cover black
video, bars and tone, and color mattes with distinct items/shared references,
plus legacy and malformed identity metadata.
Validation: distinct-generator regression failed before fix; legacy compatibility
passed. All 74 interchange tests and final full cargo xtask ci pass (3670 tests,
45 skipped); strict workspace/all-target Clippy also passes on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: align Edit Marker layout and add safe marker navigation
Give the editor a wide aligned form, larger Notes area, side action column,
and grouped palette with vertical marker types. Expand the Web Link field
with the form and keep actions accessible in small windows.
Previous/Next saves valid edits as one Undo step and stays with the original
sequence/source owner, including coincident markers. Invalid drafts stay open;
unchanged navigation and Done add no history. Keep native/shared color pickers,
Author, Notes, URL validation and immediate marker creation.
Validation: all 45 rendered sequence/marker UI tests pass, including five new
navigation/owner/validation/layout regressions. Native macOS layout, picker
Cancel and exact single-step Undo restoration verified. Full standard cargo
xtask ci passes 3675 tests (45 skipped), doctests and all remaining gates;
strict Rust 1.99.1 workspace/all-target Clippy also passes.
Co-authored-by: Codex <noreply@openai.com>
* #1435: refine Edit Marker proportions and action alignment
Narrow the dialog to 680 logical pixels and keep the core order Name,
Time/Duration, Notes, Color and marker type. Place Author after the type-specific
options as secondary metadata. Preserve our palette, custom picker and range controls.
Use consistently sized, centered rounded action buttons with a primary Done action.
Shorten Delete Marker to Delete and remove the navigation helper and unused translations.
Keep the existing navigation save/validation/Undo semantics and automation IDs.
Validation: all 45 rendered marker/sequence UI tests pass, including small-window
action accessibility. Actual macOS layout and no-op Previous/Next/Cancel verified.
Full standard cargo xtask ci passes 3675 tests (45 skipped), doctests, formatting,
Clippy, translations, layers, assets and 49 WASM crates. Strict Rust 1.99.1
workspace/all-target Clippy passes separately.
Co-authored-by: Codex <noreply@openai.com>
* #1435: tighten marker layout and validate text editing
Use a narrower aligned form with Author below Name, bounded scrolling Notes,
left-aligned colors, centered actions and an inline Web Link URL/open icon.
Remove the legacy Flash Cue choice while preserving imported marker types.
Constrain timecode typing/paste to complete numeric colon-separated fields,
validate drop-frame labels and frame bounds, and disable Done for invalid timing.
Preserve high-frame-rate timecodes and point-marker semantics when Duration is
unchecked. Route native/menu clipboard and text Undo commands to focused fields;
explicit engine commands retain project Undo and selection semantics.
Validation: standard cargo xtask ci passes 3679 tests (45 standard skips),
doctests, fmt, strict workspace/all-target Clippy, i18n, layers, 69 assets and
49 WASM crates. Also passed 48 rendered marker/sequence tests and strict Rust
1.99.1 Clippy. Actual macOS clipboard, bounded Notes, point save and exact Undo
were checked. Windows/Linux desktop interaction remains pending.
Co-authored-by: Codex <noreply@openai.com>
* M0: Wait for frame-worker recovery before asserting
Do not treat a nonempty request queue as proof of worker death in the
panic-recovery regression. Keep waiting for all injected faults and enough
post-fault completions, then drain the queue without adding more seeks.
Retain the exact fault-count, successful-recovery and empty-queue assertions
and bound the wait with a two-minute deadline.
The inherited test failed twice in independent fork CI. It did not reproduce
locally: baseline passed 20 normal and 10 delayed-report runs; the repair
passed 50 normal and 10 delayed-report runs. No product or marker UI changes.
Validation: standard cargo xtask ci passed all 4485 tests (52 standard skips),
doctests, formatting, strict workspace/all-target Clippy, i18n, layers,
69 assets and 49 WASM crates.
Assisted-by: OpenAI Codex
---------
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <codex@openai.com>
* Raise a loaded project's next_id past the ids already in it (fixes#2809)
* Demo project: start new ids past its fixed transition and marker ids (#2809)
* Count transcript, source graphic and narration keys as ids in use on load (#2809)
* Format tests: a transcript's key raises next_id on load (#2809)
* Count ids that are only referenced (clip items, subclip parents, transition ends, sends, outputs, cameras, merged clips) on load (#2809)
A clip with audio_stream >= MAX_AUDIO_STREAMS is reset to stream 0 and media
with more than MAX_AUDIO_STREAMS streams keeps the first ones, each with a
warning: one bad index must never lose a whole project.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Update MediaInfo to store all discovered audio streams in audio_streams
- Retain independent stream metadata and decoder state for MP4/MOV and Matroska/WebM
- Update audio_placement_specs to allocate successive tracks via ensure_audio_tracks
- Isolate clip rendering to read assigned audio stream rather than replaying stream 0
- Bump project schema to v13 with backwards compatibility for legacy v12 projects
Resolves#312Fixes#200Fixes#315
Edit: Label ▸ 16 colours + Select Label Group, Paste Attributes… (⌥⌘V, with
Scale Attribute Times), Remove Attributes…, Select All Matching, Remove
Unused, Consolidate Duplicates. File: New ▸ Sequence From Clip, Bin From
Selection (⇧B), Offline File…; Close Project (⇧⌘W, asks to save), Save All.
Clip: Make Subclip… (⌘U, Restrict Trims), Edit Subclip…, Modify ▸ Audio
Channels… (⇧G) / Timecode…, Video Options ▸ Frame Hold Options…, Add Frame
Hold (now splits at the playhead), Insert Frame Hold Segment, Field
Options…, Time Interpolation (Frame Sampling / Frame Blending / Optical
Flow, blending rendered on CPU; optical flow falls back to blending),
Fit to frame / Fill frame; Audio Options ▸ Breakout to Mono, Extract Audio
(WAV next to the project, imported); Replace With Clip ▸ From Source
Monitor / Match Frame / From Bin. Hold Filters: effects animate through a
hold unless set. Menus support nested submenus (egui and native) and follow
Premiere's order. Dialogs in panels::clip_dialogs with automation ids and
ui.set {clipDialog}.
Project schema v9 (no-op migration v8→v9, v8-subclip fixture): clip
time_interpolation / hold_filters / field_options / source_channels,
Interpretation.audio_channels, Subclip.restrict_trims.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- crates/speech (L2): Transcriber trait, FixedTranscriber, Whisper model catalogue (pinned,
SHA-256 verified) with optional downloader (feature `download`: ureq + rustls + RustCrypto),
pure-Rust Whisper inference on candle with word timestamps (feature `whisper`), log-mel, VAD
word tightening, MFCC speaker clustering. Both features off by default and for wasm.
- project: per-media-item transcripts (Project::transcripts); schema v9 with a no-op v8->v9
migration and a v8 fixture.
- edit::transcript: sequence transcript derived from clip transcripts, search, paragraphs,
word ranges, pause/filler detection, ripple delete of many ranges, caption layout.
- engine: transcript.* commands (generate, set, delete, inspect, search, select, extract, lift,
renameSpeaker, removeFillers, removePauses, createCaptions, models, downloadModel);
Session::transcriber for hosts/tests; features `whisper` / `speech-download` (also on the
desktop and CLI apps). Without whisper, transcript.generate fails with a clear error.
- ui: Text panel Transcript tab (Transcribe button, speaker paragraphs of clickable words,
Shift+click selection -> In/Out, extract/lift/remove fillers/create captions, search) with
text.transcript.* automation ids; headless UI test.
- docs/transcripts.md, crates/speech/README.md, architecture and project-files updates.
whisper-tiny measures 12.2% WER over 797 words on local samples.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- New crate filmcraft-format (L3): files are an envelope {format, schema_version, generator,
project}; a chain of single-step JSON migrations (v1 bare Project → v2 envelope) upgrades old
files on load; newer-than-supported files are refused with a clear "update FilmCraft" error;
damaged/foreign files report as such.
- atomic_write: temp file in the same dir + fsync + rename + dir fsync; used for every project
write (FsServices), so a crash mid-save never corrupts the project.
- Engine: file.save/saveAs/open go through the format crate; new file.saveCopy (Save a Copy…,
Cmd+Alt+S) and file.revert; the first save over an upgraded file keeps
"<name> (schema vN backup).fcproj". Project.version dropped (the envelope carries it).
- Hand-made v1 fixtures (minimal + edit without later serde-default fields) in
crates/format/tests/fixtures; 2,000-clip encode/decode timing test.
- docs/project-files.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>