motionspec
v1.0.4
Published
MotionSpec — a formal intermediate language for scroll-driven web motion. A small model writes schema-validated specs; a deterministic compiler emits GSAP/CSS, hallucination-proof by construction with enforced reduced-motion fallbacks.
Maintainers
Readme
MotionSpec
A formal intermediate language for scroll-driven web motion. A small model translates a request into a schema-validated JSON spec; a deterministic compiler turns that spec into GSAP/CSS — hallucination-proof by construction, with an enforced prefers-reduced-motion fallback and a performance budget.
The thesis: capability lives in the catalog, not the model. A bigger model can write more elaborate specs, but it can never emit a primitive, parameter, or selector the Trust Boundary hasn't approved. The compiler trusts only what passes.
request ──> Routing (small model, Stage A) ──> MotionSpec (JSON)
│ cache · 1 repair-retry · escalation │
▼ ▼
telemetry TRUST BOUNDARY (fail-closed)
│
▼
Compiler (no model, Stage B)
│
▼ out/*.motion.js + .cssStatus
| | |
|---|---|
| Version | v1.0.3 · schema frozen at spec v1 (ADR-0001, signed) |
| Published | npm motionspec · MCP Registry io.github.MasterPlayspots/motionspec |
| Tests | 177 green · CI on Node 18/20/22 |
| Catalog | 8 primitives, all device-verified |
| Dependencies | 0 vulnerabilities · SBOM committed · all permissive licenses |
| Coverage | 98.4% lines / 95.9% functions of src/ + worker/ (CI gate fails under 90%) |
| Machine audit | 7.2/10 (Production-Ready), independently re-audited |
| First client | CHS Computer — live on Vercel |
| Hosted MCP | live — private, secret-gated Cloudflare Worker · per-minute cron canary + external heartbeat (synthetic error → email in <5 min, proven) · gated /dashboard |
Schema v1 is frozen: specVersion "1.0" is the stable public contract; "0.1" is deprecated and accepted until v1.2. The [MS-XXX] error-code registry is public API. Phase B (test & security) is closed — CI is green on the x86 runner incl. Playwright e2e for every primitive (all jobs pass on every push to main — see the repo Actions tab; the x86 runner is the source of truth). Phase C (observability + hosted MCP) is live and gate-proven: the MCP server runs as a private, secret-gated Cloudflare Worker; a per-minute cron canary runs validate→compile and pings an external heartbeat, so a failure alerts by email within 5 minutes (verified on real infra). A gated /dashboard renders live telemetry.
Install
npm install -g motionspec # CLI: `motion compile spec.json` writes ./out in your cwd
npx motionspec # start the stdio MCP server (no global install needed)Use it as an MCP server in any MCP-capable agent (Claude Code, Cowork, Cursor, …) — the host LLM authors the spec, the Trust Boundary stays enforced:
claude mcp add motionspec -- npx motionspecListed on the MCP Registry as io.github.MasterPlayspots/motionspec.
Quickstart (from a clone of the repo)
npm ci # install (0 runtime deps beyond MCP SDK + zod)
npm test # 177 tests: validator, compiler-golden, router, fuzz, schema parity, worker contract
node bin/motion.js catalog # primitives + catalog version (16-char hash)
node bin/motion.js compile examples/hero.motionspec.json
node bin/motion.js pipeline "Hero headline fades in, cards staggered" --mock
node bin/motion.js stats # telemetry (model / repaired / cache-hit / escalate)Live model instead of --mock: set MOTION_API_KEY (or OPENROUTER_API_KEY); optional MOTION_MODEL (default anthropic/claude-haiku-4.5) and MOTION_BASE_URL (any OpenAI-compatible endpoint). See .env.example.
Gates (run these — they are the contract)
npm test # full suite, fail-closed trust boundary + golden determinism
npm run coverage # FAILS under 90% lines/functions (src/ + worker/)
npm run catalog-lock:check # ADR-0001 D2: a tightened bound shipped as a "patch" fails here
npm run sbom # regenerate CycloneDX SBOM; then `node bin/license-check.js`
npm run e2e # real-browser Playwright (CI x86 only — the sandbox/ARM cannot run Chromium)MCP server (distribution)
Any MCP-capable agent (Claude Code, Cowork, Cursor, …) can use MotionSpec directly — the host LLM is the spec author, the Trust Boundary stays enforced:
npx motionspec # start stdio server from the published package
claude mcp add motionspec -- npx motionspec # register in a host agentFrom a clone of the repo, npm run mcp runs the same server. Listed on the MCP Registry as io.github.MasterPlayspots/motionspec.
Tools: motion_catalog (primitives + authoring rules) · motion_validate (fail-closed, surfaces deprecations) · motion_compile (deterministic) · motion_stats. Input is size-capped (MS-INPUT-TOO-LARGE, 64 KB). Tested in test/mcp.test.mjs.
Guarantees
- Allow-list — a primitive not in the catalog never reaches the compiler.
- Injection-proof — ids, selectors, string params and triggers are charset-validated; every interpolation is a JS literal (
JSON.stringify) or a CSS-screened raw value. Malicious model output is rejected fail-closed (tested + fuzzed over 6000 random specs). - a11y —
respectReducedMotionis default-on at the compiler level (fail-safe): omittingglobalsor the field yields aprefers-reduced-motionguard. Settingglobals.respectReducedMotion: falseis accepted but emits a compiler warning (MS-GLOBALS-RRM-OFF); a prompt-only instruction is not sufficient to disable the guard. - Determinism — same spec ⇒ identical code (golden-file tests).
- Versioned — schema frozen v1; catalog SemVer enforced by a diff-gate; specs may pin
catalogVersionfor reproducibility (MS-CATALOG-PIN-MISMATCHfail-closed). - Observability — every request logs
model | model-repaired | cache-hit | escalate-*totelemetry/events.jsonl; escalation clusters are the signal for new primitives (concept §3.3).
Layout
schema/ MotionSpec JSON schema (static contract, parity-tested vs validator)
primitives/ catalog: 8 verified primitives (safe templates)
catalog.lock.json released catalog baseline (SemVer diff-gate)
src/compiler/ catalog.js · catalog-semver.js · validate.js (Trust Boundary) · compile.js
src/router/ prompt.js · clients.js (openai-compat + mock) · route.js · cache.js · telemetry.js
src/mcp/ server.mjs (4 tools, fail-closed, input-capped)
bin/ motion.js (CLI) · catalog-lock.js · license-check.js
test/ 177 tests incl. injection attacks, fuzz, golden files, schema parity, worker contract; test/e2e (Playwright)
docs/ ADR-0001 (schema freeze) · ROADMAP_TO_10 · PHASE_A_REAUDIT · CLAUDE_CODE_HANDOFFConcept, research, pitch, business docs and the CHS client site live in the sibling B_MotionSpec/ folder.
Docs
docs/CLAUDE_CODE_HANDOFF.md— start here when continuing in Claude Code (terminal).docs/ROADMAP_TO_10_2026-06-15.md— the production path to a proven 10/10 (Phases A–G, anti-goals, machine gates).docs/adr/0001-schema-freeze-v1.md— the frozen v1 contract and why.docs/PHASE_A_REAUDIT_2026-06-15.md— independent re-audit findings + fixes.
Contributing
Contributions are welcome — see CONTRIBUTING.md for setup, the
gate-driven PR checklist, commit conventions, and a short architecture tour. Bug
reports and feature requests have issue templates under .github/ISSUE_TEMPLATE/.
License
MIT.
