Docs
Everything the renderer understands today. See WHAT.md in the repo for the module-level design and for which attributes parse but have no effect yet.
Compositions are trees of custom elements. The renderer parses them into a typed program, resolves durations, compiles an ffmpeg filter graph, and returns an MP4. A vi-track is a lane; a vi-group is a run of things in one.
| ELEMENT | DESCRIPTION | ATTRIBUTES |
|---|---|---|
| vi-composition | Root. The output surface and frame rate. One per document. | width, height, fps, background |
| vi-group | A run of things in one lane, played in order. The layer a bake freezes. | id, start, start-after, end, duration, bake |
| vi-track | A lane. Parallel layers on one clock — a shot is a track, and so is a music bed. | id, start, start-after, end, duration, bake |
| vi-video | Picture. duration="fill" stretches it to the slot a rigid sibling decided. | src or id, cut, duration, loop, fit, scale, x, y, rotate, crop, speed, opacity, fade-in, fade-out, z |
| vi-image | Still picture. Same transform surface as vi-video. | src or id, duration, loop, fit, scale, x, y, rotate, crop, opacity, fade-in, fade-out, z |
| vi-audio | Sound. A music bed is one of these beside a scene, never an attribute on it. | src or id, cut, duration, start, gain, volume, fade-in, fade-out, muted |
| vi-text | Typeset text from a fixed utility vocabulary — sizes, colours, safe areas. | id, start, duration, class, z |
| vi-transition | Sits between two siblings in a group and blends them. Its absence is a smash cut. Fade only today. | type, duration |
| vi-gap | Time with nothing in it. Cutting to black for two beats is a shot. | duration |
| vi-captions | Specified, not rendered yet. Emitted by the audio it sits inside. | class, lang, word-timing, src |
| vi-animate | Specified, not rendered yet. Interpolates one property of its parent. | property, from, to, duration, delay, ease |
A scene, a bed timed against it, and a title card
<vi-composition width="1080" height="1920" fps="30" background="black">
<vi-group id="sc1">
<!-- The voice-over is rigid, so it sets the shot's length.
The picture fills it, looping seamlessly if it is shorter. -->
<vi-track id="sc1-01">
<vi-video src="intro.mp4" duration="fill" loop="crossfade" />
<vi-audio src="line-1.m4a" fade-in="0.2s" />
</vi-track>
<vi-transition type="fade" duration="0.5s" />
<!-- An insert: push in on the eyes. -->
<vi-track id="sc1-06" duration="1.5s">
<vi-video src="eyes.mp4" duration="fill" scale="1.8" y="-12%" />
</vi-track>
</vi-group>
<!-- The bed is its own lane, timed against the scene. -->
<vi-track start="sc1" end="sc1">
<vi-audio src="bed.m4a" duration="fill" gain="-16db" fade-out="2s" />
</vi-track>
<!-- Title card on top. Higher z draws above earlier layers. -->
<vi-track start="sc1" end="sc1">
<vi-text class="title-serif text-white safe-center" z="10" duration="fill">
TERM SHEET: ROMA
</vi-text>
</vi-track>
</vi-composition>