Release
v4.2.0
Added
- Rolling and ripple edits now show a live 2-up OUT/IN comparison in the program monitor while dragging. The overlay is owned by the timeline gesture, publishes only from the snapped and validated plan, and clears on commit, Escape, pointer cancel, destroy, and tool changes. It reuses PreviewLayer and the existing decoder prewarm, proxy, and filmstrip path without a second owner, handles gaps, speed, reverse, sourceStart/sourceEnd/sourceFps, linked audio-to-visual companions, and image/composition/Lottie sources, and labels OUT, IN, and GAP with high-contrast timecodes that remain usable at 320 px without hiding export or quality failures. Slip shows new IN/OUT with baseline IN/OUT corners; slide shows the left OUT and right IN at the new cut with their pre-drag baselines as corner thumbnails, both rendered as fitted virtual items so the compared frame is always visible and aspect-correct.
- Focused 2D composition timeline for Motion workspace. When a `composite-2d` composition is active the footer shows a single dedicated surface instead of stacking. The compact layout keeps layer names, in/out work area and FPS header always visible, uses a shared row model so sidebar labels and the scrollable bar/keyframe lanes stay aligned, and collapses to a single column below 640px without widening a 320px page. Scrubbing the ruler seeks via the shared clock without marking the project dirty or calling autosave.
- Layer rows expose Position, Scale and Anchor as localized vector lanes. Diamonds are rendered in the scroll surface, culled via the shared timeline viewport, and use typed vector helpers without `as any`. Diamonds are interactive buttons wired to the shared `keyframeSelectionStore`; dragging a diamond repositions its frame through atomic keyframe actions with a single undo and restores on Escape or pointercancel.
- Layer bars support pointer move and start/end trim with edge detection, adaptive snapping via shared snap targets, a single commit/undo on release, Escape/pointercancel restore, locked-track guards, and no autosave while drafting. Drafts reuse `planLinkedMoveGesture` and `planTrimGesture` instead of reimplementing semantics.
- Transform parenting uses a pick-whip that highlights valid layer rows, validates only via `itemById` (no track ID casts), and shows localized cycle/duplicate errors. A successful link or detach clears to a localized success status (“Parent linked”/“Parent removed”), records exactly one undo, and cleans window listeners on destroy.
132 more entries in the full changelog.
Fixed
- Made clean frontend test runs generate SvelteKit's ignored configuration before Vitest starts, so fresh Linux release candidates no longer fail during dependency optimization.
- Kept Android release builds reproducible by aligning the standalone app with the current Expo SDK 57 patch set and resolving one shared linking module across all native packages.
- Updated ZIP extraction used by local AI model tooling to the patched release that rejects crafted archives with abusive memory sizes.
- Edit comparison frame mapping is covered by pure tests for gaps, speed, reverse, sourceFps, linked companions, images/compositions, and timecodes, plus Chromium pointer tests that drive real timeline drags for rolling, ripple, slip, and slide, verify baseline-vs-dynamic distinction, audio-linked visual resolution, cancellation cleanup, single undo entries, absence of URL leaks, and 320 px layout.
- Composition fps header no longer hardcodes 30 due to missing parentheses.
38 more entries in the full changelog.
Changed
- App releases now publish an unpublished n8n package version only after the exact backend revision is live, then verify registry integrity, provenance, the n8n community-package scan, and a clean n8n install before making the GitHub release public.
- Extended `Clock` to support signed transport rates with FreeCut-accurate ceil/floor framing, precise `[start, end)` range boundaries, forward and reverse looping, pause-and-restore range semantics, one animation-frame loop across wraps, and a hard stop at timeline zero. Successive J/L presses advance `1x`/`2x`/`4x` and direction changes reset to `1x`; negative `playbackRate` never reaches `HTMLMediaElement.playbackRate`.
- Program preview now shows real reverse frame progression via the Clock frame queue and schedules short decoded reverse-audio grains through the existing track, clip, fade, and master gain paths. Media elements stay paused and are driven by drift-checked seeks; the stacked compositor and prewarm paths remain unchanged.
- Source Monitor now owns hover and focus routing, uses native positive `playbackRate` where browser audio stays safe, and falls back to exact frame-by-frame `requestAnimationFrame` seeking plus reverse-audio grains for reverse shuttle with correct `in`/`out` clamping. `K` pauses only the active monitor and leaves the other transport untouched.
- Added a compact localized shuttle indicator (`J`/`L` with direction arrow and speed) for transient shuttle mode, including the first `1x` press, with subtle styling at `1x` and highlighted styling at `2x`/`4x`. Normal play and every explicit pause reset the transport to `1x` normal mode.
4 more entries in the full changelog.
Quick Cut — multi-source, bounded streaming, and export semantics
- Quick Cut now uses stable multi-source IDs with `File`/`FileSystemFileHandle` resolution (`probeSourceFile` via `displayWidth`/`displayHeight`/`codec`/`sampleRate`/`channels`/`rotation`/`fps` and `EncodedPacketSink` keyframes) and `QuickCutSegment.sourceId`. The route opens multiple files in one picker, shows a source selector with missing-file warning, and adds segments from any source. Project JSON persists `sources` metadata and reconnects via `handles-db` with fingerprint verification before binding.
- Preview and segment editing switch to the segment's source. Timeline, timecode, and duration use the active source's metadata. Loop modes handle source switches at segment boundaries.
- Merge preflight compares real `videoCodec`/`audioCodec`/`width`/`height`/`sampleRate`/`channels`/`rotation`/`container` support via `getSupportedVideoCodecs` and FPS/timebase, estimates output bytes, and checks `navigator.storage.estimate` with a fixed reserve and explicit unknown/pending state (one storage contract). Incompatible merges require a unified transcode with a visible reason.
- Streaming is bounded: every scalable path writes to an OPFS `StreamTarget` scratch file. Export helpers return a plain `{scratchPath, fileName, scratchFile, wasLossless, reason, estimatedBytes}` token (serializable, no closure) and a production `discardScratchFile` helper (tested via `structuredClone`). Only the main thread copies chunkwise (4 MiB) via `openBlobWriter` (static imports, reader cancel/release in `finally`, partial final rollback). No `BufferTarget` or `arrayBuffer` for large outputs; temp files for merged transcode are also streaming and cleaned on success/cancel/init/encode/mux failure.
- Export semantics: no dummy `import('mediabunny')`, no speculative comments; `Conversion.isValid===false` throws `UnsupportedStreamCopyError` without retry, `AbortError`/mux failures are not retried, fallback only from explicit preflight before `output.start()`; sequence numbers monotonic per track; exact merged retains ordered segments without gaps; nearest-keyframe requires explicit before/after choice (default before with delta shown) and never includes outside content without UI warning; audio respects exact kept boundary and encoder delay; every early throw disposes `Input` and discards scratch; decoder configs handled per source or forced to one consistent encode.
11 more entries in the full changelog.
Tests
- Added deterministic Clock tests for negative-rate ceil semantics, range start/end boundaries, single-loop scheduling, zero clamping, successive J/L speeds and direction changes, and throttled `timeupdate`; exact reverse-audio sample, rate, envelope, cleanup, and boundary tests; shortcut and ownership tests; and Chromium coverage for the localized shuttle indicator and its 320px fit.