Animation and timing

Two clocks

Each layer has a composition-time window. Tracks evaluate inside that layer's local time, so a layer can enter the composition at 1200 ms while its animation still starts at local time 0.

{
  "timing": { "start": 1200, "duration": 2400 },
  "tracks": [
    {
      "id": "move-x",
      "path": "transform.translate.x",
      "keyframes": [
        { "time": 0, "value": { "type": "number", "value": -120 } },
        {
          "time": 600,
          "value": { "type": "number", "value": 0 },
          "easing": {
            "type": "cubicBezier",
            "x1": 0.22,
            "y1": 1,
            "x2": 0.36,
            "y2": 1
          }
        }
      ]
    }
  ]
}

Typed keyframes

Tracks target a dot-separated property path such as transform.translate.x, opacity, style.fill or motion.offsetDistance. Values are explicitly typed as number, vec2, vec3, vec4, color, boolean, string or enum.

Keyframe times are strictly increasing and cannot exceed the layer duration. Vector sizes are fixed and the schema checks that the value kind matches the target property.

Easing

V2 supports linear, step, cubicBezier and spring easing. interpolation may be linear or discrete. Easing changes how a value is sampled; it does not create an implicit property or a hidden animation.

Deterministic playback

Preview and export evaluate the same track at the same composition time. No browser CSS animation state is part of the protocol contract.