Getting started
site-motion turns your design tokens and a few lines of copy into an animated scene. Each scene is one HTML file that plays live on your site, and the same file renders frame-exact to MP4, WebM, animated WebP, GIF and a poster.
Install
Needs Node 22+, Chrome and ffmpeg. There is no npm install.
git clone https://github.com/Shivraj97/site-motion
cd site-motion
node bin/site-motion.mjs list
As a Claude Code skill: clone it into your skills folder, then ask Claude in any project, for example “use site-motion to make an approvals animation in our brand for the homepage”.
git clone https://github.com/Shivraj97/site-motion ~/.claude/skills/site-motion
Your brand: tokens
Tokens are the only source of colour and type. Draft them from your live site, then correct anything by eye:
node bin/site-motion.mjs theme https://yoursite.com --out brand.json
With Chrome installed, it measures your rendered page: the colours that cover the screen, your main button, your logo, and the fonts your text actually renders in. Add --fast to read only the HTML and CSS, --scheme dark to measure your dark mode, or --shot page.png to see the screenshot it measured. Licensed fonts get a free Google Fonts stand-in, named in its notes.
Or write them by hand. Six colours are required; everything else is derived when missing.
{
"color": { "paper": "#f4f5f1", "surface": "#ffffff", "ink": "#121411",
"muted": "#6a6f66", "line": "#d6d9d1", "accent": "#5bd96a" },
"palette": ["#c8efcb", "#8fb4ff", "#f1c6f6"],
"font": { "sans": "'Inter', sans-serif", "mono": "'JetBrains Mono', monospace",
"import": "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=block" },
"radius": { "sm": 6, "md": 12, "lg": 20 }
}
| Token | Used for |
|---|---|
paper, surface, ink |
the ground, panels, and text |
muted, line |
secondary text and hairlines |
accent |
the one colour that means “this is happening” |
palette |
categories: tools, sources, steps. Short palettes are extended with tints of your own colours |
optional positive, warning, faint, raised, accentInk, onAccent |
derived when you leave them out |
optional font.display |
headline type; scenes fall back to font.sans |
Your words: content
Every scene has a content.json of defaults. Pass only the keys you change; they deep-merge.
node bin/site-motion.mjs init ledger-stamp --tokens brand.json # writes ./brand.json and ./ledger-stamp.json
node bin/site-motion.mjs make ledger-stamp --tokens brand.json --content ledger-stamp.json
Use your product’s real nouns and numbers. For third-party brands in a scene, use fictional names.
Your look: one style across every scene
Tokens set the brand. A look (a style pack) sets how things are drawn and move: line weight, elevation, corners, texture, colour mode, label and type voice, easing, tempo and a recurring motif. Scenes copied into your project with add share one look, held in site-motion.json, so the hero, feature and pricing animations match.
node bin/site-motion.mjs add ledger-stamp # first add: writes site-motion.json, locked to ledger-stamp's look (Ink)
node bin/site-motion.mjs add card-story # follows Ink
node bin/site-motion.mjs style set soft-ui # change the look for the whole site…
node bin/site-motion.mjs sync # …and rebuild every scene you added
For a whole site, plan first: plan --brief brief.md (your sections, one line each) or plan --url https://yoursite.com maps every section to one scene in one look and draws a contact sheet of the set. Swap any pick with plan swap <slot> <scene>, then plan apply adds them all.
Your own components can wear the same look. style export writes it as a Tailwind v4 @theme (so shadow-md, rounded-md, ease-signature and your colours match the scenes), plain CSS variables, W3C design tokens (DTCG) or a section for your DESIGN.md:
node bin/site-motion.mjs style export --format tailwind --out app/look.css
node bin/site-motion.mjs style export --format design-md --out DESIGN.md
To check that a set still reads as one site, score --project measures every scene you added and names the odd one out, and lint --project flags raw values in your scene copies that the look can’t reach.
The five looks are ink, soft-ui, outline, dimensional and field; see each one at /sets/ink. Make your own in the Studio: it gives you a short code such as sm1.0020000000001 that works anywhere a look name does (--style, site-motion.json). native keeps each scene’s own look. A scene only follows the parts of a look it was built for, and the rest stays as drawn.
Product demos
A product demo is your product’s screen rebuilt in the browser: a cursor does one job, the camera follows it, and the result lands. Every label, number, cursor move and camera move lives in content.json, so you change the demo without touching code. There are three ways to make one, from fastest to most custom.
1. Re-skin a demo. Pick the demo closest to your flow, add it, and rewrite its content: your product name, screen labels, the numbers (make them add up), and when the cursor arrives and clicks.
node bin/site-motion.mjs add agent-checkout --tokens brand.json
# edit motion/agent-checkout/content.json (public/motion/ if you have a public folder), then refresh its preview
2. Start from a screenshot. Faithful to your pixels, nothing to rebuild. shot reads the screenshot’s colours into tokens and writes a ruled grid. You name the hotspots on it (the field, the value that changes, the button), then script the edits, cursor and camera in content.json.
node bin/site-motion.mjs shot screen.png --name acme --url acme.com/billing
node bin/site-motion.mjs make shot-demo --content shots/acme/content.json --tokens shots/acme/tokens.json --formats mp4,png
3. Build a new screen. When nothing fits, ask Claude with the skill installed. It builds the screen from the UI kit (browser, window, phone and terminal frames; buttons, rows, charts, toasts; a cursor and a camera) and follows the demo rules: one action, one result, 10–16 seconds.
Use site-motion to make a product demo of our invoice approval flow, in our brand,
for the features section. One action: approve an invoice in two clicks; the balance updates.
Size and playback. --view crops the demo for where it sits: the default 1600×900 hero, strip beside copy, card in a grid, compact in a phone column. --play once plays when it scrolls into view and stops on the result; --play hover rests on the result and plays while hovered.
node bin/site-motion.mjs build agent-checkout --tokens brand.json --view card --play once
Check before you ship. rehearse runs every check (framing, text that doesn’t fit, one-frame jumps, the loop seam, contrast) and writes contact sheets at the shown width and at phone width. It must end with rehearsal passed.
node bin/site-motion.mjs rehearse agent-checkout --tokens brand.json
Five demos are open source: click-to-done, dashboard-push, phone-stack, shot-demo and agent-checkout. Demos tagged Pro can be watched and themed on this site, and ship with site-motion Pro.
Render
node bin/site-motion.mjs build <scene> --tokens brand.json # one HTML file, plays live
node bin/site-motion.mjs render out/<scene>.html --formats mp4,webm,webp,png,sheet
node bin/site-motion.mjs make <scene> --tokens brand.json --formats mp4,png # both
| Format | Use it for |
|---|---|
html |
an <iframe> on your site: scales to its container, pauses offscreen, shows a still under reduced motion |
mp4, webm |
<video autoplay muted loop playsinline> |
webp |
anywhere a GIF would go, at about a third of the size |
gif |
email and old tools only |
png |
the poster |
Scenes with an intro play it once, then loop seamlessly; --range loop exports only the loop.
Re-theme a live embed
Any built scene accepts a theme in its URL, so one file can wear many brands:
ledger-stamp.html?tokens=<base64url of your tokens JSON>
ledger-stamp.html?style=sm1.2201001001020 # a look, by its code
An embedding page can also drive playback with postMessage: { type: "sm:play" }, "sm:pause", "sm:restart", or { type: "sm:seek", t: 4.2 }. The scene answers with sm:time messages.
How scenes work
A scene is setup() once and render(t) every frame, and render may depend only on t. That is what lets one file play live and also export frame-exact: the exporter seeks headless Chrome to each frame time, screenshots, and encodes with ffmpeg. Physics is simulated once and baked; loop seams are measured, not eyeballed. The repository’s RENDERERS.md covers SVG, Canvas, p5.js, Matter.js, shaders and CSS 3D, and SKILL.md is the full guide, including how to write your own scene.