rustmotion 0.7.0

A CLI tool that renders motion design videos from JSON scenarios. No browser, no Node.js — just a single Rust binary.
Documentation
# Rule: Text that "streams" (tokens arriving)

To depict a model's response being written, **don't use `typewriter`**: a typewriter reveals character by character at a fixed cadence, which reads as a typewriter, not as a stream of tokens. A model emits whole words, in uneven bursts, and each word settles visually instead of snapping in all at once.

```json
{
  "type": "text",
  "content": "Words arrive in uneven bursts, like tokens.",
  "style": {
    "font-size": 40,
    "color": "#E2E8F0",
    "animation": [{
      "name": "char_blur_in",
      "granularity": "word",
      "duration": 0.28,
      "stagger": 0.09,
      "jitter": 0.7,
      "seed": 12,
      "ink_from": "#475569",
      "blur": 6
    }]
  }
}
```

Three fields do all the work:

- **`granularity: "word"`** — the unit is the word, not the letter.
- **`jitter`** — offsets each unit's start by ±`jitter × stagger`. This is what breaks the metronomic cadence. 0.5–0.8 reads as streaming; past 1.0 words overlap and the reading order gets muddled.
- **`ink_from`** — each word starts in this colour and converges to `style.color` over its duration. A desaturated grey reproduces the "not yet accepted by the eye" token.

## `jitter` is deterministic, not random

The offsets are derived from `seed` and the unit's index, never from an RNG. This is a constraint, not a detail: frames are rendered out of order, in parallel, and sometimes in separate processes (`--frames a-b`). A word whose start depended on a random draw would jump between two neighbouring frames.

Changing `seed` reshuffles the rhythm without changing its statistics — useful so two neighbouring paragraphs don't "breathe" identically.

No unit can start before the effect's `delay`: a negative offset on the first unit would make it appear half-animated right from frame 0.

## Budget

`stagger × word count + duration` is the total settling time. For a 12-word sentence with `stagger: 0.09`, that's ~1.4s — check the scene is long enough; `validate` flags it if not.