Skip to main content
A Motionly project is a storyboard — an ordered list of scenes. Each scene owns its components, its camera, its background, its own timeline, its audio, and its duration. The top-level timeline shows the storyboard and nothing else, so it stays readable whether the project has five objects or five hundred.
Selecting a scene opens that scene’s timeline. Detailed animation lives inside a scene; the storyboard above it is about structure.

Scenes are organizational boundaries, not animation boundaries

This is the rule that separates a motion graphic from a slideshow. Nothing is cleared at a scene edge. A component that exists on both sides of a boundary keeps its identity and transforms across it. Only components that are genuinely leaving get an exit, and only genuinely new ones get an entrance.

Writing a storyboard

Declare the scenes, then put objects in them.
Scenes run back to back unless you give a start, and a scene with no duration takes an even share of whatever canvas time is left. You never author absolute time: reordering two scenes is a list move, not a retiming pass over hundreds of delays. If the storyboard is longer than the canvas, the canvas is extended to fit it.

Scene properties

Why a scene has no window by default

A scene root is given a start — the time origin its children are measured against — and deliberately not a duration. The engine culls a child once its ancestor’s window closes, so writing the scene length onto the element would clear the composition at every edge and put the slideshow back. The length still exists; it lives on the storyboard, where the strip, the pacing, and the boundary planner read it. It just is not a cage. Components that genuinely leave are animated out at the boundary; components that persist simply persist. Add clear when you actually want the old behavior.

Membership

scene NAME on any object — text, image, component, layout, showcase — puts it in that scene. An object that already declares a parent (a layout slot, a group, a showcase part) keeps it; the scene is then its ancestor. Timing inside a scene is scene-local. A delay of 0s on a member of the third scene means the start of the third scene, not the start of the film.

Shared components

Give a component that recurs the same identity:
Motionly then detects the two as one logical component and the boundary between their scenes becomes a handoff. Reusing the same element name across scenes works too — identity exists so a component can change name, size, and role and still be recognized.

Scene relationships

Every scene knows its previous and next. That is what lets Motionly plan a boundary from both sides, and it is why continuity does not need to be hand-wired.

Boundaries and participation

At every boundary each component is classified:
Shared components hand off, exits move out, arrivals move in as a wave. A component that already carries its own motion is never given a second entrance.

Transition kinds

There is no fade. Fading the frame is what makes generated video feel like a slideshow, and the doctrine forbids it: transform between shots, never dissolve. Inference is usually right, because the storyboard already knows whether something is shared. Override only when it is wrong.

Beats inside a scene

Scenes organize; beats change focus. A scene long enough to hold several turns of attention can carry beats inside it — the camera reframes the persistent composition without clearing anything.

AI generation order

The AI is directed to build structure before animation:
  1. Storyboard — how many scenes, what each is for, how long
  2. Scenes — one scene block per storyboard entry
  3. Contents — the components in each scene
  4. Shared identity — which components recur
  5. Boundaries — how each cut is crossed, derived from step 4
  6. Animation — only now, and only inside a scene
src/ai/storyboard-director.ts derives steps 1-5 deterministically from the project’s duration and assets and hands the model compilable scene blocks, so the two things it gets wrong most often — absolute timing and membership — are removed from its job.

Migrating an old project

A project written before scenes existed is one long composition. migrateToScenes lifts it into a storyboard without touching a single animation: auto picks beats, then segment, then single. The migration is idempotent and returns an AST, so the user reviews an ordinary .motion diff. Old projects still compile untouched: the storyboard pass only engages for a project that declares scene membership or storyboard intent.

Auditing a storyboard

npm run inspect:motion reports structural problems at the level they now live at:

Where the code lives

Scenes lower to the engine’s existing scene element kind, which already owns a background, a per-scene camera with depth parallax, an enter/exit envelope, and parent-local time evaluation. The renderer, the evaluator, and the .motion format are unchanged.