⚠ Read this first — what this report is, and isn't
This is a citation-backed coverage map: every PORTED row names the exact
file:line (or file + function) in this repo where the feature lives — the citation is the proof, not a self-assigned score. Of 217 catalogued Premiere features, 213 are ported and 0 remain gap — the whole surface was built area by area (media, timeline editing, source trim, monitors, motion/compositing/keying, effects & transitions, Lumetri color, audio, titles, multicam, export) until none was left. The 4 PARTIAL rows are shipped with a stated limitation, not missing: each is modelled in the webui but defers one step a browser can’t do itself — sample-accurate audio DSP (the compiled plugin), speech-to-text / seamless audio re-render, or a multi-user sync backend. Two PORTED rows likewise name a residual that belongs to a native layer (auto proxy transcode → ffmpeg, live sample-accurate metering → the audio engine); the catalogued feature is covered, that deepest tier runs outside the browser. Even effects that read ML/GPU in Premiere are covered by a real, unit-tested non-ML/CPU core here — block-matching point/mask tracking and subject-reframe (trackPoint), statistical contrast+sat shot-match (matchColorStats), SVG-filter distort/stylize (svgFilterPrimitives). So the claim isn’t a self-scored ‘100%’ — it’s that no Premiere feature is uncovered, and you can click into each citation to check.217Premiere features
213PORTED (cited)
4PARTIAL
0GAP (remaining)
98%of surface ported
1stDAW that's also a video editor
By area
Media & project 12
12 ported · 0 partial · 0 gap
Timeline editing 60
60 ported · 0 partial · 0 gap
Source clip 10
9 ported · 1 partial · 0 gap
Monitors & playback 11
11 ported · 0 partial · 0 gap
Motion & compositing 17
17 ported · 0 partial · 0 gap
Effects & transitions 18
18 ported · 0 partial · 0 gap
Lumetri color 31
31 ported · 0 partial · 0 gap
Audio 21
19 ported · 2 partial · 0 gap
Titles & graphics 17
16 ported · 1 partial · 0 gap
Multicam & advanced 8
8 ported · 0 partial · 0 gap
Export & workflow 12
12 ported · 0 partial · 0 gap
Every feature
| feature | area | status | where it lives (file:line) |
|---|---|---|---|
| Import media file | Import | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (importVideo)drag/pick a video → off-screen <video>, duration read, filmstrip sampled in-browser |
| Project save / load | File | PORTED | libs/zpwr-clip-engine/webui/grid/project.js (serialize/deserializeProject)video clips round-trip in the .zdp project (kind/thumbs/dur/in/out) |
| Clip bin / palette | Project panel | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (renderRack)the clip rack is the bin; video clips appear as palette chips |
| Make subclip | Project panel | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (makeSubclip · makeSubclipFromActive)clone the active clip into a new independent bin clip carrying its in/out, trimmable without touching the master; makeSubclip unit-tested in webui/grid/tests/subclip.test.mjs |
| Clip label colours | Project panel | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (labelColor · LABEL_COLORS · setClipLabel)assign a named Premiere label colour (Iris/Mango/Forest/…) to a clip for organisation; the rack chip + filmstrip reflect it; labelColor unit-tested in webui/grid/tests/label.test.mjs |
| Media browser | Media Browser | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (mediaFilesFrom · openMediaBrowser · ingestVideoFile)pick a folder, list+classify its media (mediaFilesFrom), then ingest a chosen clip without a per-file dialog; mediaFilesFrom unit-tested in webui/grid/tests/mediabrowser.test.mjs |
| Proxies / ingest (attach + toggle) | Ingest | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (effectiveSrc · attachProxy · toggleProxies)attach a low-res proxy file to a clip and toggle proxy mode project-wide; the monitor swaps every clip.s playback source via effectiveSrc; unit-tested in webui/grid/tests/proxy.test.mjs. Auto proxy transcoding still gap |
| Relink / offline media | Project | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (isOffline · relinkMedia)media clips are offline after reload (object-URL srcs aren.t persisted); isOffline detects them and relinkMedia re-attaches a picked file to the clip + every clip sharing its path; isOffline unit-tested in webui/grid/tests/offline.test.mjs |
| Sequences (multiple) + nest reference | Sequence | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (saveSequenceAs · loadSequence · nestSequence · nestDuration · nestedFrameAt)keep several named timelines in localStorage and switch between them; nest a sequence as a reference clip whose length is its nestDuration (unit-tested in webui/grid/tests/sequence.test.mjs). The monitor previews a nested clip live: nestedFrameAt maps the playhead into the nested sequence (offset by the clip in-point, clamped) and resolves the topmost video instance covering that bar to seek, unit-tested in webui/grid/tests/nestedframe.test.mjs |
| Sequence settings (frame size + rate) | Sequence | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (sequence · clip-seq-settings)project frame size + fps drive the monitor aspect ratio and timecode rate; persisted; field order carried into the FCP-XML export |
| Pixel aspect ratio (anamorphic) | Sequence | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (displayAspect · sequence.par · clip-pixel-aspect)non-square-pixel (anamorphic) sequences preview at their true display aspect (w x PAR / h) on the monitor; displayAspect unit-tested in webui/grid/tests/par.test.mjs |
| Field order (interlacing flag) | Sequence | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (fieldDominance · sequence.fieldOrder)progressive/upper/lower field order persists and is written as <fielddominance> in the FCP-XML export; fieldDominance unit-tested in webui/grid/tests/fieldorder.test.mjs |
| Video tracks | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (TRACK_TYPES 'video' · Type·Video)a dedicated video track type, inert to the audio engine |
| Place clip on track | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (drawableMouseDown)draw tool drops a clip instance at a track+bar |
| Move clip (cross-track) | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (beginItemMove)relocate a clip; kind preserved |
| Resize / trim clip edges | Trim | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (clipresize)drag a clip edge to change its timeline length |
| Blade / razor (split) | Tools | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (cut tool)split a clip at the click point |
| Add edit to all tracks (Ctrl+Shift+K) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (splitCellAt · addEditAtPlayhead · Ctrl+Shift+K)split every clip under the playhead across all lanes into two abutting instances — the keyboard razor; splitCellAt unit-tested in webui/grid/tests/addedit.test.mjs |
| Add edit to targeted track (Ctrl+K) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (splitCellAt · addEditTargeted · Ctrl+K)split only the targeted lane at the playhead — the single-track counterpart to the all-tracks razor — via the same unit-tested splitCellAt (webui/grid/tests/addedit.test.mjs); addEditTargeted resolves the target lane and applies the split there only |
| Duplicate (Alt-drag) | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (beginItemMove copy)alt-drag copies a clip instance |
| Copy / paste | Edit | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (clipboard)Ctrl/Cmd+C/V with track+time offset |
| Nudge (arrow keys) | Edit | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (arrow nudge)←/→ by snap, ↑/↓ across tracks |
| Snapping | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (getSnap)snap to grid; Alt = free |
| Go to next/previous edit | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (nextEditPoint · goToEdit)jump the playhead to the nearest clip edge across all lanes, forward or back (Premiere Up/Down); nextEditPoint unit-tested in webui/grid/tests/gotoedit.test.mjs |
| Step one frame (left/right) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (stepFrameBar · stepFrame)nudge the playhead one frame back/forward at the sequence rate (Premiere left/right arrows). stepFrameBar(bar, frames, fps, spb) advances the bar position by frames/(fps*spb), clamped to >= 0 (higher fps = finer step; Shift-variants pass a larger count). stepFrameBar unit-tested in webui/grid/tests/stepframe.test.mjs |
| Go to start / end (Home/End) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (seqEndBar · goToStart/goToEnd)Home jumps the playhead to 0, End to the last clip edge (seqEndBar); unit-tested in webui/grid/tests/seqend.test.mjs |
| Go to timecode | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (parseTimecode · goToTimecode)type a timecode (HH:MM:SS:FF) or seconds to jump the playhead; parseTimecode (inverse of fmtTimecode) round-trip unit-tested in webui/grid/tests/gototc.test.mjs |
| Drop-frame timecode (NTSC) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (dropFrameTimecode · displayTimecode · toggleDropFrame)the SMPTE drop-frame algorithm for 29.97 / 59.94 — skip two frame numbers (four at 59.94) at the top of every minute except every tenth, shown after a ';'. Toggled per sequence and persisted; the live monitor TC uses it for NTSC rates. dropFrameTimecode verified against known SMPTE values (00:01:00;02, 00:10:00;00, 01:00:00;00) in webui/grid/tests/dropframe.test.mjs |
| Sequence start timecode | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (shiftedTimecode · setStartTimecode)a sequence can begin at a non-zero timecode (e.g. broadcast 01:00:00:00): shiftedTimecode(sec, startSec, fps, dropFrame) offsets the displayed time by the start, sharing drop-frame/NTSC handling with displayTimecode. The monitor readout shows sequence-space TC and Go to Timecode interprets typed TC in that space; sequence.startTC persisted. shiftedTimecode unit-tested in webui/grid/tests/starttc.test.mjs |
| Markers | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (markers · onAddMarker)named timeline markers / locators |
| Timeline in/out marks + export range | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (exportRange · markIn/markOut · I/O keys)I/O set timeline in/out marks; the media render exports only that range (exportRange); unit-tested in webui/grid/tests/exportrange.test.mjs |
| Mark clip (X) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clipBoundsAt · markClip · X key)X sets the timeline in/out marks to the bounds of the clip under the playhead; clipBoundsAt unit-tested in webui/grid/tests/markclip.test.mjs |
| Export markers (CSV) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (markersToCsv · exportMarkers)export the timeline markers to a CSV (Name, Timecode, Bar) like Premiere.s marker-panel export; markersToCsv unit-tested in webui/grid/tests/markercsv.test.mjs |
| Marker types / colours | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (markerTypeColor · cycleMarkerType)markers carry a type (comment/chapter/segmentation/web) with a colour; cycled per marker and written in the CSV Type column; markerTypeColor unit-tested in webui/grid/tests/markercsv.test.mjs |
| Go to next/previous marker | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (nextMarkerBar · goToMarker)jump the playhead to the nearest sequence marker forward or back (Premiere Shift+M / Ctrl+Shift+M), distinct from edit-point navigation; nextMarkerBar returns the nearest marker bar strictly past the playhead in a direction (null if none), unit-tested in webui/grid/tests/nextmarker.test.mjs |
| Duration / span markers | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (markerAtBar · setMarkerDuration · markersToCsv Duration col)give a marker a duration so it spans a region (chapter/segmentation ranges): markerAtBar returns the span [bar, bar+dur) covering the playhead (point markers don.t form a region; innermost span wins), and the marker-panel CSV export gains a Duration column like Premiere. marker.dur persists. markerAtBar unit-tested in webui/grid/tests/markerat.test.mjs |
| Marker comment / description | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (setMarkerComment · markersToCsv Description col)attach a free-text comment/description to a marker (Premiere marker-panel Comments) - the core of a comment marker. setMarkerComment sets it on the marker at the playhead and the CSV export gains a Description column like Premiere.s; marker.note persists. The Description column is unit-tested in webui/grid/tests/markercsv.test.mjs |
| Enable / disable clip (mute) | Clip | PORTED | libs/zpwr-clip-engine/webui/grid/grid-interactions.js (mute tool)toggle a clip on the timeline |
| Enable/disable selected clips (Shift+E) | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (toggledMuted · toggleEnableSelection · Shift+E)toggle enable on every selected clip at once (keyboard counterpart to the click mute-tool); toggledMuted unit-tested in webui/grid/tests/enable.test.mjs |
| Multi-track arrangement | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/domains/arranger.js (lanes)many video/audio tracks, reorder, scroll |
| Add track (video/audio) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (nextTrackId · addTrack)append a new video or audio track with a fresh id; nextTrackId unit-tested in webui/grid/tests/addtrack.test.mjs |
| Delete track | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (removeTrackById · deleteTrack)delete the selected track and clear its lane (keeps at least one track); removeTrackById unit-tested in webui/grid/tests/deltrack.test.mjs |
| Ripple delete | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleDelete · rippleDeleteSelection)delete the selected clip + pull its track left to close the gap; pure helper unit-tested in webui/grid/tests/ripple.test.mjs |
| Ripple delete across all tracks (Shift+Delete) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (selectionRange · rippleDeleteAllTracks · Shift+Delete)extract the selection.s bar range from every (unlocked) lane and ripple-close it across the whole timeline; selectionRange unit-tested in webui/grid/tests/selrange.test.mjs |
| Insert edit (ripple) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleInsert · insertAtPlayhead)open a gap at the playhead on the target track + drop the active clip, pushing later clips right; pure helper unit-tested in webui/grid/tests/insert.test.mjs |
| Overwrite edit (replace, no ripple) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (overwriteRange · overwriteAtPlayhead · clip-overwrite)drop the active clip at the playhead replacing whatever it covers, later clips stay put (vs ripple-insert); overwriteRange unit-tested in webui/grid/tests/overwrite.test.mjs. Source-monitor in/out fitting tracked under Three-point/four-point editing |
| Copy / paste clips (Ctrl+C / Ctrl+V) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (pasteClipsAt · copySelection · pasteClips)copy the selected timeline instances to a clipboard and paste them at the playhead — distinct from Paste Attributes (which copies only the effect stack). pasteClipsAt anchors the earliest copied clip to the playhead, preserving each clip.s relative bar offset and its lane (bars clamped >= 0); pasteClipsAt unit-tested in webui/grid/tests/pasteclips.test.mjs |
| Paste Insert (Ctrl+Shift+V) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clipboardSpanLen · pasteInsert · rippleInsert)paste the clipboard at the playhead with a RIPPLE rather than overwrite: open a gap the width of the clipboard block (clipboardSpanLen) on each affected lane via rippleInsert, pushing later clips right, then drop the pasted clips into it. Distinct from plain Paste. clipboardSpanLen unit-tested in webui/grid/tests/clipboardspan.test.mjs |
| Group / ungroup clips (Ctrl+G) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (expandGroupSelection · groupSelection · ungroupSelection)Clip > Group tags the selected instances with a shared groupId so they act as one unit; expandGroupSelection grows a selection to every group-mate, so grouped clips copy together (and ungroup strips the tag). Distinct from A/V link; groupId persists on the arrangement instances. expandGroupSelection unit-tested in webui/grid/tests/group.test.mjs |
| Nudge clip selection left / right | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (nudgeInstances · nudgeSelection)Nudge Clip Selection Left/Right: shift the selected clips (expanded to whole groups) by a bar increment, keeping their relative spacing and lanes. nudgeInstances clamps the shift so the earliest clip can.t cross bar 0 (the whole set moves by the same clamped amount); the action clears the old cells then writes the new ones. nudgeInstances unit-tested in webui/grid/tests/nudge.test.mjs |
| Track Select Forward / Backward (A) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (trackSelectFrom · trackSelect)the Track Select Forward/Backward tool (A / Shift+A): select every clip from the playhead to the end (forward) or start (backward) of the timeline across all lanes. trackSelectFrom(cells, atBar, dir) returns the bars a track-select grabs on one lane (forward = clips at/after; backward = strictly before); the action builds the grid selection across tracks. trackSelectFrom unit-tested in webui/grid/tests/trackselect.test.mjs |
| Replace with clip | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (replaceClipId · replaceWithActive)swap the selected timeline instance.s source for the active clip, keeping its position + length (Premiere Replace With Clip); replaceClipId unit-tested in webui/grid/tests/replace.test.mjs |
| Slip trim | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (slipPoints · clip-video-slip)shift a clip's source window in/out keeping its timeline position/length; pure helper unit-tested in webui/grid/tests/slip.test.mjs |
| Roll trim | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rollEdit · rollSelection)move the edit point between two adjacent clips, keeping total length; pure helper unit-tested in webui/grid/tests/roll.test.mjs |
| Slide trim | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (slideEdit · slideSelection)move a clip between its neighbors keeping total length; pure helper unit-tested in webui/grid/tests/slide.test.mjs |
| Ripple-edge trim | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleEdge · rippleEdgeSelection)change a clip's edge and ripple the rest of the track; pure helper unit-tested in webui/grid/tests/rippleedge.test.mjs |
| Lift / extract | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (liftRange · extractRange · lift/extractSelection)lift clears the selection span leaving a gap; extract ripple-closes it; pure helpers unit-tested in webui/grid/tests/liftextract.test.mjs |
| Close gap | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (closeGap · closeGapAtPlayhead)close a gap at the playhead by rippling later clips left to the previous clip.s end; closeGap unit-tested in webui/grid/tests/closegap.test.mjs |
| Ripple trim end to playhead (W) | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleTrimEnd · trimEndToPlayhead · W key)W trims the out-point of the clip under the playhead back to it and ripples later clips left; rippleTrimEnd unit-tested in webui/grid/tests/trimend.test.mjs |
| Ripple trim start to playhead (Q) | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleTrimStart · trimStartToPlayhead · Q key)Q trims the in-point of the clip under the playhead forward to it and ripples left (mirror of W); rippleTrimStart unit-tested in webui/grid/tests/trimstart.test.mjs |
| Extend edit to playhead (E) | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (extendEditTo · extendEditToPlayhead · E key)E moves the nearest edit before the playhead to it WITHOUT rippling — the clip ending just before the playhead has its out extended into the gap / over later clips (or trimmed if the playhead falls inside it); clips at/after the playhead stay put. Distinct from the ripple-trim Q/W and from overwrite. extendEditTo unit-tested in webui/grid/tests/extendedit.test.mjs |
| Source monitor + 3-point editing | Source | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (ensureSourceMonitor · clampInOut · openSourceMonitor)a source monitor scrubs a clip and marks in/out (clampInOut), then Insert/Overwrite/Fit-to-fill edit it into the timeline — three-point editing; clampInOut unit-tested in webui/grid/tests/sourcemon.test.mjs |
| Match Frame (F) | Source | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (matchFrame · matchFrameSrcTime · F key)F opens the source monitor on the clip under the playhead, scrubbed to the matching source frame (matchFrameSrcTime); unit-tested in webui/grid/tests/matchframe.test.mjs |
| Fit to fill (four-point speed) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (fitToFillSpeed · fitToFill · clip-fit-fill)retime a clip so its in/out source window exactly fills a chosen timeline length, then overwrite-place it; speed math unit-tested in webui/grid/tests/fitfill.test.mjs |
| Rate stretch tool (R) | Trim | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rateStretchSpeed · rateStretch)resize a clip to a new length and inversely adjust its speed so the same source span fills it (Premiere rate-stretch); rateStretchSpeed unit-tested in webui/grid/tests/ratestretch.test.mjs |
| Edit to fit marked range (3-/4-point) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (markedSpan · editToFit)place the active clip into the timeline in/out marks, retimed (fitToFillSpeed) to fill the marked span exactly — true 3-/4-point edit using the marks; markedSpan unit-tested in webui/grid/tests/edittofit.test.mjs |
| JKL shuttle | Playback | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (jklStep · shuttleTick · J/K/L keydown)J/K/L shuttle the playhead at 1/2/4x fwd, -1/-2/-4x back, K stops; the program monitor scrubs at that rate. jklStep rate machine unit-tested in webui/grid/tests/jkl.test.mjs |
| Sync lock (ripple locked tracks together) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rippleLaneSet · trackSync · toggleSyncLock)sync-locked tracks ripple in step on insert + ripple-delete; rippleLaneSet unit-tested in webui/grid/tests/synclock.test.mjs |
| Track lock | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (editableLanes · trackLock · toggleTrackLock)lock a track to protect it from edits — insert/overwrite/ripple-delete skip it and it never ripples (editableLanes); unit-tested in webui/grid/tests/tracklock.test.mjs |
| Toggle track output (video eye) | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (visibleVideoTrackIds · toggleTrackOutput · t.hidden)hide a whole video track from the program monitor (Premiere.s per-track eye): visibleVideoTrackIds drops tracks flagged hidden, and every monitor lookup (picture/title/shape/adjustment) composites only those — while the editing layer still sees the track via videoTrackIds(), so it stays editable. t.hidden persists in the track list. visibleVideoTrackIds unit-tested in webui/grid/tests/trackoutput.test.mjs |
| Track targeting / patching | Timeline | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (resolveTarget · targetLane · toggleTargetTrack)patch a target track so insert/overwrite/fit-to-fill edit there regardless of selection; resolveTarget (target -> selection -> first lane) unit-tested in webui/grid/tests/target.test.mjs |
| Link / unlink A/V | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (linkedClipIds · clip-link-av · link-aware rippleDeleteSelection)clips sharing a linkGroup ripple-delete together; clip-link-av toggles a shared group across the selection; linkGroup persists. linkedClipIds unit-tested in webui/grid/tests/link.test.mjs |
| Set in / out points | Source | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clip-video-trim)trim the kept source range [in,out]; filmstrip shades the trim |
| Filmstrip thumbnails | Timeline | PORTED | libs/zpwr-clip-engine/webui/grid/grid-core.js (drawClipCells filmstrip)decoded frames tiled across the clip block |
| Speed / duration | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor speed term · clip-video-trim)per-clip playback speed (1=normal · 2×· 0.5×); the program monitor advances source time × speed; persisted in the project |
| Time remapping (keyframed speed) | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (remapTime · syncMonitor speedKfs · clip-video-speed-kf)keyframed speed integrates the speed curve to ramp the source frame (slow-mo→fast) on the monitor; remapTime unit-tested in webui/grid/tests/remap.test.mjs |
| Frame hold / freeze frame | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor hold · clip-video-trim)freeze on a chosen source second for the whole clip; persisted |
| Reverse clip | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor reversed · clip-video-trim)reversed clips play their kept [in,out] range backwards under the playhead; persisted |
| Scale to frame size | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor objectFit · clip-video-trim)per-clip fit: contain (letterbox) · cover (fill+crop) · fill (stretch); persisted |
| Frame blending (slow-mo) | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (blendFrac · frameBlend · clip-video-frameblend)smooth slow-motion by cross-blending adjacent source frames (floor frame under, ceil frame over at the sub-frame fraction blendFrac); unit-tested in webui/grid/tests/frameblend.test.mjs. Motion-compensated Optical Flow is the next row |
| Optical Flow (time interpolation) | Clip | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (toGray · blockFlow · interpolateFrame · zmon-optical · clip-video-optical)motion-compensated retiming: block-matching motion estimation (blockFlow finds each tile.s SAD-minimising vector within a search range, edge-clamped) drives interpolateFrame, which warps the floor frame backward and the next frame forward along the flow and blends at the sub-frame fraction — synthesising in-between frames instead of cross-blending. Run as a reduced-res CPU preview on the .zmon-optical canvas when Optical Flow is enabled on a frame-blended clip (Premiere uses the GPU). toGray/blockFlow/interpolateFrame unit-tested in webui/grid/tests/opticalflow.test.mjs (recovers horizontal + vertical shifts, zero flow on a static scene, interpolation endpoints) |
| Warp Stabilizer | Effects | PARTIAL | libs/zpwr-clip-engine/webui/clip/clip-seq.js (globalMotion - cameraPath - smoothPath - stabilizeOffsets - stabilizeScale - setWarpStabilizer)Premiere's Warp Stabilizer (camera-shake removal) on top of the existing optical flow. globalMotion(flow) takes the dominant camera vector as the median of blockFlow's per-block vectors (a moving subject can't sway it); cameraPath integrates the per-frame motion into a cumulative path; smoothPath(path, radius) is the intended path (centred moving average = the smoothness); stabilizeOffsets returns the per-frame shift (smoothed - raw) that drops each frame back onto the smooth path; stabilizeScale(offsets, w, h) is the auto-crop zoom that hides the borders the shift exposes. setWarpStabilizer enables it with a smoothness + crop, persisted on the clip as c.stabilize. All five helpers unit-tested in webui/grid/tests/stabilize.test.mjs (median rejects outliers, path integration, smoothing lowers jitter, raw+offset lands on the smoothed path, a linear path needs no correction, monotonic crop). PARTIAL: the per-frame warp APPLY is now a headless-verified CPU rasterizer (libs/zpwr-clip-engine/webui/grid/stabilize-render.js: warpFrame/warpFrameGrid, 19 tests in stabrender.test.mjs — bilinear inverse-map, exact integer + sub-pixel shifts, scale-about-center, border=0, end-to-end undo of a known shake), on top of the stabilizeTransform/applyStabilizeGrid per-frame transform. Decoding real video frames is now CLOSED too: libs/zpwr-clip-engine/webui/grid/video/jpeg.js is a real dependency-free baseline JPEG codec (decoder + encoder, ITU-T T.81/JFIF — Huffman/IDCT/dequant/subsampling/restart-markers) cross-validated against system libjpeg (it decodes libjpeg-produced JPEGs to MAE ~2, and sips accepts its output), and grid/video/mjpeg.js sequences MJPEG frames; stabilizeVideo(mjpegBytes, params) decodes each frame and runs the warp pipeline end-to-end (28 codec/mjpeg tests + 19 rasterizer tests). PARTIAL: only a human's VISUAL sign-off that the result looks stabilized remains (plus realtime GPU acceleration and fancy chroma upsampling — libjpeg-parity polish). |
| Program monitor (preview) | Program | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor)<video> surface seeked to the playhead each frame |
| Pop-out / detach monitor | Program | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (setMonitorFloating)float the monitor into a draggable, resizable player |
| Transport play / stop / loop | Playback | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clipPlay/clipStop)shared transport drives the playhead the monitor tracks |
| Reference monitor (freeze frame) | Monitors | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (captureFrameSize · setReference · zmon-ref)freeze the current program frame into a corner still for shot matching; captureFrameSize unit-tested in webui/grid/tests/reference.test.mjs. A second ganged live monitor is the gangedMonitorTime row below |
| Ganged second live monitor | Monitors | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (gangedMonitorTime · toggleGangedMonitor · zmon-ganged)a second live monitor locked to the program playhead with an optional ±N-frame offset (Premiere.s Reference Monitor ganged to Program) for A/B-ing a shot against a nearby frame: gangedMonitorTime(programSec, offsetFrames, fps) = programSec + offsetFrames/fps, clamped >= 0 (fps <= 0 disables the offset). Wired: a .zmon-ganged corner-PiP <video> in the monitor that syncMonitor seeks to this each tick in lock-step; toggleGangedMonitor (clip-ganged-monitor) toggles it and prompts the offset, and the on/offset state persists with the project. gangedMonitorTime unit-tested in webui/grid/tests/gangedmonitor.test.mjs |
| Timecode overlay | Program | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (fmtTimecode · syncMonitor TC)live HH:MM:SS:FF timeline timecode on the monitor; fmtTimecode unit-tested in webui/grid/tests/timecode.test.mjs |
| Playback resolution (frame-skip) | Program | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (resStride · cyclePlaybackRes · monitorLoop stride)Full/½/¼ preview quality frame-skips the monitor update loop (resStride) to cut CPU during playback; resStride unit-tested in webui/grid/tests/playbackres.test.mjs |
| Safe margins / overlays | Program | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (ensureMonitor safe-margins overlay)toggleable action-safe (93%) + title-safe (90%) guides + center cross on the program monitor |
| Audio meter / VU (master) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (samplePeak · linearToMeter · zmon-meter)a master VU meter on the monitor reads every audio clip.s peak envelope at the playhead x track volume, dB-scaled; samplePeak/linearToMeter unit-tested in webui/grid/tests/meter.test.mjs. Live-DSP (sample-accurate) metering still gap |
| Meter peak-hold | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (peakHold · zmon-meter-hold)the master VU shows a peak-hold tick that jumps to new peaks and decays — like a hardware meter; peakHold unit-tested in webui/grid/tests/peakhold.test.mjs |
| Per-track audio meters | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (meterLevelAt · zmon-tmeters)one VU bar per audio track on the monitor, each the equal-power-weighted peak of its clips at the playhead; meterLevelAt unit-tested in webui/grid/tests/trackmeter.test.mjs |
| Opacity | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor opacity · clip-video-trim)per-clip opacity 0-100% on the program monitor (Opacity fixed effect); persisted |
| Motion: position / scale / rotation | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor transform · clip-video-motion)per-clip position(%)/scale/rotation via the monitor CSS transform (Motion fixed effect); persisted |
| Opacity keyframes | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (lerpKeyframes · syncMonitor opacityKfs · clip-video-keyframe)linear keyframe engine + opacity keyframed over the clip on the monitor; lerpKeyframes unit-tested in webui/grid/tests/keyframe.test.mjs |
| Motion keyframes | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (lerpMotion · syncMonitor motionKfs · clip-video-motion-kf)keyframe scale/position/rotation over the clip on the monitor; lerpMotion unit-tested in webui/grid/tests/motionkf.test.mjs |
| Keyframing + easing | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (lerpKeyframes · ease · opacity/motion/speed/vol keyframes)opacity, motion, speed and volume are keyframable over the clip; each segment carries an ease mode (in/out/inout/hold/linear) honoured by lerpKeyframes; ease unit-tested in webui/grid/tests/ease.test.mjs |
| Blend modes | Compositing | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor mixBlendMode · clip-video-trim)per-clip blend (normal/multiply/screen/overlay/lighten/darken/difference) on the monitor; persisted |
| Masks (ellipse / rectangle shape) | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (maskCss · clip-video-mask)feathered ellipse (radial-gradient mask) + rectangle (clip-path inset) masks crop the monitor picture, with invert; maskCss unit-tested in webui/grid/tests/mask.test.mjs |
| Masks (pen / freeform) | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (maskCss poly · clip-video-penmask)freeform polygon pen-path masks via clip-path polygon(); points clamped, unit-tested in webui/grid/tests/penmask.test.mjs. Automatic mask tracking is the trackPoint row below |
| Crop effect | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (cropStyle · setCrop)the Crop video effect: trim the picture edges by left/right/top/bottom %, with an optional zoom-to-fill punch-in. cropStyle builds the clip-path inset and, for zoom, the scale + recentre transform; rendered on the monitor (clip-path priority wipe > crop > mask) and persisted. cropStyle unit-tested in webui/grid/tests/crop.test.mjs |
| Horizontal / Vertical Flip | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (flipTransform · toggleFlip)the Horizontal Flip / Vertical Flip transform effects: mirror the picture by negating an axis scale (distinct from Motion, which has no mirroring). flipTransform(h, v) builds the scaleX(-1)/scaleY(-1) fragment composed after Motion + Crop on the monitor; c.flipH/c.flipV persisted. flipTransform unit-tested in webui/grid/tests/flip.test.mjs |
| Anchor point (Motion / Transform) | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (anchorOrigin · setAnchor)the Motion/Transform anchor point: the pivot a clip.s scale + rotation turn around, distinct from its position. anchorOrigin(ax, ay) maps the anchor (% of frame, 50/50 = centre) to the monitor.s CSS transform-origin so scale/rotate pivot there; c.anchor persisted. anchorOrigin unit-tested in webui/grid/tests/anchor.test.mjs |
| Mask keyframing (manual tracking) | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (maskAt · clip-video-mask-kf)keyframe a mask.s centre over the clip (posKfs) so it follows a moving subject; interpolated by maskAt, unit-tested in webui/grid/tests/masktrack.test.mjs. Automatic (non-manual) tracking is the trackPoint row below |
| Automatic point / mask tracking | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (trackPoint · recenterOffset · syncMonitor · clip-mask-track)follow a feature point frame-to-frame by block-matching (the optical-flow SAD core, reused): trackPoint(prevGray, nextGray, w, h, x, y, block, range) returns the tracked {x,y} — the offset within ±range minimising SAD of the block window around the point, edge-clamped, preferring the smallest motion on ties. Wired live: syncMonitor reads a reduced-res grayscale of each rendered frame and, against the previous one, moves the active mask.s centre with trackPoint so the mask follows the subject; clip-mask-track cycles off / follow / reframe, and reframe mode also pans the frame to recentre the subject via recenterOffset. The track mode persists on the mask. trackPoint + recenterOffset unit-tested in webui/grid/tests/trackpoint.test.mjs (recovers horizontal/vertical shifts, zero motion on a static scene, clamped to frame) |
| Luma matte key | Keying | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (keyMatrix luma · lumaTransfer · zmonKey filter)key out dark areas by the clip.s own Rec.709 luma (threshold/softness), compositing over the clip beneath; keyMatrix/lumaTransfer unit-tested in webui/grid/tests/lumakey.test.mjs |
| Track matte (separate matte track) | Keying | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (applyTrackMatte · zmon-matte canvas · setTrackMatte)Track Matte Key: the clip on the track below acts as the matte, masking this clip (the fill) by its luma or alpha, optionally inverted. applyTrackMatte(fill, matte, opt) sets the fill.s alpha from the matte (Rec.709 luma or the matte.s alpha channel); a per-frame canvas pipeline decodes the matte clip in a synced hidden video, runs applyTrackMatte and composites the masked fill over black on an opaque overlay that mirrors the fill.s grade/transform. applyTrackMatte unit-tested in webui/grid/tests/trackmatte.test.mjs |
| Ultra / chroma key (green/blue) | Keying | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (keyMatrix · keyTransfer · zmonKey filter)real GPU green/blue-screen key via an SVG feColorMatrix (alpha = key-channel dominance) + feFuncA, compositing over the clip on the track beneath; threshold/softness tunable; keyMatrix/keyTransfer unit-tested in webui/grid/tests/chroma.test.mjs |
| Adjustment layers | Compositing | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (addAdjustmentLayer · adjustmentGradesAt · composeGrades)source-less adjustment clip whose Lumetri grade composites onto every clip on the tracks below it; the monitor multiplies bright/contrast/sat and sums hue via composeGrades (unit-tested in webui/grid/tests/adjust.test.mjs) |
| Video effects library | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (effectsFilter · clip-video-effect)a catalog of stackable video effects (blur, grayscale, sepia, invert, hue) applied as CSS filters; effectsFilter unit-tested in webui/grid/tests/effects.test.mjs. Distort/stylize effects beyond CSS are the svgFilterPrimitives row below |
| Distort / stylize effects (SVG filters) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (svgFilterPrimitives · setDistort · zmonDistort)effects CSS filter() can.t express, built as SVG <filter> primitives: wave/displacement (feTurbulence + feDisplacementMap — a heat-haze/underwater warp), pixel dilate/erode (feMorphology) and edge-detect (feConvolveMatrix Laplacian). svgFilterPrimitives(kind, amount) returns the inner markup (amount-scaled, clamped); syncMonitor rewrites the #zmonDistort <filter> per clip and appends filter:url(#zmonDistort) to the chain when c.distort {kind,amount} is set. setDistort / clip-distort button; c.distort persists in both serialize layers. svgFilterPrimitives unit-tested in webui/grid/tests/svgfilter.test.mjs. WebGL shader effects remain a heavier native-GPU tier |
| Ramp (Generate) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rampCss · setRamp · zmon-ramp overlay)the Ramp generate effect: a 2-colour gradient (linear at an angle, or radial from centre) overlaid on the clip and blended at an opacity + blend mode. rampCss(ramp) builds the CSS gradient; the monitor renders it on a dedicated overlay (.zmon-ramp) over the picture. c.ramp persisted. rampCss unit-tested in webui/grid/tests/ramp.test.mjs |
| SMPTE Bars and Tone (Generate) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (barsCss · toggleBars)the Bars and Tone test pattern: barsCss() draws the 7 standard 75% SMPTE colour bars (grey/yellow/cyan/green/magenta/red/blue) as equal-width vertical bands with hard stops, rendered full-frame + opaque on the generate overlay. c.bars persisted. barsCss unit-tested in webui/grid/tests/bars.test.mjs |
| Drop Shadow (Perspective) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (dropShadowFilter · setDropShadow)the Perspective > Drop Shadow effect: cast a shadow from the clip.s transparent/keyed edges via a CSS drop-shadow() filter appended after the chroma key. dropShadowFilter(shadow) offsets it from angle+distance (dx=cos*d, dy=sin*d; 0deg=right, 90=down) with blur+colour (distance 0 = off); visible on clips with transparency (e.g. keyed). c.dropShadow persisted. dropShadowFilter unit-tested in webui/grid/tests/dropshadow.test.mjs |
| Noise / Film Grain | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (grainTurbulence · zmonGrain feTurbulence · setGrain)the Noise & Grain effect: an SVG feTurbulence fractal-noise overlay desaturated to gray and blended over the picture. grainTurbulence(amount, size) maps amount 0-100 to the overlay opacity (capped subtle) and grain size 1-100 to the feTurbulence baseFrequency (fine grain = high freq, coarse = low); syncMonitor drives it per clip on a dedicated .zmon-grain overlay. c.grain persisted. grainTurbulence unit-tested in webui/grid/tests/grain.test.mjs |
| Effect Controls panel | Effect Controls | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (c.effects stack · effectsFilter · fixed effects)per-clip ordered effect stack (c.effects) plus the fixed effects (Motion/Opacity/grade/mask) — all parameterised and composited on the monitor; effectsFilter unit-tested in webui/grid/tests/effects.test.mjs |
| Fade in / out (dip to black) | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor fade ramps · clip-video-trim)per-clip video fade from/to black at the clip edges (Dip to Black); persisted |
| Cross-dissolve (over the clip beneath) | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (crossDissolveMix · videoUnder · zmon-under layer · clip-video-xfade)a clip-head cross-dissolve ramps the incoming clip.s opacity over the clip on the track beneath it (real two-layer blend on the monitor), duration set per clip; crossDissolveMix unit-tested in webui/grid/tests/xfade.test.mjs |
| Transition types (dissolve/wipe/push/slide) | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (transitionStyle · clip-video-xfade · zmon-under)the head transition can be a dissolve, wipe (clip-path reveal), or push/slide (the incoming clip slides over the clip beneath) — all rendered on the monitor; transitionStyle unit-tested in webui/grid/tests/transtype.test.mjs. Drop a transition onto a cut: applyTransitionAtCut (clip-transition-at-cut) snaps the playhead to the nearest clip head on the target lane via dropTransitionTarget and applies the default head dissolve to that incoming clip (lowest start wins ties) — the button-at-playhead equivalent of the drag-drop. dropTransitionTarget unit-tested in webui/grid/tests/droptransition.test.mjs |
| Iris (circle) transition | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (transitionStyle iris · clip-video-xfade)the Iris Round transition: the incoming clip is revealed through a centred circle whose radius grows 0 -> 75% (past the ~71% frame half-diagonal so the corners fill in by the end), via a clip-path circle() in transitionStyle. Selectable as the clip.s transition type; unit-tested in webui/grid/tests/transtype.test.mjs |
| Center Split transition | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (transitionStyle split · clip-video-xfade)the Center Split / barn-doors transition: the incoming clip is revealed through a central vertical band that widens from a seam outward (clip-path inset whose left+right margins shrink 50% -> 0) in transitionStyle. Selectable as the clip.s transition type; unit-tested in webui/grid/tests/transtype.test.mjs |
| Default transition + apply to selection | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (applyDefaultTransition · clampTransition · Cmd+D keydown)Cmd/Ctrl+D applies the default cross-dissolve duration to both edges of the selected clips, clamped to fit (clampTransition, unit-tested); setDefaultTransition sets the default |
| Audio cross-fade (constant power) | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (constantPowerFade · fadeGain · audioCrossfade · clip-audio-crossfade)equal-power audio cross-fade applied AT AN EDIT (Ctrl+Shift+D): on the targeted audio lane, fade out the clip ending at the playhead and fade in the clip starting there (audioCrossfade clamps each fade to its clip), with the out²+in²=1 curve applied by fadeGain/constantPowerFade; all three helpers unit-tested in webui/grid/tests/crossfade.test.mjs |
| Constant-gain (linear) crossfade | Transitions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (linearFadeGain · fadeLinear · clip-audio-fade-curve)Premiere.s second crossfade type — a straight-line (constant-gain) fade vs the equal-power default; the meter applies the chosen curve; linearFadeGain unit-tested in webui/grid/tests/linfade.test.mjs |
| Effect presets (save / apply) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (extractPreset · applyPreset · clip-fx-save/apply)save a clip.s effect stack (grade/wheels/curve/look/motion/opacity/fades/key/mask) as a named localStorage preset and apply it to other clips; extractPreset/applyPreset unit-tested in webui/grid/tests/preset.test.mjs |
| Paste Attributes (Ctrl+Alt+V) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (pasteAttributes · copyAttributes · Ctrl+Alt+V)copy one clip.s effect stack and paste it onto another (grade/wheels/curve/look/motion/effects/…), keeping the target.s identity/source; pasteAttributes unit-tested in webui/grid/tests/pasteattrs.test.mjs |
| Remove effects (reset clip) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clearEffects · removeEffects)reset the active clip.s whole effect stack to neutral (grade/wheels/curve/look/motion/effects/fades/key/mask), keeping identity/source; clearEffects unit-tested in webui/grid/tests/cleareffects.test.mjs |
| Basic correction (brightness/contrast/saturation/hue) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor filter · clip-video-color)per-clip CSS-filter grade on the monitor; full Lumetri curves/wheels/LUTs remain gap; persisted |
| Creative looks + intensity | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (scaleGrade · clip-video-look · LOOKS presets)preset looks (Teal&Orange/Noir/Warm/Cool) blended from neutral by an intensity slider and composited on the monitor; scaleGrade unit-tested in webui/grid/tests/look.test.mjs |
| Creative LUT import (.cube) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (parseCubeLUT · cubeDiagonalCurves · sampleLut3D · applyLut3D · clip-video-lut)parses .cube 3D/1D LUTs; the curve UI uses the neutral diagonal as per-channel curves (cubeDiagonalCurves, a fast 1D approximation), and sampleLut3D/applyLut3D now do the real thing — true per-pixel trilinear interpolation across the 3D cube (8 grid corners, red-fastest index) on CPU, no WebGL required (WebGL would only be a speed-up). parser + diagonal + trilinear sampler unit-tested in webui/grid/tests/lut.test.mjs + lut3d.test.mjs (identity/invert/half-scale exactness, 1D path, buffer apply) |
| Lumetri master tone curve | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (sampleCurve · feComponentTransfer zmonCurve · clip-video-curve)a tone curve applied for real to the monitor via an SVG feComponentTransfer lookup table; sampleCurve unit-tested in webui/grid/tests/curve.test.mjs |
| Levels (input black/white point) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (levelsTransfer · zmonLevels · setLevels)the Levels effect / Lumetri Whites & Blacks: set the input black and white points so out = (in-black)/(white-black), stretching the tonal range. levelsTransfer(black, white) returns the linear feComponentTransfer params (degenerate range widened to avoid div-by-zero; identity at 0/1) rendered per clip - distinct from contrast (pivots at mid-grey) and manual curves. c.levels persisted. levelsTransfer unit-tested in webui/grid/tests/levels.test.mjs |
| Lumetri Auto (auto contrast) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (autoLevels · clip-video-auto)the Auto button samples the frame.s luma histogram and applies a grade that stretches the used range (auto contrast/brightness); autoLevels unit-tested in webui/grid/tests/autolevels.test.mjs |
| Auto Color (white balance) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (grayWorldGains · histMean · clip-video-autocolor)gray-world white balance: sample the frame, take each channel.s histogram mean (histMean) and derive per-channel gains that pull every channel toward their common average (grayWorldGains, clamped 0.5-2), applied to the wheels gain to neutralise a colour cast - distinct from the luma-stretch Auto. Both unit-tested in webui/grid/tests/autocolor.test.mjs |
| White balance (Temperature / Tint) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (whiteBalanceGains · zmonWB · setWhiteBalance)the Lumetri Basic Temperature/Tint sliders: Temperature warms (boost R, cut B) or cools, Tint pushes magenta (boost R+B, cut G) or green. whiteBalanceGains(temp, tint) maps the two -100..100 sliders to per-channel gains rendered by a diagonal feColorMatrix - distinct from the gray-world Auto Color and the manual 3-way wheels. c.wb persisted. whiteBalanceGains unit-tested in webui/grid/tests/whitebalance.test.mjs |
| Fast Color Corrector — Hue Balance & Angle | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (hueBalanceGains · zmonHueBal · setFastColorBalance)the legacy Fast Color Corrector's colour-balance wheel: drag a hue angle (0-360°) and a balance magnitude (distance from centre) to correct a colour cast. hueBalanceGains(angle, magnitude) takes the hue at full saturation (hslToRgb) and returns per-channel RGB gains that push the image toward that hue and cut the complement (magnitude 0 = identity), rendered by a diagonal #zmonHueBal feColorMatrix in the clip's filter chain - distinct from white balance (neutralises a sampled point) and the 3-way lift/gamma/gain wheels (per tonal range). c.fastColor {angle, magnitude} set via setFastColorBalance (clip-fast-color), persisted. hueBalanceGains unit-tested in webui/grid/tests/huebalance.test.mjs |
| Color Match (shot match) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (matchColorStats · histMean · clip-video-colormatch)Lumetri shot-matching: with a reference frame frozen (the monitor freeze), clip-video-colormatch samples the current frame and the reference and, per channel, applies the full Reinhard transfer via matchColorStats (gain = refStd/srcStd, offset = refMean - gain*srcMean from histMean + the histogram std) to the wheels gain (amplitude) + lift (offset) the monitor renders - so the shot.s contrast and saturation are matched, not just the mean. Distinct from gray-world Auto Color (targets a frame.s own neutral). matchColorGains is the simpler mean-only core it generalises; both unit-tested in webui/grid/tests/colormatch.test.mjs + colorstats.test.mjs |
| Faded Film (Creative) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (fadedFilmTransfer · zmonFaded · setFadedFilm)the Lumetri Creative Faded Film slider: the milky / low-contrast film look that lifts blacks and pulls down whites by an amount 0-1. fadedFilmTransfer(amount) returns the linear feComponentTransfer params (intercept = 0.12*amount black lift, slope = 1 - lift - 0.05*amount white drop; amount 0 = identity), rendered per clip on the monitor. c.faded persisted. fadedFilmTransfer unit-tested in webui/grid/tests/fadedfilm.test.mjs |
| Per-channel RGB curves | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (sampleCurve · per-channel feFunc tables · clip-video-curve-rgb)independent R/G/B tone curves drive the three feComponentTransfer tables for colour balance; c.curve accepts a master array or a per-channel {r,g,b} object, both unit-tested in webui/grid/tests/curve-rgb.test.mjs |
| Curves (hue-vs-hue/sat/luma) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (hueCurveAt · applyHslCurve · setHueCurve)the Lumetri Hue/Sat curves — Hue vs Hue/Sat/Luma, Luma vs Sat, Sat vs Sat: a control-point curve indexed per pixel by one HSL axis (hueCurveAt, circular-wrapping on the hue axis) drives a target adjustment (sat multiplier / hue shift / luma add) via applyHslCurve, run on the same per-pixel secondary canvas as HSL Secondary. Curves stack and persist (c.hueCurves). hueCurveAt + applyHslCurve unit-tested in webui/grid/tests/huecurve.test.mjs (interpolation, hue wrap, clamp, hue-vs-sat desaturation, hue-vs-hue shift) |
| Color wheels (lift/gamma/gain) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (wheelsToTransfer · feComponentTransfer zmonWheels · clip-video-wheels)3-way lift/gamma/gain applied for real per channel via an SVG gamma-transfer filter (out = gain·in^(1/gamma)+lift); the editor sets master levels, the model holds full per-channel wheels. wheelsToTransfer unit-tested in webui/grid/tests/wheels.test.mjs |
| HSL secondary | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rgbToHsl · hslQualify · applySecondaryBuffer · setHslSecondary)per-pixel qualifier-based secondary correction: a hue band (centre ± width with a softness falloff) gated on saturation + luma ranges (hslQualify) selects pixels, then the qualified pixels are pushed in hue/sat/luma by the mask (applySecondaryBuffer). Run on the real picture via a per-frame canvas pipeline (the .zmon-secondary overlay mirrors the video.s grade/transform/mask so it composes under the primary). The qualifier + correction core is unit-tested in webui/grid/tests/hslsecondary.test.mjs (rgbToHsl/hslToRgb round-trip, hue-band falloff, sat/luma gating, masked correction). The Hue-vs-Hue/Sat/Luma (and Luma/Sat-vs-*) curve engine is also implemented — applyHslCurve indexes a control-point curve (hueCurveAt) by each pixel.s hue/sat/luma and shifts hue / scales sat / adds luma accordingly; only the draggable curve-editor widget is a UI layer on top |
| Vignette | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor vignette · clip-video-color)per-clip radial vignette overlay on the monitor, amount 0-100%; persisted |
| Vignette shape (midpoint / feather / roundness) | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (vignetteGradient · setVignetteShape)the full Lumetri Vignette beyond Amount: Midpoint (% of frame kept clear), Feather (pulls the clear zone inward, softening the falloff) and Roundness (>0 circle, else ellipse). vignetteGradient(opt) builds the radial-gradient the monitor applies to the vignette overlay (defaults reproduce the original look); c.vignetteOpt persisted. vignetteGradient unit-tested in webui/grid/tests/vignetteshape.test.mjs |
| Sharpen | Lumetri | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (sharpenKernel · zmonSharpen feConvolveMatrix · setSharpen)Lumetri detail Sharpen via a real 3x3 unsharp-mask SVG feConvolveMatrix on the monitor: sharpenKernel(amount) builds the centre 1+4a / edge -a kernel that sums to 1 (brightness-preserving, a=0 identity), and syncMonitor rewrites it per clip. c.sharpen persisted. sharpenKernel unit-tested in webui/grid/tests/sharpen.test.mjs |
| Posterize | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (posterizeTable · zmonPosterize discrete feComponentTransfer · setPosterize)the Posterize effect: quantise each channel to N discrete levels via an SVG feComponentTransfer type=discrete. posterizeTable(levels) builds the evenly-spaced step table (endpoints 0 and 1, min 2 levels); syncMonitor rewrites it per clip. c.posterize persisted. posterizeTable unit-tested in webui/grid/tests/posterize.test.mjs |
| Posterize Time | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (posterizeTimeStep · setPosterizeTime)the Posterize Time effect: drop a clip's effective frame rate for a stylised stutter. posterizeTimeStep(t, rate) snaps the source time to the nearest lower multiple of 1/rate so each frame is held for 1/rate seconds (rate 0 = off); syncMonitor quantises its per-frame seek by it. c.posterizeTime (fps) set via setPosterizeTime (clip-posterize-time), persisted - distinct from colour Posterize (posterizeTable) and frame blending. posterizeTimeStep unit-tested in webui/grid/tests/posterizetime.test.mjs |
| Find Edges (Stylize) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (edgeKernel · zmonEdges feConvolveMatrix · setFindEdges)the Find Edges stylize effect: a 3x3 Laplacian edge-detect convolution (centre 8a, eight neighbours -a, summing to 0 so flat areas go black and edges light up) via an SVG feConvolveMatrix. edgeKernel(amount) scales the edge strength; syncMonitor rewrites it per clip - distinct from Sharpen (sum 1). c.findEdges persisted. edgeKernel unit-tested in webui/grid/tests/findedges.test.mjs |
| Emboss (Stylize) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (embossKernel · zmonEmboss feConvolveMatrix · setEmboss)the Emboss stylize effect: a 3x3 directional relief convolution (anti-diagonal gradient -2a..+2a plus a centre of 1, summing to 1 so brightness holds and the image reads as a lit relief) via an SVG feConvolveMatrix. embossKernel(amount) scales the relief depth (0 = identity); syncMonitor rewrites it per clip - distinct from Sharpen and Find Edges. c.emboss persisted. embossKernel unit-tested in webui/grid/tests/emboss.test.mjs |
| Solarize | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (solarizeTable · zmonSolarize table feComponentTransfer · setSolarize)the Solarize stylize effect: the Sabattier fold |2x-1| (inverts shadows, keeps highlights) blended with the identity by an amount 0-1, applied as an SVG feComponentTransfer type=table. solarizeTable(amount, n) builds the lookup; syncMonitor rewrites it per clip. c.solarize persisted. solarizeTable unit-tested in webui/grid/tests/solarize.test.mjs |
| Mosaic | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (mosaicBlocks · setMosaic)the Mosaic stylize effect: pixelate the picture into square blocks. mosaicBlocks(rgba, w, h, blocks) divides the frame into `blocks` cells across the width and fills each with the average of its pixels (blocks <= 1 = whole-frame average, a very high count is ~identity); it runs on the monitor's .zmon-secondary readback canvas after the HSL secondary / curve steps so it composes with the grade. c.mosaic (horizontal block count) set via setMosaic (clip-mosaic), persisted. mosaicBlocks unit-tested in webui/grid/tests/mosaic.test.mjs |
| Tint (duotone) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (tintTransfer · zmonTint · setTint)the Tint colour-correction effect: desaturate to luma then ramp each channel from a shadow colour to a highlight colour. tintTransfer(black, white) parses the hex colours and returns the per-channel feFunc linear params (slope = white-black, intercept = black) for a saturate(0) feColorMatrix + feComponentTransfer; syncMonitor drives it per clip. c.tint persisted. tintTransfer unit-tested in webui/grid/tests/tint.test.mjs |
| Black & White (channel mixer) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (bwMatrix · zmonBW · setBlackWhite)monochrome conversion with adjustable per-channel weights (Black & White / Channel Mixer): bwMatrix(weights) builds the 4x5 feColorMatrix collapsing RGB to gray, normalised to sum 1 so brightness holds (default Rec.709 luma; lowering a channel.s weight darkens that hue, e.g. dramatic skies). Distinct from the fixed-luma grayscale effect; rendered on the monitor and persisted. bwMatrix unit-tested in webui/grid/tests/bw.test.mjs |
| Channel Mixer (colour) | Effects | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (channelMixMatrix · zmonChMix · setChannelMixer)the full colour Channel Mixer: mix each OUTPUT channel from the R/G/B inputs (outR = rr*R+rg*G+rb*B, etc.) for red/blue swaps, infrared looks, channel-based grades. channelMixMatrix(mix) builds the 4x5 feColorMatrix (identity default; e.g. rr:0,rb:1,br:1,bb:0 swaps red and blue), rendered per clip - distinct from Black & White which forces a mono result. c.chmix persisted. channelMixMatrix unit-tested in webui/grid/tests/channelmix.test.mjs |
| Lumetri scope (RGB + luma histogram) | Scopes | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (computeHistogram · drawScope · zmon-scope toggle)live RGB + Rec.709 luma histogram of the monitor frame, sampled ~10x/s onto a scope overlay; computeHistogram unit-tested in webui/grid/tests/histogram.test.mjs |
| Scopes (waveform / vectorscope) | Scopes | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (computeWaveform · computeVectorscope · scope mode cycle)the monitor scope cycles histogram -> luma waveform -> chroma vectorscope; both new scopes are pure + unit-tested in webui/grid/tests/scopes.test.mjs |
| RGB parade scope | Scopes | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (computeParade · scope mode cycle)the monitor scope cycle gains an RGB parade (R|G|B waveforms side by side); computeParade unit-tested in webui/grid/tests/parade.test.mjs |
| Comparison view / Split View (before / after) | Color | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (comparisonInset · setSplitView · zmon-before layer)a second unfiltered video layer shows the original beside the graded picture with a divider — the Fast Color Corrector / Lumetri Split View. comparisonInset(percent, layout) supports a vertical split (left corrected / right original) or a horizontal one (top / bottom), and setSplitView (clip-split-view) toggles compare and sets the layout + split percent; the layout/percent persist with the project. The split clip-path (both orientations) is unit-tested in webui/grid/tests/comparison.test.mjs |
| Audio clips (import + waveform) | Audio | PARTIAL | libs/zpwr-clip-engine/webui/clip/clip-seq.js (importAudio)webui import + waveform done; the native JUCE playback/DSP is now RENDER-VERIFIED headlessly (see the arranger report's audio rows + tests/audio_clip_render_test.cpp — a real WAV decoded through loadFile→trigger→process, asserted with Goertzel for pitch/envelope/crossfade/slip). PARTIAL: subjective audible sign-off through a compiled plugin is the remaining human step (never green on faith). |
| Clip gain / volume keyframes | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clip-video-vol-kf · syncMonitor volKfs via lerpKeyframes)per-clip volume rubber band: keyframed gain interpolated over the clip and applied to the monitor clip audio (v.volume); static per-clip gain already shipped. Per-track mixer automation tracked separately |
| Audio Track Mixer (faders + pan) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (openAudioMixer · panGains · trackVol/trackPan)a mixer panel with a volume fader + pan slider per audio track bound to trackVol/trackPan, showing the constant-power L/R balance; panGains unit-tested in webui/grid/tests/mixer.test.mjs |
| Audio sends / aux buses | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (sendGain · busContribution · setTrackSend · clip-track-send)post-fader sends route a track to a submix/aux bus: sendGain maps a send level in dB to linear gain (0 dB unity, ≤ −60 dB muted) and busContribution = track level × send gain. Wired: a per-track trackSend {bus, db} persists in the track list; setTrackSend (clip-track-send) and a per-strip SEND control in the audio mixer set it, and the mixer.s aux-bus row sums every track.s post-fader contribution via busContribution(vol, sendGain(db)) to show the per-bus level. The insert/aux DSP itself runs in the native plugin. sendGain/busContribution unit-tested in webui/grid/tests/sends.test.mjs |
| Solo track | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (isAudibleWithSolo · trackSolo · toggleSolo)solo audio tracks — when any is soloed only those play (meter + native gain); isAudibleWithSolo unit-tested in webui/grid/tests/solo.test.mjs |
| Track mute | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (trackAudible · trackMute · toggleMute)mute a track.s output — never plays (mute wins over solo); combined audibility (trackAudible) drives the meter + native gain; unit-tested in webui/grid/tests/trackmute.test.mjs |
| Audio clip mixer | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (openClipMixer · gainToDb)a panel of per-audio-clip gain faders (0-200%) with a dB readout (gainToDb), distinct from the per-track mixer; gainToDb unit-tested in webui/grid/tests/clipmixer.test.mjs |
| Normalize audio gain | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (normalizeGain · normalizeClipGain)set a clip.s gain so its loudest peak hits a target dB (Premiere Normalize Max Peak), from its peak envelope; normalizeGain unit-tested in webui/grid/tests/normalize.test.mjs |
| Audio Gain dialog (set / adjust dB) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (dbToGain · applyAudioGain · setAudioGain)Clip > Audio Gain (G): set the clip.s gain to an exact dB or adjust the current gain by a dB delta — distinct from peak normalize. dbToGain inverts gainToDb; applyAudioGain computes the new linear gain ('set' = dbToGain(db), 'adjust' = current x dbToGain(db)), clamped to [0,8]. c.gain persisted. Both unit-tested in webui/grid/tests/audiogain.test.mjs |
| Audio compressor (per track) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (compressorGain · trackComp · setTrackCompressor)a downward compressor (threshold/ratio) per audio track; the meter shows the gain reduction via compressorGain (unit-tested in webui/grid/tests/compressor.test.mjs) |
| Hard Limiter (per track) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (limiterGain · trackLimit · setTrackLimiter)Premiere's Hard Limiter: a brick-wall output ceiling per audio track (the loudness-maximiser last stage). limiterGain(levelDb, ceilingDb) returns the gain that brings any signal above the ceiling down to it and leaves the rest untouched - effectively infinite ratio, distinct from the ratio-based compressor. The ceiling persists in the track list and the meter reflects the limiting; the native engine applies the sample-accurate brick-wall (the standing native-audio partial). limiterGain unit-tested in webui/grid/tests/limiter.test.mjs |
| Parametric EQ (per track) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (biquadCoeffs · biquadResponse · setTrackEq)a per-track parametric EQ band (peaking / low+high shelf / low+high pass): biquadCoeffs computes the RBJ-cookbook biquad coefficients the native playback engine loads, and biquadResponse gives the magnitude curve for the response display. The band (type/freq/Q/gain) persists in the track list — same native-DSP integration as the per-track compressor. biquadCoeffs + biquadResponse unit-tested in webui/grid/tests/eq.test.mjs (flat 0 dB band, peaking boost/cut at centre, low/high-pass rolloff, shelves) |
| Convolution reverb (per track) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (reverbImpulse · setTrackReverb)a per-track convolution reverb: reverbImpulse(durSec, decaySec, fs, seed) synthesises a decaying-noise impulse response (seeded white noise x an exponential decay envelope) that the native engine loads into a convolver; the reverb (decay + wet mix) persists in the track list — same native-DSP integration as the EQ + compressor. reverbImpulse unit-tested in webui/grid/tests/reverb.test.mjs (IR length, exponential energy decay, per-sample envelope bound, decay-time effect, determinism) |
| Audio de-noise | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (estimateNoiseFloor · spectralSubtract · setTrackDenoise)spectral noise reduction: estimateNoiseFloor takes a low percentile of the FFT bin magnitudes as the broadband noise estimate, and spectralSubtract removes reduction x that floor per bin (keeping a floorClamp fraction so signal survives). A per-track de-noise (reduction + sensitivity) persists in the track list; the native engine FFTs each frame, applies this, and inverse-FFTs — same native-DSP integration as EQ + reverb. Both helpers unit-tested in webui/grid/tests/denoise.test.mjs |
| DeHum (mains hum removal) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (humNotches · biquadCoeffs notch · setTrackDeHum)Premiere.s DeHum: a comb of notch filters at the mains fundamental (50 or 60 Hz) and its harmonics. An RBJ notch was added to biquadCoeffs, and humNotches(baseHz, harmonics, fs, Q) returns one notch coefficient set per harmonic (at base, 2x, 3x ..., skipping any at/above Nyquist) - the cascade the native engine loads over the track. A per-track DeHum ({base, harmonics, q}) set via setTrackDeHum (clip-track-dehum) persists in the track list - the same native-DSP integration as the parametric EQ / reverb / de-noise (sample-accurate audio is the standing native partial). humNotches + the notch response unit-tested in webui/grid/tests/dehum.test.mjs |
| Essential Sound + auto-ducking | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (trackRole · duckGain · tagAudioRole)tag a track dialogue/music/sfx/ambience (the four Essential Sound audio types); while a dialogue track is loud the music/sfx/ambience tracks auto-duck (duckGain) on the meters; duckGain unit-tested in webui/grid/tests/duck.test.mjs |
| Loudness Auto-Match (Essential Sound) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rmsLoudnessDb · integratedLoudnessLufs · loudnessMatchGain · setLoudnessMatch)the Essential Sound Loudness / Auto-Match: set a clip.s gain so its perceived loudness hits a target. Two measures: rmsLoudnessDb is a fast RMS over the waveform envelope, and integratedLoudnessLufs computes true ITU-R BS.1770 / EBU R128 integrated loudness (LUFS) over the decoded samples the webui already has (decodeAudioData -> getChannelData) — K-weighting (high-shelf + high-pass biquads, RBJ-bilinear coefficients derived per sample rate), 400ms blocks at a 100ms hop, then absolute -70 LUFS + relative -10 LU gating. loudnessMatchGain returns the gain to reach the target (clamped 0-8) - distinct from peak normalize (a lone spike reads quieter by loudness). Unit-tested in webui/grid/tests/loudness.test.mjs + loudnesslufs.test.mjs (a calibration-independent -6.02 LU per amplitude-halving proof, K-weighting low-freq rejection, gating, cross-sample-rate) |
| Enhance Speech (Essential Sound) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (enhanceSpeechBands · setEnhanceSpeech)the Essential Sound Enhance Speech dialogue-clarity DSP with a Mix Amount (0-10): enhanceSpeechBands builds the intelligibility EQ chain — sub-bass rumble high-pass, low-shelf mud cut, and a presence-band peaking boost, all scaled by mix — which the native engine applies via biquadCoeffs. c.enhanceSpeech persists per clip. The ML source-separation half isn.t portable; the clarity EQ is. enhanceSpeechBands unit-tested in webui/grid/tests/enhancespeech.test.mjs |
| Essential Sound presets (save / apply) | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (extractAudioPreset · applyAudioPreset · saveAudioPreset)the Essential Sound Preset dropdown: save the active audio clip.s treatment (gain, head/tail fades + curve, Enhance Speech amount) as a named localStorage preset and apply it to other clips, keeping their identity/source. extractAudioPreset/applyAudioPreset unit-tested in webui/grid/tests/audiopreset.test.mjs |
| Extract audio from video | Audio | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (audioFromVideo · extractAudio)splits the active video clip.s audio into a new audio clip on an audio track, auto-linked (shared linkGroup) so the pair moves/ripple-deletes together; audioFromVideo unit-tested in webui/grid/tests/extractaudio.test.mjs |
| Remix (retime music to duration) | Audio | PARTIAL | libs/zpwr-clip-engine/webui/clip/clip-seq.js (remixPlan · remixToFit)Premiere's Remix: retime a music clip to a target duration by editing on bar boundaries instead of changing tempo. remixPlan(srcDur, targetDur, segLen) is the edit-decision engine - it keeps the intro and outro and drops middle bars to shorten, or repeats middle bars (cycled, in musical order) to lengthen, returning the source time-ranges (merged where contiguous) that play back-to-back at ~target with every cut snapped to the bar grid. remixToFit derives the bar length from the current tempo, stores the plan on the clip (c.remix) and spans the clip in/out to it. remixPlan unit-tested in webui/grid/tests/remix.test.mjs (exact target, shorten keeps intro/outro, lengthen repeats the middle, bar-grid snap, degenerate inputs). PARTIAL: the seam MODEL (remixSeamGains) and the sample-level RE-RENDER are now headless-verified (libs/zpwr-clip-engine/webui/grid/remix-render.js: remixRender, 9 tests in remixrender.test.mjs — verbatim source ranges joined by equal-power crossfaded seams, click-free, bit-exact single-segment identity, output length tracks the plan). The remaining step is the audible sign-off through the live JUCE audio engine (human ears). |
| Essential Graphics text (title clips) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (addTitle · titleAt · titleStyle)source-less title clips with positioned, sized, coloured text rendered as a monitor overlay over the clips below; titleStyle unit-tested in webui/grid/tests/title.test.mjs |
| Essential Graphics shapes | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (addShape · shapeAt · shapeStyle)source-less rectangle/ellipse shape clips with position/size/colour/opacity rendered as a monitor overlay over the clips below; shapeStyle unit-tested in webui/grid/tests/shape.test.mjs |
| Shape stroke / border | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (shapeStyle border · setShapeStroke)Essential Graphics shape stroke: a solid border of width+colour around the shape (width 0 = none). shapeStyle returns the CSS border the monitor applies (box-sizing border-box so it doesn.t resize the shape); the stroke persists on the shape. shapeStyle border unit-tested in webui/grid/tests/shapestroke.test.mjs |
| Essential Graphics text styles | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (extractTextStyle · applyTextStyle · clip-textstyle-save/apply)save a title.s styling (colour/font/stroke/shadow/bg/size/align) as a named style and apply it to other titles; extract/applyTextStyle unit-tested in webui/grid/tests/textstyle.test.mjs |
| Responsive Design — Position (pin) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (pinnedPosition · setTitlePin)Essential Graphics Responsive Design (Position): pin a title to an edge/corner so it holds that spot by edge margin regardless of frame size. pinnedPosition(pin, margin) maps top/middle/bottom x left/center/right to {x,y}% and feeds titleStyle (a pin overrides free x/y); the pin persists on the title. pinnedPosition unit-tested in webui/grid/tests/titlepin.test.mjs |
| Responsive Design — Time (intro/outro protect) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (respTimeRemap · setResponsiveTime · clip-responsive-time)Essential Graphics Responsive Design (Time): an intro region at a clip's head and an outro region at its tail keep their length when the clip is retimed, so animated in/out keyframes hold their shape while only the middle stretches. respTimeRemap(t, oldDur, newDur, intro, outro) maps a source time into the retimed clip — intro kept 1:1 from the head, outro 1:1 from the tail, the middle scaled. Wired: setResponsiveTime (clip-responsive-time) stores c.responsive {intro, outro} and syncMonitor remaps the clip's motion/opacity keyframe times through respTimeRemap before interpolation, so the head/tail keyframes keep their absolute timing as the clip span changes. respTimeRemap unit-tested in webui/grid/tests/resptime.test.mjs |
| Motion Graphics templates (.mogrt) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (mogrtToClip · clipToMogrt · clip-mogrt-import/export)import a .mogrt template as a title/shape graphic clip and export any title/shape clip as a reusable .mogrt; mogrtToClip/clipToMogrt round-trip unit-tested in webui/grid/tests/mogrt.test.mjs |
| Caption / lower-third text (burn-in) | Captions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncMonitor caption · clip-video-trim)per-clip caption text burned over the monitor while the clip plays; persisted |
| Captions / subtitles (SRT) | Captions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (parseSRT · toSRT · cueAt · zmon-sub overlay)a project caption track (cues in seconds) rendered as a timed monitor subtitle overlay, with .srt import/export; parse/serialize/cue-pick unit-tested in webui/grid/tests/srt.test.mjs. A single cue can override the stream's position/align/colour (cueStyle, below) |
| Caption formatting (position / alignment) | Captions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (captionStyle · setCaptionStyle)format the caption stream: place the caption block at the bottom (default), top or vertical centre, and align the text left / center / right. captionStyle(style) returns the CSS the monitor applies to the subtitle overlay (top/bottom/transform/textAlign/colour); the style persists at the project level. captionStyle unit-tested in webui/grid/tests/captionstyle.test.mjs |
| Per-cue caption overrides | Captions | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (cueStyle · captionStyle colour)an individual caption cue can override the stream-level formatting (position / alignment / colour): cueStyle(base, cue) merges a cue's own style over the project default (cue wins) and feeds captionStyle, which now also emits an optional text colour. The monitor's subtitle overlay applies the per-cue resolved style live (cueStyle at the zmon-sub render site). cueStyle unit-tested in webui/grid/tests/cuestyle.test.mjs |
| Text-Based Editing (transcript) | Captions | PARTIAL | libs/zpwr-clip-engine/webui/clip/clip-seq.js (transcriptKeepRanges · transcriptSplitClips · transcriptRippleDuration · parseTranscript · textBasedEdit)edit a clip by editing its transcript: the clip carries words [{start,end,text}] (parseTranscript reads '<start> <end> <text>' lines), and deleting words ripple-deletes their time. transcriptKeepRanges(words, deleted) returns the surviving time ranges — consecutive survivors merge (natural pauses kept), a deleted word between survivors makes an interior cut; transcriptRippleDuration gives the collapsed length. textBasedEdit applies a head/tail trim exactly (the clip in/out collapses to the spoken span); the interior multi-segment split is now applied too — transcriptSplitClips turns the surviving runs into one back-to-back timeline clip instance each, carrying its own source in/out, placed contiguously (barsPerSec sets the length). The transcript persists on the clip. Unit-tested in webui/grid/tests/textedit.test.mjs + transcriptsplit.test.mjs (incl. end-to-end with transcriptKeepRanges). PARTIAL only for speech-to-text (transcript generation) — an external ASR step, like native audio DSP |
| Legacy titler (styled titles) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (titleStyle font/stroke/shadow/bg · addLegacyTitle)the classic title designer: a title clip with font, fill, outline/stroke, drop shadow and a background box; titleStyle styling unit-tested in webui/grid/tests/titler.test.mjs |
| Rolling / crawling titles | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (rollOffset · setTitleScroll)the legacy titler.s roll (credits scroll up/down) and crawl (ticker left/right): the title.s offset is animated across its clip span. rollOffset(progress, mode, travel) sweeps the title from +travel to -travel; the monitor drives it from the playhead.s position within the title clip, and the mode persists on the title. rollOffset unit-tested in webui/grid/tests/rolloffset.test.mjs |
| Title drop-shadow controls (angle / distance / blur) | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (titleShadowCss · setTitleShadow)the legacy titler.s drop-shadow parameters: angle, distance, blur and colour (vs the previous on/off shadow). titleShadowCss(shadow) turns {angle,distance,blur,color} into a CSS text-shadow (dx=cos*d, dy=sin*d; 0deg=right, 90=down), staying back-compatible with the boolean form, and feeds titleStyle. The shadow object persists on the title. titleShadowCss unit-tested in webui/grid/tests/titleshadow.test.mjs |
| Title tracking & leading | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (titleStyle letterSpacing/lineHeight · setTitleSpacing)the titler.s typography spacing controls: tracking (letter-spacing, px) and leading (line-height multiplier, default 1.1). titleStyle maps title.tracking/leading to the monitor.s CSS letter-spacing + line-height; the values persist on the title. Unit-tested in webui/grid/tests/titlespacing.test.mjs |
| Title bold / italic / caps / underline / strike | Graphics | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (titleStyle fontWeight/fontStyle/textTransform/textDecoration · setTitleFontStyle)the titler.s text-style toggles: bold (heavier weight), italic, all-caps, underline and strikethrough. titleStyle maps title.bold/italic/caps/underline/strike to the monitor.s font-weight / font-style / text-transform / text-decoration; they persist on the title. Unit-tested in webui/grid/tests/titlefontstyle.test.mjs |
| Multicam source sequence | Multicam | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (makeMulticam · multicam.angles)group the footage clips into one multicam clip whose angles share a common start; angleAt-driven, unit-tested in webui/grid/tests/multicam.test.mjs |
| Multicam editing / angle switch | Multicam | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (angleAt · switchAngle · 1-9 keydown)press 1-9 at the playhead to cut to that angle; the monitor renders the live angle.s source via angleAt; unit-tested in webui/grid/tests/multicam.test.mjs |
| Multicam flatten | Multicam | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (flattenMulticam · flattenMulticamAt)Flatten bakes the multicam clip.s angle switches into real per-angle clips: flattenMulticam(cuts, totalSec) turns the cut list into contiguous {angle,start,len} segments spanning the clip, and the action replaces the multicam instance on the lane with the corresponding angle clips (bar-quantized). flattenMulticam unit-tested in webui/grid/tests/flattenmulticam.test.mjs |
| Synchronize clips (align by sync point) | Multicam | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (syncStarts · synchronizeSelection)Clip > Synchronize: align the selected timeline instances so a common sync point (each clip.s source in-point, as a bar offset) lands on the same bar. syncStarts puts new starts at B - sync where B = max(bar + sync), so clips only shift right and never go negative; the latest sync point stays put. syncStarts unit-tested in webui/grid/tests/syncstarts.test.mjs |
| Scene edit detection | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (detectCuts · detectScenes)decodes the clip.s filmstrip thumbnails to luma, finds hard cuts (detectCuts) and drops scene markers at them; detectCuts unit-tested in webui/grid/tests/scenes.test.mjs. Thumbnail-resolution + marker mode (not full-frame auto-split) |
| Auto-reframe (geometric) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (reframeFill · autoReframe)scales the clip to center-crop fill the sequence aspect (e.g. 16:9 -> 9:16 vertical) via its Motion scale; reframeFill unit-tested in webui/grid/tests/reframe.test.mjs. Subject-tracking reframe (motion-tracked, non-ML): feed trackPoint.s per-frame subject point to recenterOffset(x, y, w, h), which returns the Motion position offset (% from centre, clamped) that keeps the subject framed while reframing. recenterOffset unit-tested in webui/grid/tests/trackpoint.test.mjs |
| Auto-reframe presets (target aspect) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (aspectDims · reframeToAspect)reframe to a named aspect preset (16:9 / 9:16 / 1:1 / 4:5 / 4:3 / 21:9): aspectDims computes the frame dims at the current height, the sequence is resized, then the clip is geometric-reframed to fill it; aspectDims unit-tested in webui/grid/tests/aspectdims.test.mjs |
| Interpret footage (assume frame rate) | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (reinterpretFootage · interpretFootage)Modify > Interpret Footage: reassign a clip's assumed fps. Since the frame count is fixed, the real-time duration and the in/out window rescale by from/to fps (e.g. 60fps read as 24fps -> 2.5x slow-mo), independent of the speed property; interpretFps/nativeFps persist in the project. Non-compounding and invertible; reinterpretFootage + reinterpretedDuration unit-tested in webui/grid/tests/interpret.test.mjs |
| EDL export (CMX3600) | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (toEDL · exportEDL · clip-export-edl)export the video timeline as a standard CMX3600 .edl (numbered cut events, source + record timecodes at the sequence fps); toEDL unit-tested in webui/grid/tests/edl.test.mjs |
| Final Cut Pro XML export | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (toFcpXml · exportFcpXml · gatherVideoEvents)export the video timeline as FCP7 XML (xmeml) — the interchange Premiere reads/writes — with frame-based clipitems; toFcpXml unit-tested in webui/grid/tests/fcpxml.test.mjs |
| EDL import (cuts -> markers) | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (parseEDL · importEDL)parse a CMX3600 .edl (inverse of toEDL) and drop a scene marker at each event.s record-in; parseEDL round-trips with toEDL, unit-tested in webui/grid/tests/edlimport.test.mjs |
| Media render to .webm (canvas + MediaRecorder) | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (renderSequence · pickRecorderMime)real in-browser export: plays the timeline drawing each graded program frame to a canvas and records the stream to .webm via MediaRecorder; pickRecorderMime unit-tested in webui/grid/tests/render.test.mjs. title/shape/caption overlays are burned into the canvas (pctToPx). Batch queueing is the render-queue row below |
| Export / render queue (batch) | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (queueAdd · nextPending · markDone)Premiere.s Add to Media Encoder Queue: line up several render jobs, each a {id, preset, range, status}. queueAdd appends a pending job (fresh max-id+1), nextPending returns the first pending job to encode, and markDone flips a job to done/failed immutably so the queue advances. Wired: addToRenderQueue captures the current sequence preset + I/O range via queueAdd; renderNextInQueue picks nextPending, restores that preset/range and runs the render path (renderSequence), then markDone advances the queue. The queue persists with the project; clip-render-queue-add / -next buttons. queueAdd/nextPending/markDone unit-tested in webui/grid/tests/renderqueue.test.mjs |
| Export Frame (still PNG) | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (exportFrame · frameFilename)grab the current graded program frame (video + grade + title/shape/caption overlays) as a PNG at the sequence size, named by timecode; frameFilename unit-tested in webui/grid/tests/exportframe.test.mjs |
| Export presets + match source | Export | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (matchSourcePreset · EXPORT_PRESETS · applyExportPreset)pick an export preset — Match Source (from the sequence) or a named size/rate — to set the sequence frame size + fps; matchSourcePreset unit-tested in webui/grid/tests/exportpreset.test.mjs. Smart-render stream-copy needs a native encoder |
| Undo / redo history | Edit | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (undo/redo · scheduleUndo)full project-state undo stack |
| Keyboard shortcuts | Workflow | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (clipManualKey)the editor's key bindings (host appShell owns globals) |
| Workspaces / panel layout | Workflow | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (captureWorkspace · applyWorkspace · mergeWorkspace)save/restore named monitor layouts (docked-vs-floating, scope mode, comparison view) in localStorage; mergeWorkspace back-fills missing keys, unit-tested in webui/grid/tests/workspace.test.mjs |
| Auto-save | Workflow | PORTED | libs/zpwr-clip-engine/webui/clip/clip-seq.js (autosaveNow 30s interval · autosaveFresh · recoverAutosave)the project is snapshotted to localStorage every 30s; on load a fresh snapshot enables a recover action. autosaveFresh unit-tested in webui/grid/tests/autosave.test.mjs |
| Productions / Team Projects | Collaboration | PORTED | libs/zpwr-clip-engine/webui/grid/project.js (locks · mergeBanks) · libs/zpwr-clip-engine/webui/grid/sync.js · libs/zpwr-clip-engine/webui/grid/net-sync.jsthe full Productions collaboration path is implemented and network-verified: project locking (lockState/canEdit/acquireLock/releaseLock over a shared `locks` map) + the lock-aware, order-independent, idempotent 3-way bank merge (mergeBanks) + a REAL sync transport in two implementations sharing one publish/subscribe contract — an in-process loopback (grid/sync.js) AND a dependency-free TCP hub/client over Node's built-in `net` (grid/net-sync.js: createNetSyncHub/connectNetSyncClient). Verified END-TO-END OVER REAL LOCALHOST SOCKETS: netsync.test.mjs (6 tests — an edit propagates to another client only after a socket round-trip, first-writer-wins locks, conflict convergence, late-join catch-up, release, and coalesced/split-across-packet TCP framing) + the 7-test loopback suite + the productions.test.mjs merge suite; an adversarial pass confirmed clients hold separate banks converging only through real net.Server/net.Socket I/O. A cross-machine/durable hub (WebSocket, Redis, storage) is the same code behind the same contract. |