Element reference

September 14, 2026 · View on GitHub

camelCase composition elements map 1:1 onto entities. Lowercase DOM vocabulary is valid only inside <html> content.

Structure

ElementWhat it is
<stage>The infinite canvas, and the only valid root. Holds <scene> children, and loose nodes parked beside them.
<scene>A clipped, playable frame; owns the timeline its children sit on. Only under <stage>, never nested.
<group>Container with a transform; auto-fits its box and its span from its children. No size and no fill of its own.
<sequence>Track-like container for back-to-back clips, and where transitions are declared. No transform of its own.

Nodes

ElementWhat it is
<rect>A rectangle. Takes paints, strokes, shadows and effects. With mask it clips its parent instead of drawing.
<text>Text; its children are the glyphs. Sizes itself to them unless given a box.
<textRange>A style override over a run of the parent <text>'s glyphs, by character index.
<video>A video clip: a rect whose intrinsic paint is the media src names.
<image>A picture: a rect whose intrinsic paint is the media src names.
<audio>A clip with a sound and no picture; on the canvas, a waveform box.
<captions>A styled, timed transcript of the enclosing scene (or of a transcript file).
<adjustmentLayer>Draws nothing; its transform composes onto the clip directly below it, for as long as its own clip lasts.
<html>A rect whose paint is real, reactive HTML drawn into the box by the browser.
<surface>A rect whose paint is a canvas your ref draws into, sampled every frame.

Paints

Children of a node, stacked in document order over its intrinsic fill. See paints.md.

ElementWhat it is
<solidPaint>A solid color; what the fill prop is shorthand for.
<linearGradientPaint> / <radialGradientPaint>A gradient; takes <colorStop> children.
<colorStop>One gradient stop. Valid only inside a gradient paint.
<imagePaint> / <videoPaint>Media painted into another element's box — a rect or a text filled with a picture.
<htmlPaint>The paint form of <html>.
<surfacePaint>The paint form of <surface>.
<shaderPaint>A WGSL fragment shader over the media paint below it, or procedural where there is none.

Styles and motion

Sub-entity children of the node (or paint) that holds them. See styles.md, animations.md, keyframes.md.

ElementWhat it is
<stroke>An outline of the parent's box or glyphs. Several stack.
<shadow>A drop shadow beneath the parent's silhouette. Several stack.
<effect>A CSS-style filter over the parent's rendered pixels. Several stack.
<animation>One preset in/out animation of the node holding it.
<keyframeTrack>The keyframes of one prop of the element holding it.
<keyframe>One keyframe of the track holding it.

User-defined components are ordinary Solid components; they compose the elements above and carry no runtime cost. Only the elements above produce entities.

Coordinates and sizing

  • Coordinates are pixels relative to the parent's box, origin top-left. No percentages, no layout keywords; explicit numbers until the layout engine lands.
  • x and y default to 0. Size defaults are per element, not inherited from the parent:
ElementDefault box
<video>, <image>, <adjustmentLayer>1920 × 1080
<scene>required — the frame's own size
<rect>, <html>, <surface>100 × 100
<audio>500 × 150 (the waveform box on the canvas)
<rect mask>500 × 500
<text>fits its glyphs
<captions>the preset's — it lays out the caption block against the scene's frame
<group>, <sequence>fits its children
  • A <text> given neither width nor height sizes itself to what it says; giving it either fixes the box and wraps into it.
  • <group> and <sequence> never take a size: theirs is the union of their children's.
  • How media pixels map into the box is controlled by objectFit (default "cover"), never by the box itself. A generated asset's placeholder therefore always has a definite size, even before the asset exists.

Common props

Every node accepts:

PropTypeDefaultMeaning
idstringstampedHow the element is addressed — by the editor writing back to it, by capture, by syncTo. Written into your source if you leave it out (see module.md).
refSceneNode variable or (node: SceneNode) => voidnoneSolidJS-style ref; receives the element's node when it is created. For <surface>/<surfacePaint> the node's element is the backing canvas (see surface-paint.md).
namestringnoneHuman-readable node name; what labels the node in the editor.
x, ynumber0Position relative to the parent, px.
offsetX, offsetYnumber0Render-time translation on top of x/y, px; moves the drawn content without changing the layout box (the channel the slide animations drive). Subpixel values are kept.
width, heightnumberper elementBox size, px — see the table above.
keepAspectRatiobooleanabsentLocks the box to its authored proportions: resizing one bound (an editor handle, a layout row) drives the other so the ratio width:height has is kept — or, with neither authored, the ratio the box currently has.
constrainX"left" | "right" | "center" | "stretch" | "scale""left"How the element follows its scene's frame when that frame is resized, horizontally — see below.
constrainY"top" | "bottom" | "center" | "stretch" | "scale""top"The same vertically.
rotationnumber0Rotation in degrees.
scalenumber1Uniform scale about the box origin. Overrides scaleX/scaleY while set.
scaleX, scaleYnumber1Per-axis scale.
opacitynumber101; out-of-range values clamp, like CSS.
cornerRadiusnumber0Uniform corner radius, px.
cornerRadiusTopLeft, cornerRadiusTopRight, cornerRadiusBottomRight, cornerRadiusBottomLeftnumbercornerRadiusPer-corner radius, px; a corner without one takes cornerRadius, so cornerRadius={20} cornerRadiusTopLeft={0} rounds three corners.
blendModeBlendMode"sourceOver"How the element composites over what is below it: the canvas blend modes, camelCase — multiply, screen, overlay, darken, lighten, colorDodge, colorBurn, hardLight, softLight, difference, exclusion, hue, saturation, color, luminosity.
hiddenbooleanabsentExcludes the element from rendering (and its audio from the mix) without removing it: it keeps its place in the timeline and its children.
start, end, sourceIn, sourceOutTimesee timing.mdTemporal placement.
playbackRatenumber1Speed multiplier for the node's local time (see timing.md).
transitionTransitionSpec | nullnoneTransition into the next clip; direct children of <sequence> only (see transitions.md).

Props are animated by <keyframeTrack> children naming them; preset in/out effects are <animation> children. No prop takes keyframes inline.

Constraints

constrainX and constrainY say what an element does when the frame it sits in is resized — a scene taken from 1920×1080 to 1080×1920, say. Nothing else reads them: a constraint moves nothing at the moment it is written, only the next time the frame changes size.

ValueconstrainXconstrainY
"left" / "top"Keeps its distance from the left edge — where an element with no constraint stays.The same from the top edge.
"right" / "bottom"Keeps its distance from the right edge, so it travels with it.The same from the bottom edge.
"center"Keeps its position relative to the middle of the frame.The same vertically.
"stretch"Holds both margins, so the element is resized by the frame's width delta.Holds the top and bottom margins, resizing its height.
"scale"Position and width take the frame's horizontal ratio, so the element keeps its share of the frame.The same vertically.

Editor state

Three more props are written by the editor and read back on the next mount. They are not part of the composition — nothing rendered or exported depends on them — but the source is the document, so a row resized in the timeline has nowhere else to be remembered:

PropTypeMeaning
selectedbooleanWhether the editor has the element selected. Absent means not.
clipHeightnumberHeight of the element's row in the timeline, px. Absent means the common row height.
expandedbooleanWhether the timeline shows the element's keyframe rows below its clip. Absent means collapsed.

Write them or delete them freely; the editor rewrites its own.