A MotionDoc is Blinn’s open animation document. It is produced by the Figma plugin (Figma Motion → MotionDoc) and consumed by @blinn-motion/core. The format is intentionally small, time-based (seconds), renderer-agnostic, and human-readable enough to hand-author for tests.
Design goal: anything the engine can play, the Figma converter can emit — and the format stays readable. See the full schema for every field.

Top level

Layers nest

A layer’s base position is relative to its parent’s box (top-level layers are relative to the stage). Children inherit the parent’s animated transform — exactly like the DOM. That nesting is why a card can move and its badge moves with it.

Tracks animate one property

Each track drives a single normalized property over the base value. The op decides how the sampled value combines with the base:
Multiple tracks can target the same property — they compose in order over the base. That’s how a spring entrance and a hover offset can stack cleanly.

Keyframes hold a value at a time

  • t is absolute time on the timeline, in seconds.
  • v is a number, a [x, y] vector, a "#RRGGBBAA" color, a boolean, or a string.
  • easing governs interpolation from this keyframe to the next (out-interpolation, like CSS transition-timing-function). The last keyframe’s easing is ignored.
Before the first keyframe the value is held; after the last keyframe it is held. So a track only needs keyframes where something actually changes.

A complete tiny example

This is a real, playable MotionDoc — a card that springs up and fades in while a badge spins.
card.motion.json