Skip to content

Case studyPersonal · AI product

Keyline

Every edit, yours or Claude's, is one undo step.

Role
Solo · product, design, front end, back end, AI
Timeline
2026 · 1 week
Stack
TypeScript · Next.js 16 · React 19 · Cloudflare Workers · Durable Objects · D1 + Drizzle · R2 · MCP SDK · Anthropic API · Workers AI (Clef)
Status
Live · free to use
keyline.italik.dev
Keyline: screenshot

Problem

AI can already generate an animation from a prompt. The hard part is the last 10%: "make this card a bit faster", "the bounce feels cheap". Words are a bad interface for timing and easing, and a chat can't be pointed at one element at 2.3 seconds, so people tune motion somewhere else and paste numbers back.

I wanted that loop to be the product: Claude builds, I watch, point at the exact frame and fix the feel by hand.

What I built

  1. 01

    Your Claude, live

    A 31-tool remote MCP server with OAuth 2.1: claude.ai or Claude Code edits the scene while you watch it change.

  2. 02

    Point at a frame

    Pause, select elements and pin a comment to that second; Claude claims it, fixes exactly that and resolves the thread.

  3. 03

    Tune feel without words

    Timing bars and an easing editor with spring sliders and a live loop; copy any move as CSS, Motion or SwiftUI.

  4. 04

    References in, checked out

    Drop images, a brand URL or a video; the browser breaks clips into moves, and a vision model checks the result against your checklist.

keyline.italik.dev
Keyline: Editor and chat
Keyline on mobile: Landing
keyline.italik.dev
Keyline: Motion tuning
keyline.italik.dev
Keyline: Reference with marked details
keyline.italik.dev
Keyline: Inspector
keyline.italik.dev
Keyline: Export in the browser
keyline.italik.dev/dashboard
Keyline: Projects
keyline.italik.dev
Keyline: Landing
keyline.italik.dev/explore
Keyline: Explore

Architecture

Humans and Claude share one write path.

A drag in the editor and a tool call from Claude become the same thing: a batch of ops, validated whole and committed by the project's Durable Object. Claude sees frames from the same renderer the editor and the export use.

  • Code
  • LLM
  • Check
  • Output

System map. Clients: Your Claude, Web editor, Video export. Cloudflare edge · deterministic: MCP server, Project's Durable Object, Chat runner, D1 · R2 · KV, Op validator, Frame renderer. AI: . LLM zone · edits only through ops: Clef-flash, Claude, Clef vision. Connections: Your Claude to MCP server (tool calls); Web editor to Project's Durable Object (ops · live); Web editor to Chat runner (chat); Web editor to Video export (every frame); MCP server to Project's Durable Object (ops); Chat runner to Project's Durable Object (ops); Project's Durable Object to Op validator (validate); Project's Durable Object to D1 · R2 · KV (snapshots); Chat runner to Clef-flash (message kind); Chat runner to Claude (turn + tools); Chat runner to Frame renderer (render_frame); Frame renderer to Claude (PNG frames); Frame renderer to Clef vision (frames).

One question, end to end

“Make the second card bounce in like this reference video.”

  1. 01Code

    The browser turns the clip into moves, an easing guess and contact sheets

  2. 02LLM

    Clef-flash reads the message as a revision: medium effort, Opus

  3. 03LLM

    Claude reads the project overview, the reference sheets and the selected card

  4. 04Check

    apply_ops is validated whole; a bad op comes back with its index and a valid example

  5. 05Code

    The Durable Object commits one undo step and broadcasts it; the card moves live

  6. 06Check

    A rendered strip, the design lint and the Clef checklist confirm the result

  • Every Claude edit is one undo step.

    Atomic batches with exact inverses

  • One renderer for editor

    The same pure renderToSvg

  • One write path for humans and AI.

    Same validator

  • 55 / 57 messages routed right.

    Clef-flash eval · never under-picked effort

Decisions & trade-offs

  • Chose JSON ops on a scene graph over letting the model write animation code

    because Ops can be validated, synced and undone exactly, and they render the same on server and client. Nothing the model writes needs a sandbox.

  • Chose the user's own Claude over MCP over hosting a model and selling credits

    because Generating motion is a commodity and people already pay for Claude. Keyline's AI bill stays near zero, with no markup to explain.

  • Chose one SVG renderer everywhere over canvas, WebGL or a headless browser

    because One pure function gives the same picture in the editor, the browser export and the Worker frames Claude checks. No render servers.

  • Chose a Durable Object per project over a CRDT

    because One authority per scene keeps validation and undo simple. Undo runs on the server, so it works across tabs and reloads.

AI specifics

Models
claude-opus-5-5, claude-sonnet-5-5, Cloudflare Clef and Clef-flash, or your own Claude over MCP
Routing
Clef-flash sorts each chat message into question, tweak, revise or build
Tool use
31 MCP tools, reused one to one as the in-app chat's function calls
Self-checks
Worker-rendered frames, a design lint and a Clef vision checklist against references
Cost controls
Per-turn requests, 1h prompt cache, capped tool results, monthly budgets
Evals
Clef routing 55 / 57, frame detail checks 38 / 40 on real Workers AI

What I'd do differently

I'd design the op format for the model first. My strict schemas made Claude fail whole batches, and errors pointed at expanded ops it never wrote. Now a lenient layer accepts names, aliases and defaults, then maps every error back to Claude's own op index with a valid example.

Results

Live and free with Google or GitHub sign-in. I built it solo in a week, with Claude Code as my coding partner. Clef routing picked the right model and effort for 55 of 57 eval messages. Every chat call is logged with its cost, which is how I found a $3.90 turn and cut it.

Next

Agent-made knobs: named sliders that drive many keyframes at once. Brand import for JavaScript-rendered sites. Lottie and GIF export, then open-sourcing the scene engine.