- LICENSE-MIT / LICENSE-APACHE from the Crafting Apps standard (copyright "ArtCraft Team and the
FilmCraft contributors"; Apache text in the canonical apache.org layout)
- NOTICE (new): license, brand carve-out, third-party list from ATTRIBUTION.md
- docs/brand/LICENSE-brand.txt (new): ArtCraft brand terms; brand sidecars, ATTRIBUTION.md and
AGENTS.md §1.8 point to it (owner "ArtCraft Team"; forks and modified versions remove the marks)
- README: "## License and credits" section per the standard (absorbs "Credits and clean room"),
badge anchor #license-and-credits, alt text "License: MIT OR Apache-2.0"
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Over the control channel (MCP bridge mode) agents read the live app with
ui.screenshot / render_frame and ui.elements right after an edit, and got
pictures of a state that was still changing:
- render_frame in bridge mode moves the playhead and screenshots the
Program monitor. After a seek the monitor shows the nearest cached
picture until the exact frame is decoded, so a deep seek into a long
file returned the previous picture (even the previous sequence's).
- ui.elements answered while the timeline zoom was still animating (the
fit after opening a sequence), with clip rects that moved afterwards.
Screenshots are now taken once paused monitors show their exact frames
and the timeline zoom is at rest (at most 5 s, then whatever is there).
ui.elements retries until the zoom has been at rest for two frames: it
answers from the frame before the last one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Opening a sequence fits the timeline once, on the first frame. An empty
sequence fits its 1 s minimum duration, so clips added afterwards (File
> New Sequence then a drag, an insert, or timeline.place over the
control channel) showed at frame-level zoom: the first clip filled the
whole track and the rest were off screen.
The zoom an empty-sequence fit chose is remembered; when the sequence
gets content and the zoom is still that value, the timeline fits again.
A zoom changed in between is kept.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Phones record portrait video as landscape pictures plus a rotation in the
container: the MP4/MOV tkhd matrix (ISO/IEC 14496-12 §8.3.2) or the
Matroska Projection pose roll (RFC 9559 §5.1.4.1.28.46). The matrix was
parsed but never used, so every portrait iPhone clip imported sideways
at its landscape size.
- isobmff: Track::display_rotation() reads 0/90/180/270° from the matrix
signs (mirrored / sheared matrices are left alone).
- matroska: parse Projection (type, yaw, pitch, roll);
VideoInfo::display_rotation() for rectangular projections.
- frame: VideoFrame::rotated() turns every plane at its own resolution
(4:2:2 chroma is widened to 4:4:4 for quarter turns) and swaps the PAR.
- codecs: Mp4Source / MkvSource report the displayed size and PAR, and
GopCache rotates decoded frames before caching them.
- web: the WebCodecs source configures the decoder with the coded size
and rotates its output the same way.
Tests: a one-frame ProRes MOV built in the test with 0/90/180/270°
matrices (reported size + which half ends up on top), plane rotation for
RGBA / 4:2:0 / 4:2:2, and a synthetic Matroska file with a -90° roll.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
file.newSequence and sequence.settings accepted fps 0 (or a negative
rate). The next frame computation divided by zero; over MCP the panic
poisoned the session lock and every later call failed with "session lock
poisoned" until the server was restarted, losing unsaved work.
Both commands now reject rates whose frame duration is not positive.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Desktop/shared:
- Frame workers catch panics per job: a failing decode/render no longer kills the worker
or leaves its frame in flight forever (blank monitors). Counted as perf.stats failedJobs.
- UI pass catches panics and shows a "FilmCraft hit an error" window (Save Project /
Continue) instead of closing the app.
- Panic hook writes <data dir>/Logs/crash-<day>.log with thread, location and backtrace;
a window that can't start shows an error dialog instead of exiting silently.
- GPU compositor only on adapters that render/blend Rgba16Float with >= 4096 textures;
GPU validation errors and oversize frames switch to the CPU compositor instead of
wgpu's default panic.
- Dock layout and Media Browser splitter no longer panic on tiny panels/windows.
Web:
- Export mode / previews / voice-over / log reveal no longer call std::env::temp_dir
(panics on wasm32): new filmcraft_engine::temp_dir(); default export dir /exports.
- Fatal-error overlay with Reload; WebGPU device failure retries on WebGL2 (?webgl);
cache-busted wasm/glue URLs; webcodecs entries[0] guard.
Tests: robustness_ui (worker survives injected panics, UI panic recovery, tiny windows),
crash hook, dock split, GPU plan size, default export dir; web smoke test extended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Lumetri grades PQ / HLG working spaces in their own signal normalised to
HDR White (Basic Correction) / HDR Range (Curves) in cd/m²
(filmcraft_color::GradeSpace): exposure in stops of light, highlights above
HDR White kept, HDR Specular scales them; Rec. 709 unchanged.
- HDR static metadata (mdcv/clli, Matroska MasteringMetadata/MaxCLL/MaxFALL)
on VideoStreamInfo::hdr; PQ media use MaxCLL / mastering peak as the
BT.2390 source peak; media.colorInfo reports it.
- HSL Secondary Refine: Denoise (median of the key) and Blur (Gaussian).
- Lumetri Presets (18 original looks in 4 folders) with thumbnails rendered by
our Lumetri on a procedural preview picture; Effects panel rows and a
thumbnail grid when wide; lumetri.presets / applyPreset / presetThumbnails.
- Color Match: Comparison View toggle; Apply Match uses its reference frame.
- Goldens lumetri_hdr_pq and lumetri_presets_grid; D-Log M stays unsupported
(no published formula).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Multi-Camera view: automatic / 2x2 / 3x3 / 4x4 grid layouts paged when the
angles don't fit (page arrows, keys 1-9 pick cameras on the shown page),
Multi-Camera Selection Top Down, Show Multi-Camera Preview Monitor (grid
fills the monitor when off), Auto-Adjust Multi-Camera Playback Quality
(lower cell decode scale while playing), Transmit Multi-Camera View (stored,
no device yet), Edit Cameras dialog with a thumbnail per angle. Only the
shown page's angles are decoded, at the cell scale. Engine commands
multicam.gridLayout/page/nextPage/prevPage/selectionTopDown/
showPreviewMonitor/autoAdjustQuality/transmitView/grid.
Subclips: restricted subclips limit trims, rolls, slides and slips on both
sides (EditCtx::media_start); the Source monitor shows a subclip's range
(or the whole master with the range as In/Out when unrestricted), opens at
its In and shows the master clip's markers inside it (source.inspect);
Convert to Master Clip keeps the range as In/Out and the inherited markers;
Make / Edit Subclip and Convert to Master Clip in the Project panel menu.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sub-pixel filter passes run over fixed block widths; frame / region planes are recycled
through a bounded pool (zeroed on reuse) instead of fresh calloc / munmap per frame; the
palette mode-info arrays (40 bytes per 4x4) exist only when screen content tools are allowed;
CDF adaptation is branch-free. Draft mode skips deblocking, CDEF and loop restoration of shown
frames that refresh no reference slot. Media-stack test: VP9 / HEVC / AV1 draft playback only
reaches draft requests, and an export afterwards is bit-exact with ffmpeg.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Interpolation keeps its reference windows in reusable scratch (no 2 x 10 KB zeroing per block)
and filters with taps outer / outputs inner over fixed block widths; SAO edge and band offsets
select the offset per lane instead of a table lookup; uni / bi output clips with min / max; runs of
bypass bins decode with one division; context-coded bins are branch-free. Draft mode skips
deblocking and SAO of sub-layer non-reference pictures of the top sub-layer. Bit-exact with 1, 3
and all threads; draft output differs only on flagged pictures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The loop filter's lane masks are 0 / -1 integers with bitwise selects and min / max clipping
(bool masks and clamp kept it scalar); the 2D inverse transform's column pass runs the generated
butterflies on 4 / 8 columns at once; 8-bit sub-pixel filters accumulate in 16-bit lanes (every
sum of the VP9 filters fits modulo 2^16). Branch-free bool decoder update. Bit-exact; tested
against the per-column transform on random blocks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frames are published one superblock row at a time once loop filtered; a post stage per frame
(own thread) assembles bands from the tile strips, filters them in raster order and builds the
output picture, while the next frame's tile columns decode and wait per band for the reference
rows they read. Bit-exact with 1, 3 and all threads. Draft mode skips the loop filter of frames
that refresh no reference slot. av1dec / hevcdec bench knobs and VP9 / AV1 4K playback scenarios
in the bench.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
filmcraft-mxf gains a streaming writer (ST 377-1 partitions, primer, header
metadata, VBR index segments with temporal offsets, RIP; ST 378 OP1a
frame wrapping, ST 390 OP-Atom clip wrapping) for VC-3, ProRes, AVC byte
stream and PCM with start timecode and caller-supplied package UMIDs, plus
write_opatom_pcm. filmcraft-export adds mxf-op1a / mxf-opatom formats
(DNxHR, ProRes or H.264 + PCM; OP-Atom writes one mono file per channel),
presets, the engine mxfVideoCodec parameter and CLI .mxf inference.
Tests read our files back and check them against ffprobe / ffmpeg.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Premiere's AAF and OMF export options: embedded or separate WAV/AIFF audio,
sample rate and bit depth, trim with handles, rendered clip effects, breakout
to mono, AAF video mixdown and linked media; AAF/OMF import writes embedded
audio next to the document and links it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared mob-style composition model; AAF objects in structured storage over
filmcraft-cfb; OMF objects in a Bento container; embedded / consolidated audio
supplied by the caller (essence::audio_needs, MediaOptions).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>