Skip to content

Example: plain text

No manifest row · built today as betta-plain-text

Typed copy with nothing behind it: brand-blue bold text sized to its own content, left-aligned, optionally tilted, sliding up and fading in. The docx's "a component that's just typed text, no background box behind it at all".

flowchart TB
    subgraph scene["scene-plain-text"]
        T["plain-text<br/>text · absolute · content × content<br/>slideFade from bottom"]
    end

The document

{
  "id": "scene-plain-text",
  "durationInFrames": 75,
  "layers": [

    // ── One layer, both axes "content": the POINT shape. Hugs its ink, never wraps, never
    //    shrinks. No `anchor` is authored, so the text infers it from its alignment: left →
    //    top-left, and x/y are the top-left of the ink box.
    {
      "id": "plain-text",
      "type": "text",
      "zIndex": 0,
      "layout": {
        "mode": "absolute",
        "16:9": { "x": 120, "y": 120, "w": "content", "h": "content" },
        "9:16": { "x": 120, "y": 320, "w": "content", "h": "content" },
        "1:1":  { "x": 120, "y": 120, "w": "content", "h": "content" }
      },
      "typography": {
        "16:9": { "family": "GT Eesti Display", "weight": 700, "size": 60, "color": "#054F8E",
                  "horizontalAlign": "left" }
        // "9:16": …, "1:1": …
      },
      "props": { "content": [ { "value": "Your text here" } ] },
      "animations": [
        { "animation": "slideFade", "params": { "from": "bottom", "distance": 40, "durationInFrames": 12 },
          "at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 0 } }
      ]
    }
  ]
}
Bound field Control
plain-text.props.content[0].value text
plain-text.typography.*.color colour
plain-text.layout.*.rotation degrees

What the engine does with it

Resolve. One slideFade expansion into a y track and an opacity track.

Solve. Both axes "content", so measure runs unconstrained and the box is the ink extent of the one run. The inferred top-left anchor puts that box's corner at (120, 120).

Animate. A translate and an opacity on the node's own matrix; nothing depends on it.

Place. One positioned span.

What this shows

  • The simplest possible layer exercises the same pipeline as the lockup: measure, an inferred anchor, a named animation, a matrix.
  • Anchor inference. horizontalAlign: left with no anchor reads exactly like today's x/y; center would put x at the ink's centre, which is what a centred headline wants.

Stress points

  1. Anchor inference from alignment only covers the horizontal tier. Coordinate System & Sizing → The anchor grid says an unset anchor on text "infers from the authored typography alignment"; horizontalAlign gives left/centre/right but the vertical tier (top/baseline/…) is only implied. State it: verticalAlign top|middle|bottom maps to top|centre|bottom, default top.
  2. A tilt on a content-sized layer changes nothing about its box. Correct by the resting-box rule, but the built component rotates about the ink centre and so does the brief — consistent; noting only that a rotated point-text's extents for a future background are the unrotated box pushed through the matrix, per The Motion Graph. Nothing awkward otherwise.