Emulo video

SkillMedia

Use when a brief has to become a film. Turns a one line ask into a Claude Design prompt written in the animations-v3 engine's own language, plus the built piece.jsx and a contact sheet to look at before anyone renders. Covers reference roles, the kit, the storyboard gate, the motion floor, and the verification commands. Do not use for backend work, UI design, or marketing copy alone.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Emulo video skill

What this skill tells your AI

The instructions your AI receives, as published by ohad6k/emulo in skills/video/SKILL.md and read by ahel’s review.

You take a brief and hand back a film. Not a prompt, a film: the prompt that built it, the composition files, and frames somebody can look at.

0. Load the profile before you write a word

  1. Locate emulo.py two directories above this skill; fall back to ./emulo.py only for a direct repo checkout.
  2. Store the resolved absolute path as EMULO_PY, then run python "$EMULO_PY" plugin profile-path --domain video.
  3. If it exits nonzero, give its exact recovery instruction and stop loading personal context. Never substitute a generic creative persona.
  4. Read every returned path completely. First is the core working profile, second is the video profile. Both outrank anything below.
  5. If the repo has videos/README.md, it routes short-form work. This skill owns long-form and commercial film only. A vertical Reel that is a designed film, not a screen recording, is this skill.

1. What you hand back

A folder the person can upload to Claude Design and get a film. That is the deliverable. Not a prompt in a chat message, not a description of a film, not a list of ideas. A folder.

Build it at videos/_kits/<brand>/ in this exact shape, because the shape is what makes it work:

#ArtefactWhy it is there
1PROMPT.mdthe brief. One page, in the engine's language
2START-HERE.mdthe upload order. Which files, in which order, in one message. Without it the person guesses and the guess is wrong
3ATTACH/every asset the film needs, including animations-v3.jsx itself
4frames/reference stills whose filenames carry the instruction
5KIT.mdthe manifest: every file, its pixel size, its known defects

Optionally, and only after the four above are finished: build/piece.jsx plus build/frames/, the film built and rendered locally so you can look at it before anyone else does. That is verification, not the deliverable. A kit with no local build still ships. A local build with no kit does not.

The three things that decide whether the folder works

Ship the engine inside ATTACH/. animations-v3.jsx goes in the folder with the assets. Claude Design needs the runtime it is being asked to write against. Leaving it out is the most common way a good prompt produces a bad film.

Isolated parts, never a screenshot of a whole screen. One object per file, transparent, 1600px minimum on the long edge, plus 4K plates at the film's aspect ratio. A whole screen dropped in is a slab and reads as broken. Claude Design films fail on missing assets, never on prompt length.

Put the instruction in the filename. REF-VERCEL_03_object-became-the-mark.png teaches; ref3.png does not. The person uploading them keeps the names, so every file carries its own lesson into the context.

Name what is missing. Never invent a substitute.

If an asset does not exist, say so in PROMPT.md under its own heading, and say what to do instead. A brief that admits two missing assets is usable. A brief that quietly fakes them produces a film with two broken beats and no way to tell why.

Every prompt contains, in this order and by name

  1. the brief in the engine's language: OM_SCENES, CUES, named Easing
  2. the transformation chain, as match anchors: what becomes what
  3. the asset list, with real filenames, so no beat is blocked on a missing part
  4. the failure conditions for this specific film, not generic ones
  5. the verification commands, so the claim "it works" has an output behind it

A worked example of the whole shape is videos/_kits/claude/: brief, upload order, 31 assets with the official mark split into stackable layers, twelve instruction-named frames, and two missing assets named rather than faked.

2. The engine

animations-v3.jsx is the Claude Design runtime. Read videos/_kits/_engine/README.md once, then work from this table.

Never edit animations-v3.jsx. Its own header says re-running copy_starter_component overwrites it. Every improvement made there is destroyed on the next host copy. The leverage is in the brief.

UseNever use
Easing.easeOutExpo and the named curvescubic-bezier(...), any CSS string
OM_SCENES named sections with durabsolute frame numbers as the structure
CUES.SectionName to key choreographywall clock, setTimeout, requestAnimationFrame
animate({from, to, start, end, ease})(T)useEffect painting anything visible
interpolate([...], [...], ease)(T)CSS keyframes running on their own
<Shot from to> for a hard cutconditional mounting per section
one <CompositionStage> as the only exportable rootthe exportable attribute anywhere else

The model in one sentence: the animation is one element tree rendered as a pure function of one authored time axis, so nothing mounts or unmounts at a section boundary and any object can persist, move or morph across the whole film by ordinary interpolation. That is why this engine suits the work. Zero cuts, one object transforming across the entire film, and the collision law are its defaults instead of things a brief has to fight for.

<CompositionStage width={1080} height={1920} bg="#161309"
                  scenes={window.OM_SCENES} playback={window.OM_PLAYBACK}>
  <Piece />          // ONE component, the whole film
</CompositionStage>
useComposition() -> { T, CUES, time, duration, authoredTotal, playing }

OM_SCENES and OM_PLAYBACK are JSON string literals in plain inline <script> tags of the main document, not type="text/babel", passed through untouched. Every entry needs a desc, one plain sentence, because the user reads it in the timeline popover. Never hand-set nat.

<script>window.OM_SCENES = '[{"name":"Strike","dur":2.5,"desc":"The mark lands and throws green across the ground"}]';</script>
<script>window.OM_PLAYBACK = '{"mode":"loop"}';</script>

Easing, the complete list. linear; easeIn/easeOut/easeInOut for Quad, Cubic, Quart, Expo, Sine; easeInBack, easeOutBack, easeInOutBack; easeOutElastic. Back and elastic overshoot, so they are the game-feel curves and belong nowhere near a logo or an official brand file.

Render from T only. The exporter seeks each frame with a synchronous commit and may serialise the stage the moment the seek returns, so anything painted from an effect or a private animation loop exports stale.

Never render <Captions>. Ohad films the export off his phone and adds his own Hebrew and English. A burned caption ruins that. Locked on-screen copy is a normal element placed where the composition wants it.

Set bg to the film's ground, never the #0b0b0e default, and never #000000. A designed world needs somewhere for light to fall off to.

Define exactly three or four motion helpers up front and use no easing or transform outside them:

MOTION.slam    Easing.easeOutExpo     arrivals and impacts
MOTION.snap    Easing.easeOutBack     chips landing, overshoot capped at 6%
MOTION.drive   Easing.easeInOutQuart  travel, light, drift
MOTION.settle  Easing.easeOutQuart    the final resolve

3. Assign the references. Never average them.

Every reference gets one job and an explicit do-not-copy list. Without the line "do not average the references" the model blends three styles into mush. This is the single cheapest fix in the whole system.

ReferenceIts one jobNever take
videos/vercel-spec/vercel-spec_1920x1080_60fps.mp4transformation, depth, scale contrast, the zero-cut continuous compositionits palette, and never its grey placeholder chrome, which is what the no-kit build produced
Spotify, videos/refnces/motion/Video-53319.mp4camera and easing: three events, the hold, the settleits green, its product
Claude, videos/refnces/motion/oFSdbD1WKeB9fUJJ.mp4monochrome identity, typography, restraintits brand, its interface
videos/_kits/duolingo/the logo built by assembly, and the one-object-huge-on-dark grammarits colour, its mascot

Write it into the prompt in this shape:

Use X as the PRIMARY authority for: pacing, restraint, match anchors, scale
contrast, camera push and pull, depth, the final hold.
Use Y only for: monochrome identity, typography, exact logo, clarity.

Do not copy X's design. Do not introduce X's colour. Do not average the
references.

Read the source. Five films, one engine.

videos/_handoff/_film-sources/ holds the source of five different finished films, all built on the same engine. Read across them. One film teaches you that film; five films on one engine teach you the workflow, which is the thing this skill is actually for.

FileThe film
vercel-film.jsx (49 KB)the spec commercial that got 321 upvotes on r/ClaudeAI
claude-master.jsx (68 KB)the Claude cinematic master, 1920x1080 60fps 20.0s
claude-film.jsx (41 KB)an earlier Claude cut, so you can diff a film against its own revision
film.jsx (62 KB)a third long film
reel.jsx (16 KB) and clip.jsx (5 KB)the same grammar at reel and clip length

Supporting them:

FileWhat it gives you
animations-v3.jsx (55,474 bytes)the engine. Byte-identical in every one of the three source archives, verified by hash. It is a fixed substrate, not a per-film thing. Never edit it
PROMPT-1.md and PROMPT-2.mdthe real prompt pair that produced one of these films. The storyboard-gate prompt, then the build prompt
camera_keyframes.jsonreal camera data from a finished film, instead of invented easing
ui.jsx, tweaks-panel.jsx, support.jsthe host scaffold the films run inside

How to read them, and this is the point. Do not copy one film. Open at least three and ask what is the same in all of them: how a scene list is declared, where the transformation chain is expressed, how an entrance is timed against the thing it hits, how the last three seconds are built, what never appears. The constants across five films are the workflow. Anything present in only one is that film's costume, and copying it is how you get a film that looks like a tribute instead of a piece of work.

Two ratios that hold across them:

Motion budget, roughly 70/20/10. Seventy percent of the movement is the object transforming, twenty the camera pushing or pulling, ten the camera travelling. When a film feels busy but dead, this has inverted and the camera is doing the work the object should be doing.

Build in stages, and gate between them. Build the first five to eight seconds. Render. Look at a contact sheet. Only then continue. A twenty second film built before anyone looked is a twenty second film nobody can fix, because the defect is in the concept and the concept is now load-bearing.

Also in the repo, for the current job rather than the general workflow: videos/_handoff/vercel/reel/Storyboard.dc.html (the largest storyboard that exists), and videos/_kits/claude/frames/, twelve stills whose filenames carry the instruction.

4. Build the kit before you write the prompt

Films fail on missing assets, not on prompt length. The Vercel film was built from an 8,000 word prompt with a camera scale graph, a match anchor chain, an easing table and a frame by frame shot list, and every frame of it is grey rectangles standing in for text and a hand drawn triangle in place of the real mark. The prompt was not too weak. It handed the model nothing real to put in the frame, and placeholders are the only thing a model can draw with no assets.

Claude Code builds the kit. Claude Design animates it. That split is the pipeline.

  1. Measure the reference at 1:1, one file, never a contact sheet. Write down beats, ground colour, mean luminance, mean saturation, and what physically occupies the frame.
  2. Brand intake. Official marks live on the brand's own guidelines subdomain, served gzipped, mixed in with their "Please Don't" examples. Render a light and dark contact sheet and look before naming anything.
  3. Rebuild the product UI as live DOM carrying real strings, then shoot it at 3x to 5x into flat plates with _tools/shoot.mjs. Interfaces are rebuilt. World art is rendered and composited. Nothing is faked.
  4. Cut parts, not screens. A whole screen is a slab, and a slab cannot be animated, only slid. Ship a parts/ folder of isolated transparent objects at 1600px and up: every button, chip, node, bar, tile, badge, icon. Plus 4K landscape plates for the ground.
  5. Split the mark into its own layers. An official SVG splits into layers that stack back pixel perfect. Verify it: stacked against the original, the maximum difference on any pixel should be 1 of 255, which is antialiasing. Then the film assembles the mark instead of cutting to it.
  6. Optimise. Every file under about 350 KB, the whole kit under about 4 MB, so it survives being carried into a Claude Design project.
  7. Open every file and log its defects in KIT.md. Clipped buttons, missing alpha, wrong aspect, white emblems that vanish on a white card. Every defect you found goes in the prompt under KNOWN KIT DEFECTS with what the film must do about it. If you found none, say you opened every file and found none.

Aspect is a real defect class. Rendering 1200x800 chips into a 224x160 box stretches every flag horizontally by 7%, which is subtle enough to survive review and wrong in every frame.

Published artifacts run under a strict CSP that blocks every external host, so nothing in a kit may point at a CDN. Everything is a project file or a data URI.

5. Write OM_SCENES first

It is the outline, and the section names become the cue vocabulary the rest of the brief speaks in. Six sections is a good film. Ten is a slideshow.

The Vercel film, verbatim, as the shape to aim at:

The Blade 4.6 · Aperture 2.0 · Preview 2.0 · Production 2.25 ·
Everywhere 2.25 · Scale 2.25 · Convergence 2.0 · Lockup 1.75

Each desc is one sentence naming a physical event, not a mood. "The triangle becomes an aperture, the camera pushes through it and pulls back into a full product preview" is a desc. "A sense of speed and possibility" is not.

6. The transformation chain, as match anchors

Name the one object that carries the film and forbid breaking it.

Every scene inherits one visible object, shape, line or motion vector from the previous scene. Never: scene fades out, empty background, next scene fades in. The incoming beat is visible while the outgoing is still 25 to 50% visible.

Worked examples from films that shipped:

  • Duolingo. One green circle never leaves the screen: Duo's mark, then the lesson node, then the thing every name collapses into, then Duo again.
  • Spotify. The track Midnight Signal is printed on the player bar file and on the phone file, so the same song moves bar to desktop to phone to lineup.
  • Emulo. The faceless silhouette is on screen at T=0 and in all six sections, and the payoff is the solid robot arriving in front of it so the two together are exactly the shipped mark.

The colour rule that comes with this. An object that will become an official layer corrects to that layer's colour, never to the brand's published one. Duolingo's duo-01-field.svg is filled #50C800 while Feather Green #58CC02 is the guidelines and product value. Correcting to the published green would have stepped colour on the exact frame that must be invisible. The file wins over the guidelines page.

7. The prompt

Fill this. Delete nothing structural. A brief that is long and contains no filenames is the wrong brief.

You are directing a <N> second <vertical|landscape> spec commercial for <BRAND>,
built on the animations-v3 composition engine. Cinematic. Few objects, large, lit.

FORMAT. WRITE IT LITERALLY.

  <CompositionStage width={<W>} height={<H>} bg="<ground hex>"
                    scenes={window.OM_SCENES} playback={window.OM_PLAYBACK}>

<W> wide by <H> tall. If your composition is <wider than it is tall | not
<W>x<H>> you have failed before anything else is judged.

THE ONE LAW

Every object on screen is a file from the list below. The timeline never draws a
<BRAND> screen, never draws the mark, never stands text in with a grey
rectangle, never approximates imagery with a gradient. It places, masks, crops,
lights and moves those files.

If a beat needs an object the kit does not contain, say so and stop. Do not
substitute a div. If you cannot resolve the paths, tell me before building
anything rather than drawing replacements.

REFERENCES

<one job per reference, with a do-not-copy list. Then: do not average them.>

THE ASSETS

  <every file, its pixel size, and one line on what it is for. Name which
   element level parts exist and what they are meant to do on their own.>

THE BAR, AND WHAT IT RULES OUT

<the genre exclusions, not craft notes. Genre exclusions are what the model
already understands: six disconnected slides, a SaaS product tour, a dashboard
montage, a conference presentation, a developer tutorial, a browser screen
recording, a wall of technology logos, a generic futuristic AI advertisement.>

- no paragraphs, no terminal dumps, no reports, no lists of findings. If a frame
  needs more than about eight words to be understood, the frame is wrong
- no charts, no graphs, no dashboards, no code editors
- no neon, no glow, no purple, no gradient meshes, no particle fields

At most ONE object carries text in any frame, and that object is a real thing
with edges, not a caption floating in space.

GROUND AND LIGHT

Measured off the reference film, not chosen:

  frame average sits between <hex> and <hex>, <channel> dominant
  mean luminance <n> of 255
  mean saturation <n>

The base is <hex> and never pure black. One warm key light, <position>, fixed.
Every object carries a contact shadow and a cast shadow. Depth is blur and
scale. Bloom on <named elements> only. One grain pass at low opacity.

LOCKED COPY

  <three or four lines, nothing else>

No feature list, no metric, no URL, no invented tagline, no subtitle under the
logo. Set in <typeface, and say plainly if it stands in for a licensed brand
font>. Revealed through a horizontal mask, never typed letter by letter.

THE ENGINE

<script>window.OM_SCENES = '[
 {"name":"<Name>","dur":<s>,"desc":"<one plain sentence>"},
 ...
]';</script>
<script>window.OM_PLAYBACK = '{"mode":"loop"}';</script>

Key everything to T from useComposition() against those cues. One continuous
composition, zero cuts.

  MOTION.slam    Easing.easeOutExpo     arrivals and impacts
  MOTION.snap    Easing.easeOutBack     landings, overshoot capped at 6%
  MOTION.drive   Easing.easeInOutQuart  travel, light, drift
  MOTION.settle  Easing.easeOutQuart    the final resolve

Nothing eases outside those four. No elastic, no Back curve on an official brand
file, no setTimeout, no requestAnimationFrame, no useEffect painting, no wall
clock, no random, no CSS keyframes running on their own. Render everything from
T so any seek reproduces its frame. Never render <Captions>. Never edit
animations-v3.jsx.

THE ANCHOR

<the one object physically present across beats that carries the film. Name it
and forbid breaking it.>

THE SECTIONS

<one block per OM_SCENES entry. Each block carries:
   what is on screen and which file
   coverage as a percentage of frame width for every hero object
   what causes the next thing to happen
   a "Do not:" line specific to this beat>

CAMERA

<N> events and nothing else moving the frame:

  1. <cue range>   <what>
  2. <cue range>   <what>

Between them the camera holds and the objects do the work. No drifting, no
breathing zoom, no shake, no orbit, no continuous parallax.

Motion budget:
  60% local object and geometric transformation
  20% surface, lighting, parallax, environment
  20% camera scale and reframing

WHERE THE COLOUR COMES FROM

<name the objects allowed to be saturated, and say the ground picks up their
colour. Forbid coloured light with no object making it.>

MOTION SHAPE, MEASURED

<the numbers from §8. State the reference figures and the floor this film must
clear.>

KNOWN KIT DEFECTS

  <every defect you found opening the files, and what the film must do about it>

FAILURE CONDITIONS

<15 to 25 lines, each a specific observable defect for THIS film. §10.>

BEFORE YOU BUILD, RETURN AND STOP

1. the CompositionStage line, so I can see the dimensions
2. the OM_SCENES literal
3. a <N> frame storyboard, and per frame: which asset, its coverage as a
   percentage of frame width, how many elements are moving, and the WORD COUNT
   on screen. Any frame over eight words is a defect, tell me and fix it
4. your impact list with times
5. confirmation the anchor object is on screen in every section
6. anything you cannot verify

Do not animate until I approve.

Then PROMPT-2.md, the approval:

Approved. Before you build, confirm these four:

  <four checks specific to this film, each one a thing that was measured off the
   reference and could quietly go missing>

Now build it from the approved storyboard. Deterministic, keyed to T, kit files
only. When it is running, show me <the cue boundaries> at full size before
anything else.

8. The motion floor, measured

Zero cuts alone reads dead. Cut rate and energy are two separate specifications and a brief has to carry both.

Frame to frame motion energy, sampled at 15fps:

Filmmeanpeakframes above 4.0near-stillcuts
Vercel, the reference2.37813.00522.0%26.2%zero
Duolingo v16.55740.2%zero
Duolingo v2, rejected2.56576.54513.6%50.2%zero

Read the v2 row. Half of that film is frozen. The mean looks acceptable only because a handful of enormous transitions drag it up, and the peak is six times the reference. That is the signature of a slideshow with big transitions between static cards. A motion designer produces the opposite shape: a lower peak and far less stillness, because something is always moving.

The floor to write into a prompt:

  • near-still frames below 26%
  • no single frame above 25 energy
  • frames above 4.0 above 22%
  • at least two elements mid-transformation at every moment that is not a hold
  • a growing hero gains at least 35% of frame width per 0.5s
  • holds are named and counted. Two or three in a film, plus the final lockup

The freeze test. If a frame's motion would survive freezing every gradient in it, the motion is real. A continuously drifting pool or breathing gradient lowers the near-still number without adding one frame of real motion. That is the metric moving, not the film, and we have shipped a bad video that exact way before by optimising the measurement instead of the thing it measured.

Luminance is one film or two. Measured on a rejected build: greetings 19.9, transition 75.1, UI middle 226.2, outro 180.4. A 19.9 to 226.2 span is not a grade change, it is a different film glued between two designed worlds. Name one ground for the whole piece and a ceiling for the brightest section.

Coverage stops things coming out tiny. Hero object 25% to 45% of frame width as a floor, and higher on payoff beats. In the rejected middle the nodes sat at roughly 6%, which is why nothing read and nothing felt like it was moving.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
290
Forks
28
Last commit
Aug 2026
Hacker News mentions
20
Advanced
Catalog kind
skill
Gateway key
video-ohad6k
Source
github.com/ohad6k/emulo