New export format alongside audio/image/video/SVG. GIF is multi-frame like
video but palette-quantized with no audio, so it reuses the per-frame RGBA
render/readback path (render_frame_to_gpu_rgba) and streams frames to a
background encoder.
- core: GifExportSettings (resolution, framerate, loop, transparency, fit,
time range) with centisecond-quantized frame delay + tests.
- gif_exporter: encoder pipeline. Per-frame NeuQuant quantization is the
dominant cost and is per-frame independent, so it's fanned out across a
worker pool (cores-1, capped 8); a writer thread reorders and LZW-encodes
sequentially. Uses the `gif` crate directly (already resolved via `image`).
- orchestrator: start_gif_export + render_next_gif_frame (one frame per egui
update), wired into is_exporting/has_pending_progress/cancel.
- dialog: GIF tab + settings; main.rs: handle ExportResult::Gif and pump frames.
- Cargo: opt-level=3 for gif/color_quant/weezl in the dev profile so debug
builds aren't crippled by unoptimized NeuQuant loops.
Together these cut a 10s GIF export from ~1:43 to ~3s.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Linux release ffmpeg is built statically from source, and ffmpeg only
autodetects --enable-vaapi when libva headers are present at configure time.
Neither build path installed them, so every release shipped a static ffmpeg
with no h264_vaapi encoder -- the zero-copy export silently fell back to
software 100% of the time.
- Containerfile + build.yml: install libva-dev + libdrm-dev so the from-source
ffmpeg gets VAAPI.
- build.yml: assert the release binary links libva, so a missing dep can't
silently regress to a software-only build again.
- deb/rpm: libva (libva2/libva-drm2/libdrm2, libva/libdrm) is a hard runtime
dep -- the vaapi-enabled ffmpeg DT_NEEDEDs it, so the app won't launch
without it. The VA driver is a soft recommends (absent it, export falls back
to software): va-driver-all (deb), intel-media-driver/mesa-va-drivers (rpm).
build.rs needs no change: releases link ffmpeg statically (its bundling path
is skipped) and the AppImage is thin, taking libva from the host like libvulkan.
When exporting H.264 with audio, try the gpu-video-encoder ZeroCopyEncoder:
render each frame to RGBA and hardware-encode it into a VAAPI surface
inline, on the encoder's own VAAPI-capable wgpu device — no GPU->CPU
readback, no swscale, no software-encoder thread. Falls back to the
existing software path verbatim when VAAPI/the device is unavailable
(non-Linux, non-H264, or init failure), so it's additive.
- VideoExportState gains zero_copy: Option<ZeroCopyVideo> (encoder + its own
vello renderer + ExportGpuResources + a reused RGBA target, all on the
encoder's device).
- start_video_with_audio_export builds it for H.264 and skips spawning the
software encoder thread when present.
- render_next_video_frame routes to a zero-copy arm that reuses
render_frame_to_gpu_rgba on the encoder's device, then encode_rgba; on the
last frame finish() writes the temp .mp4 and sets video_progress=Complete
so the existing mux runs. video_thread=None makes the mux join a no-op.
Separate export device (vs modifying the eframe device) keeps this contained
to export. Video-only export stays on the software path for now. Runtime
verification (an actual H.264 export) is pending — cannot run the editor in
the dev container.
Implemented foundational pane system using eframe/egui:
- Workspace structure with lightningbeam-core and lightningbeam-editor
- Layout data structures matching existing JSON schema
- All 8 predefined layouts (Animation, Video Editing, Audio/DAW, etc.)
- Recursive pane rendering with visual dividers
- Layout switcher menu
- Color-coded pane types for visualization
Foundation complete for interactive pane operations (resize, split, join).