Video export, animated GIF export, image export, audio-only export, transparent stacked-alpha export, FFmpeg WASM intermediates, named export presets, batch source export, and FCPXML interchange.
The export panel currently exposes three live encoder paths:
webcodecsfor the fast frame-by-frame pipelinehtmlvideofor the precise HTML-video-seeking pipelineffmpegfor the CPU FFmpeg WASM pipeline
FCPXML is exposed as a selectable export container for NLE interchange.
-
During video export, red
Canceldiscards the run. YellowFinish File Earlybelow it finishes the current frame, finalizes the partial file, and downloads it. Available after the first frame in WebCodecs, HTMLVideo, FFmpeg, and HAP; disabled during preparation and finalization. Audio ends with the partial video (browser-compressed audio keeps only complete packets). Audio-only, GIF, image sequences, and batch conversion do not offer early finish. -
A sticky summary bar at the top wraps compact badges in at least two columns, ending in a green Export pill that includes the estimated file size when a byte estimate is available.
-
Its first badge shows
SaCwhen export resolution and frame rate match the active composition, orNaCotherwise; clickingNaCcopies those composition settings into Export. -
Clicking a summary badge smooth-scrolls within that Export panel to the related control group and briefly highlights it.
-
A compact command row above
Basiccontains a project-persistent preset list plusLoad,Update, andSave. -
The workflow picker (
WebCodecs,HTMLVideo,FFmpeg) is its own section aboveBasic. -
Basiccontains output naming and container selection. The container row is grouped byVideo,Image,Audio, andXML, and switches output mode by selecting a deliverable directly. -
The
Videogroup contains codec selection, resolution, frame rate, bitrate/rate controls, animated GIF palette controls, stacked-alpha, and range toggles. -
The video resolution header includes a compact orientation pictogram. Orientation is independent from the selected preset, so
1080p,4K, and the other preset pills stay selectable in portrait andCustomremains reserved for genuinely custom dimensions. -
Narrow dock panels never scroll horizontally: lower option groups stack to one column, chip grids step from three to two and finally one column at the narrowest breakpoint, and summary navigation scrolls only the panel's vertical form.
-
In
Imagemode the same middle group becomes anImagepanel with format-aware resolution and quality controls, and it can export either the current playhead frame or a numbered image sequence folder. -
The
Audiogroup contains audio-only format selection, sample rate, bitrate for browser-compressed audio, normalization, and audio-only range controls. -
Lower in the panel,
Advanced Video,Advanced Audio, andRange & Summarysections provide raw-value access. -
Export settings, presets, and the batch queue live in
exportStoreand are restored with the project. They are not timeline undo/redo history entries.
- Presets are stored per project, not in browser-only local storage.
Saveprompts for a name and creates a new preset or overwrites an existing preset with the same name.Updateoverwrites the currently selected preset without asking for a new name.Loadrestores the selected preset back into the live export settings.- Presets and the current export settings are written into the project UI state and restored with the project.
FrameExporter is used for both the WebCodecs and HTMLVideo export buttons.
Canvas-backed sources such as text, solids, Lottie, and Rive are re-rendered for every export frame before capture, so the exported frame matches the current timeline time instead of reusing a stale first-frame texture. Motion shape clips are built as motion layer sources and rendered by the WebGPU motion renderer at export frame time before compositing.
- Export canvas capture snapshots the submitted GPU image immediately, without a per-frame
queue.onSubmittedWorkDone()round trip. The retainedVideoFrameremains valid if canvas cleanup happens afterward; capture no longer reads a nullable canvas field after yielding. - A canvas capture failure still permits pixel readback, but disables repeated direct-capture attempts only for that export canvas. Initializing a new export retries the direct path.
tests/browser/export-canvas-probe.htmlis a dev-only synthetic WebGPU check: it compares immediate/waited capture, verifies alternating frame pixels, encodes H.264, and reproduces the former cleanup race without changing a project. Its timings are not whole-editor export benchmarks.- Uses WebCodecs sequential decoding for a single clip.
- FAST export resolves the requested time to a source sample, waits for that exact decoded frame, and fails if it stays unavailable instead of silently substituting a buffered neighbor. The Windows beta harness verifies the complete exported frame sequence with independently decoded frame counters.
- Regular multi-clip exports use source-shared sequential WebCodecs decoders; nested-composition video clips use
ParallelDecodeManager. - Parses source media with MP4Box.
- Decode, buffer, and unsupported-file failures remain in the selected workflow. Errors are logged and surfaced; Fast mode does not automatically switch to HTMLVideo.
Nested preview and export account for each composition wrapper's start time and trim when seeking deeper video sources.
- Uses detached
HTMLVideoElementinstances and browser seeking. - Prepares nested video sources for the selected export range and parent trims. Ordinary forward 1x composition branches skip unused descendants; retimed or transition-driven branches keep conservative preparation. Composition wrappers do not consume video decoders.
- If a required video cannot be admitted within the media budget, preparation reports the failure before rendering.
- Waits for ready state and a fresh frame before capture. A temporarily unavailable nested source triggers the export readiness retry; an older preview composition texture is never accepted as the current export frame.
- Is slower than fast mode, but it is the explicit compatibility choice for difficult files or timing cases.
Supported containers:
- MP4
- WebM
Supported codecs are checked at runtime:
- H.264
- H.265
- VP9
- AV1
- WebM is limited to VP9 or AV1.
- MP4 accepts the full codec list, but browser support is checked with
VideoEncoder.isConfigSupported(). - Unsupported combinations are not silently promised by the docs; they must pass the runtime checks or be remapped by the encoder logic.
- The selected bitrate is passed into
VideoEncoder, but in the WebCodecs path it is a target, not a guaranteed final file bitrate. rateControl = cbrmaps toVideoEncoderConfig.bitrateMode = "constant"and falls back to variable bitrate if constant mode is rejected during encoder configuration.- Browser encoders can undershoot the requested bitrate on simple material, so the panel treats file size as a target estimate rather than an exact promise.
stackedAlpha is supported in the WebCodecs / HTMLVideo export path.
- The export canvas height is doubled.
- The top half contains RGB.
- The bottom half contains alpha as grayscale.
OutputPipelinemode2andExportCanvasManagerhandle the stacked-alpha render path.
- This is a stacked-alpha format, not a conventional single-layer transparent video container.
Animated GIF is exposed as .gif in the video container group.
- Available from the WebCodecs / HTMLVideo workflow selector, but GIF is not a WebCodecs codec.
- Uses the same frame-accurate browser render path, then encodes indexed GIF frames with the
gifencJavaScript encoder. - Supports palette size, global vs per-frame palette mode, forever/once/count loop modes, transparent or opaque GIF output, and binary alpha threshold.
- Uses fast quantization without dithering because
gifenchas no dithering support. - Does not support audio.
- Uses the GIF size estimator instead of video bitrate math.
- Stops before rendering when the selected range would exceed the browser encoder's memory budget; use FFmpeg GIF or reduce duration, FPS, or resolution for larger exports.
- Available from the FFmpeg workflow selector.
- Uses FFmpeg
palettegenandpaletteusefor palette-quality output. - Supports palette size, global/per-frame palette behavior, dithering, Bayer scale, forever/once/count loop modes, transparent or opaque GIF output, transparency threshold, and frame-difference optimization.
- Does not extract or mux audio.
- GIF estimates are based on output pixels, frame count, palette size, dither mode, palette mode, transparency mode, and optimization settings.
- The panel shows a single estimate and a content-dependent range because GIF LZW compression varies heavily with motion, noise, and transparency.
- MP4/WebM estimates continue to use bitrate targets.
Audio export is handled separately from the video encoder.
- Audio is extracted from the selected timeline range.
AudioExportPipelinerenders the mixed audio through the same clip-local path used for processed timeline waveforms.- Audio-only WAV export writes the mixed
AudioBufferas 16-bit PCM WAV. - WebCodecs export can mux the audio chunks into the final file.
- Audio-only export supports uncompressed WAV (
.wav) without WebCodecs audio encoding. - Audio-only export supports MP3 (
.mp3) through the browser-side Mediabunny MP3 encoder package, without the Native Helper. - Browser-compressed audio-only export writes AAC (
.aac) or Opus (.ogg), according to runtime support. - AAC is the MP4 default. Browser exports default to 192 kbps and retry with a Chromium-compatible AAC bitrate when the requested bitrate is unsupported.
- Opus is used for WebM when supported.
- Clip-local trim, region edit-stack operations including paste/insert/delete silence, reverse, speed/pitch, mute, EQ, and volume are rendered before mixing.
- If the browser cannot encode a usable audio format, the export can proceed without audio.
- Audio availability is determined by browser and container support; export may proceed without audio when no supported format is available.
Image export can render a single composited frame at the current playhead position or a numbered still-image sequence over the selected range.
- PNG
- JPG
- WebP
- BMP
- A visual clip's Export Current Frame context-menu command renders the whole active composition at its full resolution, independent of preview quality. Its JPG has a black background, without preview overlays. Use the export panel's PNG or WebP format for transparency.
- Timeline
Framemode does not use the In/Out range. It renders only the current playhead frame. Direct source batch export instead encodes the complete source image. Sequencemode uses the normal export range, respectsUse In/Out, renders at the selected frame rate, and writes numbered image files into a user-selected folder when the browser supports File System Access.- Browsers without folder write access fall back to a ZIP download.
- Custom resolution still applies before the image is written.
- PNG and BMP are exported losslessly.
- JPG and WebP expose a quality control in the panel.
- Audio is ignored while image export is active.
When the current frame contains a supported glyph/cell treatment, the Advanced panel can export the exact cell result independently of the normal raster deliverable:
- TXT writes the character grid as plain UTF-8 text.
- SVG creates real vector
<text>cells; it does not embed a raster frame. - Web Pack bundles TXT, SVG, metadata, and optional gzip tracking sidecar data in a ZIP.
The exporter uses the same grid/ramp contract as the GPU glyph path. Files and Blobs are created only for the download operation and are never stored in durable project state.
- Media files can be queued for batch export from the export panel.
- The queue can use each job's own settings or apply one shared technical configuration while retaining individual file names.
- Direct source jobs bypass timeline-only outputs and In/Out markers; source images are exported at the selected output resolution.
HAP is a dedicated browser encoder choice rather than an FFmpeg codec. It
produces QuickTime .mov files through the WebGPU block encoder and exposes
HAP, HAP Alpha, and HAP Q formats for VJ and media-server playback. The export
summary, size estimate, progress UI, persistent presets, and project settings
all treat HAP as its own encoder; video exports use PCM audio when audio is
included.
The FFmpeg path is a separate CPU-based export pipeline.
- Loads the FFmpeg core from the local
/ffmpegpath on demand. - Uses a single synchronous
callMain()execution model. - Blocks the UI while encoding is running.
- Reports progress from FFmpeg log output where possible.
- ProRes
- DNxHR / DNxHD family
- FFV1
- UTVideo
- MJPEG
- Animated GIF
- MOV
- MKV
- AVI
- MXF
- GIF
- GIF export is silent.
- This build does not expose a shared decoder pool.
- Multi-threaded mode is only reported as a capability check; the exported core path is synchronous.
callMain()blocks while encoding, so it is not the same runtime profile as the WebCodecs path.
FCPXML export is available through the container chooser as .fcpxml.
- Timeline structure
- Clip timing and track layout
- Basic audio placement
- Compositions are skipped
- Text clips are skipped
- The XML points back to media by file reference, so it is an interchange file, not a self-contained rendered deliverable
- This is useful for NLE round-tripping, not for final media delivery.
Still-image export renders the current composited frame through an export render session.
- The runner reads back the rendered RGBA pixels.
- It encodes the pixels as PNG, JPG, WebP, or BMP according to the selected image format.
- Still-image and image-sequence paths use CPU pixel readback.
- Prepare clips and runtimes for the selected export mode.
- Seek all clips to each export time.
- Build layers for that frame.
- Render procedural motion shapes, nested compositions, transitions, and supported 3D assets, then composite through the GPU engine.
- Capture a
VideoFramefrom the export canvas when possible, otherwise fall back to pixel readback. - Encode and mux the file.
Baked Datamosh transitions are prepared as ordinary project-backed video media before frame rendering. Preview and export therefore consume the same cached codec artifact; export does not run the I-frame-removal bake again. Isolated source renders used by the baker stage detached HTML video frames through a canvas before WebGPU import so a newly sought frame cannot collapse into a repeated source column.
WebCodecs decoder startup submits a bounded search window of up to 32 samples before waiting for delayed initial output. It does not insert a separate output wait after each small startup chunk; normal decoding still waits for its target, and end-of-source decoding still drains the decoder. This supports hardware decoders that briefly report an empty queue before delivering their first frame.
- Render each frame through the GPU engine.
- Read pixels from the GPU.
- Collect frames in memory.
- Extract audio if enabled and the selected output supports audio.
- Run FFmpeg encoding.
- Neither path is background rendering. Both depend on the current browser session.
When export fails in the UI, reproduce the same browser-side path through the dev bridge before changing exporter code:
$token = Get-Content -Path .ai-bridge-token -Raw
$headers = @{ Authorization = "Bearer $token"; 'Content-Type' = 'application/json' }
$body = @{ tool = 'debugExport'; args = @{ includeAudio = $true; exportMode = 'fast'; download = $false; maxRuntimeMs = 25000 } } | ConvertTo-Json -Depth 6
Invoke-RestMethod -Uri 'http://localhost:5173/api/ai-tools' -Method Post -Headers $headers -Body $bodydebugExport calls FrameExporter in the active browser tab and returns blob metadata, sampled progress, engine readiness before/after, and recent Export/WebGPU logs. It intentionally does not download unless download = $true. Use maxRuntimeMs to cancel cleanly before a long bridge request appears hung.
Interpret the result as follows:
- Blob
size > 0: browser export works; debug UI download/progress/preset handling next. WebGPU device lost during exportplus brokengetStatsfields such asrenderLoop.isRunning=false,renderDispatcher=null, ortargetCanvasCount=0: hard-reload the browser tab or callreloadApp, then retest.- Video-only timelines should skip audio work even if
includeAudio = $true; a long "Rendering audio" phase usually points at audio-range detection.
- Preview and export are separate pipelines, even though they reuse the same engine.
- Precise export still depends on browser media readiness and seek behavior.
- FFmpeg export is blocking.
- The exporter does not provide a true multi-pass render pipeline.
Key implementation files:
src/components/export/ExportPanel.tsxsrc/components/export/useExportState.tssrc/components/export/useExportRunController.tssrc/components/export/exportHelpers.tssrc/components/export/runners/src/components/export/panel/src/engine/export/FrameExporter.tssrc/engine/export/ClipPreparation.tssrc/engine/export/BrowserGifExporter.tssrc/engine/export/ImageSequenceExporter.tssrc/engine/export/VideoSeeker.tssrc/engine/export/VideoEncoderWrapper.tssrc/engine/export/codecHelpers.tssrc/engine/managers/ExportCanvasManager.tssrc/engine/pipeline/OutputPipeline.tssrc/services/export/fcpxmlExport.tssrc/engine/ffmpeg/FFmpegBridge.tssrc/engine/ffmpeg/codecs.ts
FAST export includes the final exact-frame wait in its bounded decoder recovery. If the browser loses the decoder after samples were submitted, export recreates it and restarts from the preceding keyframe once. It still requires the exact source frame; a missing frame or failed recreation produces an explicit failure instead of substituting a neighboring frame or retrying indefinitely.
Export submissions retain exclusive ownership until the runner and its cleanup settle. Same-tick duplicate starts and restart attempts during cancellation are ignored; cancellation leaves the timeline export lock in place until cleanup finishes. A later export can start normally after completion or failure.
Video export checks codec support and selects the audio format before preparation, but allocates the video encoder only when the first RGBA or zero-copy frame is ready. Slow source loading, audio rendering, and asset preparation therefore do not hold an idle video codec that the browser can reclaim. Cancellation during preparation discards the pending encoder and muxer. This does not restore inaccessible source files or prevent resource loss after encoding has begun.