Vite + React + motion/react
Hot reload. Keyboard nav. ?dev=1 for the timeline scrubber. The deck is the artefact — open it in Chrome on the projector and click through with arrow keys.
bun install && bun run dev
# → localhost:5173
a Claude Code plugin · v1.1.0
Cinemorph composes Vite + React decks where every persistent element carries a stable id and morphs cleanly between stages via shared-layout (FLIP) transitions. Watch the same sixteen primitives rearrange themselves below — no per-element animations defined, just eight different layouts of the same source.
Each stage is one entry in a stages.ts file. Sixteen
element ids carry across all eight — no per-element
animation defined anywhere. Framer Motion's shared-layout
algorithm computes every transition automatically.
three production targets, one source of truth
Hot reload. Keyboard nav. ?dev=1 for the timeline scrubber. The deck is the artefact — open it in Chrome on the projector and click through with arrow keys.
bun install && bun run dev
# → localhost:5173
30-second to 5-minute cinematic film. Audio bus mixes a music bed, voiceover, and SFX cues. Smear cuts on real scene transitions. aeBounce on every element that lands with weight.
/cinemorph video --out launch.mp4
Editable PowerPoint with native Morph transitions between slides. For stakeholders that don't ship from a browser. Compatible with Office 2019+ and Microsoft 365.
/cinemorph pptx --out pitch.pptx
the pipeline
--theme < --tokens < --reference < --prompt. Later layers win on fields they provide. Missing fields trigger a clarifying question.
Spawns the claude CLI on PATH. System prompt is agents/morph-composer.md. Emits one JSON object — stagesTs + dataTs.
Vite + React 18 + Tailwind + motion/react. <LayoutGroup> wraps the persistent element layer. Every primitive carries a stable layoutId.
Live deck, MP4 (Playwright + ffmpeg), or PPTX with native Microsoft Morph. One source of truth.
export const STAGES: Stage[] = [
{
id: 'hook',
elements: {
wordmark: { pos: { left: '50%', top: '50%', width: '20%' }, shape: 'wordmark' },
kpi: { pos: { left: '12%', top: '24%' }, shape: 'kpi' },
pillar: { pos: { left: '88%', top: '24%' }, shape: 'pillar' },
},
},
{
id: 'reveal',
elements: {
wordmark: { pos: { left: '50%', top: '14%', width: '12%' }, shape: 'wordmark' },
kpi: { pos: { left: '20%', top: '60%' }, shape: 'kpi' },
pillar: { pos: { left: '80%', top: '60%' }, shape: 'pillar' },
pipeline: { pos: { left: '50%', top: '50%' }, shape: 'pipeline' },
},
},
];
Hook → reveal: the wordmark shrinks and slides up; the kpi and pillar drift outward; the pipeline fades in. One synchronised 700 ms transition. No code per element.
earned the hard way
For 30-second-style films the composer applies eight rules below. Every one was earned by shipping a real video and getting each detail wrong before getting it right.
Writes a single elapsedMs. Phases are non-overlapping windows. SMEAR_MS = 350 cross-fades at boundaries.
aeBounce easingFor elements that land with weight. Dan Ebberts' AE bounce ported to TypeScript.
Never on internal animation events. They lead the visual by 300–500 ms so the sweep + the new scene's snap reads as one cinematic cut.
A stoppedSfxRef: Set<number> ensures each cue's stopAtMs runs exactly once. The single most painful bug in the build.
Minimal transparent click area + 64 px play icon. Pre-warm the SFX pool on first interaction.
-ss seek-mode trapInput-seek (-ss before -i) when trimming with afade. Output-seek can produce silent files that pass duration checks.
Music 0.20–0.25 baseline, ducks to 0.05–0.08 under VO. Whooshes 0.30–0.40, POPs 0.70–0.80, BLIPs 0.30–0.45 tapered, VO 0.85–0.95.
?dev=1 appends a frame-accurate timeline so a reviewer can give precise timestamp feedback during iteration.
starter decks
Generate any of these with /cinemorph new --from-example <name>. Each ships its own brief.md as documentation by example.
install
# into your Claude Code plugin directory
git clone https://github.com/LucasDuys/cinemorph.git
cp -r cinemorph/plugin ~/.claude/plugins/cinemorph
# In a Claude Code chat:
/cinemorph new --from-example cinemorph-about-30s --out my-cinemorph-film
cd my-cinemorph-film
bun install && bun run dev # → http://localhost:5173
# ?dev=1 for the timeline scrubber
Auth is your Claude Code subscription via the claude CLI on PATH.
No ANTHROPIC_API_KEY required.