The rendering pipeline
From per-frame evaluation to ffmpeg, on both the CPU and GPU backends.
Rendering turns a Scene Document into an MP4. It happens one frame at a time, and every frame follows the same two-step shape: evaluate, then draw.
Per-frame: evaluate then draw
- Evaluate. The timeline computes each node's animated properties at frame
n, producing anAnimatedState, and resolves the camera into aCameraState. Simulations contribute their state for framenhere too. - Draw. The camera is projected, and the state is rasterized into an RGBA frame.
Keeping these steps separate is what makes rendering deterministic and seekable β see Determinism.
Two backends
| Backend | Stack | Use it for |
|---|---|---|
| CPU | cosmic-text + swash | The default. Crisp text and code, no GPU needed. |
| GPU | wgpu + WGSL | Shaders and the bloom post-process (--gpu). |
The CPU backend handles high-quality text shaping and rasterization. The GPU backend adds programmable shaders and bloom.
GPU compositing order
When rendering on the GPU, each frame is composited in a fixed order:
background shaders β CPU/content draw β region & overlay shaders β bloomSo a background_shader sits behind everything, region/overlay shaders sample
and modify the drawn content, and bloom is applied last:
Files that made this video
The GPU effects scene: a scene script, one Rust source file, and three WGSL shaders registered in the manifest.
scenes = ["scenes/intro.ccs", "scenes/terrain.ccs", "scenes/pathfind.ccs", "scenes/particles.ccs", "scenes/graph.ccs", "scenes/life.ccs", "scenes/boids.ccs", "scenes/tweens.ccs", "scenes/inserts.ccs", "scenes/edit.ccs", "scenes/edit_source.ccs", "scenes/editor_theme.ccs", "scenes/font_set.ccs", "scenes/remove_styles.ccs", "scenes/morph.ccs", "scenes/shapes.ccs", "scenes/effects.ccs"]
theme = "dark_documentary"
[episode]
title = "How Rivers Form"
[output]
fps = 30
width = 1280
height = 720
[shaders]
aurora = "shaders/aurora.wgsl"
glitch = "shaders/glitch.wgsl"
scanlines = "shaders/scanlines.wgsl"
[transition]
kind = "crossfade"
frames = 18Encoding
Finished RGBA frames are streamed β as raw video β into ffmpeg, which encodes H.264 and muxes any audio into the final container:
RGBA frames β ffmpeg (rawvideo β H.264) β output.mp4--crf and --preset tune that final encode; --format png skips it entirely
and writes frames to disk instead. See the CLI reference.
The whole journey
For where each stage lives in the codebase, see Architecture.