Skip to main content

buttery

Agent-friendly 2D explainer animations. The scene is a pure function of time: state(t) resolves every property at t, nothing accumulates between frames, every frame renders independently and in parallel.

Pydantic models are the schema. JSON is the product contract; the Python API is sugar over the same models.

Merging two sorted lists, one comparison per beat

examples/merge_sorted.py: the merge is simulated in Python, then each step becomes keyframes.

Red-black tree left rotation, one step at a time

examples/rb_rotation.py: nodes are groups, edges are lines whose endpoints reference the nodes, so the edges follow the rotation for free. The before/after trees are two tuples; the script diffs them.

Agent tool surface   validate / state / preview / render     (tools.py, cli.py, mcp_server.py)
Authoring            Python sugar  <->  JSON                 (objects.py, expr.py, parse.py)
Core                 Scene, primitives, expression DAG       (scene.py, evaluate.py)
Renderer             skia-python, motion blur via sub-frames  (render.py)

Install

pip install buttery    # or: uv add buttery
brew install ffmpeg    # for .mp4 output (PNG sequences work without it)

The renderer is skia-python, which ships large platform wheels; expect a heavier install than the code size suggests.

From a clone:

uv sync                # Python 3.11+, pydantic, skia-python, numpy, mcp
uv run pytest

Python

from buttery import *

dot = Circle("dot", r=0.3, fill="coral")
dot.x = tween(-3, 3, at=0, dur=1.5, ease="out_cubic")
dot.y = 0.2 * sin(6 * T)

ring = Circle("ring", fill=None, stroke="white")
ring.x = dot.ref.x
ring.r = dot.ref.r + 0.5

scene = Scene(duration=3).add(dot, ring, Text("label", content="Hello", y=-1.6))
scene.state(1.0)                       # plain data
scene.preview(1.0, path="p.png")       # quick low-res PNG
scene.render("out.mp4")                # motion blur, all cores, ffmpeg
scene.save("scene.json")               # the same thing as JSON

obj.prop reads the stored expression; obj.ref.prop makes a reference to it (the spec's dot.r + 0.5 became dot.ref.r + 0.5 because a plain attribute read cannot be both a value and a reference).

JSON

{
  "duration": 3,
  "objects": [
    {"id": "dot", "type": "circle", "r": 0.3, "fill": "coral",
     "x": {"op": "tween", "keys": [[0, -3], [1.5, 3]], "ease": "out_cubic"},
     "y": {"op": "mul", "args": [0.2, {"op": "sin", "args": [{"op": "mul", "args": [6, "t"]}]}]}},
    {"id": "ring", "type": "circle", "fill": null, "stroke": "white", "x": "dot.x", "r": "dot.r + 0.5"}
  ]
}

Shorthand strings like "dot.r + 0.5" parse (no eval) into the same op tree. uv run buttery schema prints the JSON schema from Scene.model_json_schema().

Coordinates: world units, origin at center, y up. The frame is view_width (default 8) units wide. Primitives: circle rect line text group. text wraps at max_width and honors newlines. Ops: add sub mul div neg sin cos abs min max clamp smoothstep noise. Eases: linear in_quad out_quad in_out_quad out_cubic in_out_cubic spring. Colors: hex or CSS names; fill/stroke can be tweened between colors.

Agent surface

uv run buttery validate scene.json
uv run buttery state scene.json --t 1.25
uv run buttery preview scene.json --t 1.25 --out p.png --scale 0.25
uv run buttery render scene.json out.mp4 [--no-motion-blur --samples 8 --shutter 0.5 --workers N]
uv run buttery mcp            # MCP server on stdio: same four tools + scene://schema resource

Every call returns {"ok": true, ...} or {"ok": false, "errors": [{"path", "message", "object", "property", "t"}]}. Never a bare stack trace.

Claude Code skill: skill/ (symlink or copy it into ~/.claude/skills/buttery). Register the MCP server with claude mcp add buttery -- uv run --directory /path/to/this/repo buttery mcp. Or from the published packages, no checkout needed: claude mcp add buttery -- npx -y buttery-mcp (the buttery-mcp npm shim runs uvx buttery mcp; see npm/).

Validation and evaluation rules

  • Structural validation is pydantic (unknown fields rejected, arity checked, colors checked).
  • Semantic validation: unique ids (global across groups), references resolve to numeric animatable properties, no dependency cycles, tween key kinds match the property kind.
  • Evaluation compiles each expression to a closure once, walks the DAG in dependency order, and never mutates the scene.
  • Motion blur: samples sub-frames spread across shutter × frame interval, averaged (0.5 = 180° shutter).

Layout

src/buttery/
  expr.py        AST models (Op, Tween, Ref), operator overloading, sugar (T, sin, tween, keyframes, ...)
  parse.py       shorthand parser -> AST, constant folding
  objects.py     Circle, Rect, Line, Text, Group
  scene.py       Scene, semantic checks, state(t)
  evaluate.py    compile + topological evaluation
  render.py      skia rasterizer, motion blur, parallel render, ffmpeg
  tools.py       validate / state / preview / render (JSON in, JSON out)
  cli.py         `buttery` command
  mcp_server.py  MCP server
examples/        bounce.py, squash_bounce.py, merge_sorted.py, rb_rotation.py (Python) and their .json, launch_demo.json
skill/           Claude Code skill
tests/

Not in v1

Equations/LaTeX, 3D or cameras, GUI, audio, plugins, manim parity.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

buttery-0.2.0.tar.gz (2.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

buttery-0.2.0-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

File details

Details for the file buttery-0.2.0.tar.gz.

File metadata

  • Download URL: buttery-0.2.0.tar.gz
  • Upload date:
  • Size: 2.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for buttery-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9cf1b1f4d45eafe704cd67e7ba1ce60caea01dbac67eef8fcf9c2e34a06fb6c5
MD5 2643ee3cb319d06886d383c0017e90ad
BLAKE2b-256 cf053d90da9cb076fa5397ec834f3238d752df22839a45aef1d9143675ca5691

See more details on using hashes here.

Provenance

The following attestation bundles were made for buttery-0.2.0.tar.gz:

Publisher: publish.yml on fletchgraham/buttery

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file buttery-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: buttery-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 32.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for buttery-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e84fce24490f72b87cf8cebf9bda75fa4629a8714bd74e20a64ee6319e800a06
MD5 aad8728732705b7571b50005506fe2cf
BLAKE2b-256 304bc33128e5f72929e2a3e9df8b7d8fd15e84d79ed3369a7fbdf71b1da0f3b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for buttery-0.2.0-py3-none-any.whl:

Publisher: publish.yml on fletchgraham/buttery

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page