What does longtake do?
Based on onetake by Patrick, modified for vertical (9:16) short-video platforms. What changed and why:
CHANGES.md. Vertical method:references/vertical.md.
Short motion films about a product, built from the product. Not a video editor, not a slideshow
generator: a composition (one HTML file, window.__seek(t)), a move library (lib/motion.js),
footage recorded from the real thing, a sound palette that shares one room, and an oracle
that says whether the cut has a rhythm and whether it carries, before a human has to watch it.
Six films taught it. motion-web took three cuts: one and two were rejected as "PPT-style one-by-one display" for a uniform cadence — the rhythm half. Pocket Weather Club had the rhythm and was still PPT: its v1 passed every rhythm check and was rejected, because each beat replaced the one before. v3 was accepted when every beat grew out of the last — the character lands on the headline, the page grows out of its card, a stage opens from the character. That is the carry half. One dot added the operator: with a still camera it was "just missing nimble tracking camera moves"; with a camera that chases what each beat frames — lagging, leaning, settling — it was "camera moves, lens and physics all fine". knockon carried by cause: a light tabletop machine where every beat is the collision that starts the next. clearing carried by scale: one take from a year to a free half hour and back, a camera that chases the anchor on screen so it lands the same at 1× and 300×. overlap was the meaning lesson: its first cut was "nice art but not clear what it means", and adding labelled cursors made it worse; it read only once the idea was built into the artwork — an & hidden in two noise plates that appears at the instant the passes come into register. Everything here exists so the next film starts where those films ended.
What the protocol cannot give you (read first)
The rules below are mostly rejections written down: they keep a film from being a slideshow. They are a floor. A film can pass every rule and every oracle leg and still be dead — W1 (a vertical promo, 2026-11) did: carry 1.00, VERDICT PASS, and the verdict was "very rigid, didn't reach 70% of the reference". What it lacked is what the accepted films had:
- Material worth looking at in every beat. The onetake launch film (the usual reference) is v8: three prompts, each becoming a complete designed mini-film in its own palette and motion language. The viewer watches work, not labels about work. Ask first: what is the most beautiful thing we own (footage, finished films, real UI)? Build the film out of that, full frame. A concept that explains a process with cards and chips is a diagram, and a diagram moved well is still a diagram.
- A clock. Every strong case cuts to a music grid — sends on downbeats, the fastest stretch on the drop, a stop on a silent beat. Without narration, music is the timeline, not decoration. Timing beats by "long enough to read" gives an even pace that reads as stiff. If the user's project forbids music, say what that costs and ask.
- An arc. Density and speed build toward one peak, then release. Five equal stations is a list.
- Change as the content. In the reference the thing itself transforms (a window reflows into a phone, a bar opens into a film). Motion that only travels between static beats is transitions around slides.
- Rounds of looking. The reference took eight reviewed cuts. Show stills of the hook and the peak before the first render and a draft before polishing; never present one unreviewed pass as final.
When this skill, and when not
- A launch / teaser / intro clip for an app, a page, a skill, a feature — yes.
- A narrated feature demo (30–60 s) that shows the product being used, possibly in several languages — yes:
rebuild the UI instead of recording it (§4,
references/product-demo.md). - The user has a reference clip they want the feel of — yes, start at §1.
- Long-form, talking-head, editing existing footage with transitions — no.
- The user names HyperFrames or Remotion explicitly — use what they name. Otherwise this pipeline.
The protocol — in this order, no skipping
1 · Deconstruct the reference before touching anything (hard rule)
python3 scripts/analyze_ref.py ref.mp4 --out ana/ # energy map, cuts, stillness, contact sheets, motion line
Read the energy map and the sheets and write down the numbers the film has to match. The energy map says when
the film moves; the motion: line says how —
median t80 (snaps or S-curves) and smear (rendered with motion blur or not). What decided the motion-web film:
the reference was 34 % dead-still, had 7 hard cuts in two bursts, and kept every element small with a
lot of white space. None of that is obvious from watching once, and a film built without measuring it came
out on a uniform cadence — twice. references/reference-deconstruction.md.
The reference's numbers outrank the genre rules below. "Small elements, big ground" and "still a third of the time" were measured from motion-web. The onetake launch film is ~10 % still and mostly full frame; W1 followed the genre rules against it (still 0.50, empty ground) and came out empty and slow. Write down still %, how much of the frame is filled, cut count and where the densest stretch sits, and match those. Also note what the reference's beats are made of (finished designed pieces? real UI? type?) and whether it cuts to music — that is §2's input.
2 · Concept — three central ideas before any beat sheet (hard rule)
A concept is one sentence about the picture, not the product: the single idea the film is made of. Write three that differ in that idea — not three stories told with the same cards:
- one element transforms through everything — a dot is the caret, splits into the skill list, hollows into a loading ring, unrolls into a spring curve, lands as the dot on the i of the wordmark;
- one camera move through scale — start inside the caret, pull out to the input, dive through the send button
into the work, come out through the finished film (
cases/clearing-15s: a year → one day → a half hour → back); - a before/after split — the same beats as a slideshow on the left and carried on the right, until the right side breaks into the left;
- a chain reaction — every beat is the collision that starts the next (
cases/knockon-15s); - or a physical metaphor, one continuous surface, a typographic system…
For each: the hook frame, what carries every boundary, what it rules out (no cards? no cuts?), and its look —
a preset from looks/ (python3 scripts/look.py sheet → gallery/sheets/looks.png: paper, dusk, tabletop,
ultramarine, riso, ember, each measured from an accepted film), the product's own colours
(look.py from-shot shots/*.png --out look.json), or one made for this film. Show the three and let the user pick.
The template's story — kinetic words → typed prompt → ticking checklist → result → staccato
hits → black wordmark — is one concept, never the default: an operation demo built on it passed every oracle leg
(carry 1.00) and was sent back as "looks a lot like motion web… no creativity". The same holds for the examples in the list
above and for every case: picking "one dot" because it is the first example is copying, not a concept (W1 did, and
read as a diagram). Test each concept with two questions: what is the viewer looking at in the busiest second?
(it must be something beautiful, not a label) and what does the thing itself turn into?
Vertical (9:16) films are not landscape films rotated: the frame is a tall column, so fill it top to bottom,
let material run off the edges, and keep the platform's safe zones (captions and buttons cover the bottom ~20 %
and the right edge). stills.py --width 1080 --height 1920 keeps the aspect in its sheet. The method, with the
nested-portal dive and its numbers: references/vertical.md, case cases/huazhong-dongtian-22s/.
3 · Storyboard as rhythm and carry
Write the chosen concept as a beat sheet: t · beat · what moves · what is still · what carries into the next beat.
Rhythm. Vary shot length by ≥ 4× (0.25 s words next to 2.5 s holds). At least one stretch of near-silence in picture and sound. One story — the concept's — not a catalogue. Element size and ground follow the reference (§1).
Arc and clock. Pick the music before the beat sheet, find its downbeats, its silent gaps and its drop (scripts/beat_grid.py), and write every t in the sheet as a beat of that track. The peak of the picture sits on the drop.
Carry. At every section boundary, name the thing that survives it and moves: the hand, the subject, a
container that becomes the next scene (morphRect), a stage that opens from the subject (iris), a camera that
pushes into a card until it is the scene (zoomThrough), a cast that folds into the lockup (gather → seal).
If nothing survives, it is a slide change, whatever the rhythm. Bare cuts belong to bursts of hits and the end
card, when the concept has them. references/rhythm.md.
4 · Footage from the real thing — or the UI rebuilt from screenshots
python3 scripts/record_footage.py footage.json --out footage/
Real pages, driven in real time by Playwright (wall-clock-paced sweeps, wheel steps, clicks), recorded at the size you will show them, with a magenta marker injected the instant the input starts so the action frame is findable afterwards. Frames come out at 30 fps as JPEG; the pointer path is saved so the composition can draw the hand back in — the viewer must see the cause, not just the effect. Config format in the script's docstring.
Or rebuild it. When the film walks through an app's features (and above all when it has a voice or other
languages), the user screenshots or records only reference takes, and the UI is rebuilt in HTML in the reference's
own pixel frame. Every string lives in a table, every state is written by a pure set(state), and the replica sits
on the plane where the camera can close in at any zoom. Highlights are measured from its DOM (lib/ui_kit.js).
Narration comes from scripts/vo_tools.py: audition, lines, word times, subtitles. A second language is ?lang=
on the same comp, its VO mapped onto the authored timeline by UIK.timeWarp knots on words that mean the same
thing, checked pixel-identical for the source language with scripts/frame_diff.py. The content stays the product's
real output. Method, numbers and what bit: references/product-demo.md. It is a technique, not a look: palette,
stage, camera grammar and transitions are chosen fresh in §2 every time.
5 · Compose — one file, pure functions of time, moves from the library
mkdir -p cases/my-film && cp templates/comp.html lib/motion.js cases/my-film/ # the template loads motion.js → window.OM
python3 scripts/probe.py my-film/comp.html # as soon as it plays end to end: what carries each boundary, each move's curve
Pick moves by looking at gallery/sheets/<move>.png — six frames over the speed curve of what moves. The library
has 39: entrances, carries, contact and live sims, camera and its projection helpers, and a fluid set (a light field, ripples, silk, a belt, SwiftUI springs); each is a function of time returning numbers for a DOM
transform or a canvas call. Never re-derive a spring or an ease with fixed constants. The template is the
motion-web film (kinetic words, typed prompt, ticking checklist, fly-throughs, live sims, a hold, staccato hits,
one continuous hand path every sim reads from) — copy its beats only when that is the concept picked in §2;
otherwise keep its contract and helpers and write the concept's own beats. Everything is f(t); sims are pre-simulated once at 240 Hz and
sampled. Preview ?play, pin ?t=6.4&hud. references/motion-library.md, references/composition.md.
The look ships with the comp. python3 scripts/look.py apply ember cases/my-film/comp.html (or a look.json)
writes look.js beside it: the eight colours as CSS variables and LOOK.color, three OFL faces subset to the glyphs
the comp sets and inlined, so the file:// render gets real type. Load it before the comp's script, write against
var(--ink) / var(--display) or LOOK.font('display', 96), and chain window.__ready on LOOK.ready. Re-run it
after copy changes; it names any character a face lacks (--cjk <font> for Chinese / Japanese / Korean).
Camera: keyed, but operated. OM.camera(t, keys) puts the camera where each beat needs it; the feel of an
operator comes from how the keys are placed: key the subject ~0.1 s ahead on sineInOut to follow it, key the landing
point before a snap on expoInOut to whip to it, add a hand (a slow two-sine float, zero in the holds) and OM.shake
on every landing. Draw a faint OM.lattice farther back, or on an empty ground the move doesn't read. With a camera,
__track returns screen boxes (OM.projectBox), __motion hands render.py the travel, and __meta.inFrame names
what must never leave the frame. The method, with code: references/composition.md → A camera.
6 · Render — 1080p30 drafts, 4K60 only after acceptance
python3 scripts/stills.py comp.html --times 0.7,2.4,3.8,6.2,9.9,12.7 --out stills.png # look before you render
python3 scripts/render.py comp.html --out draft.mp4 --sfx sfx.wav # 1920×1080 · 30 fps · 180° shutter
python3 scripts/render.py comp.html --out film.mp4 --final --sfx sfx.wav # 3840×2160 · 60 fps, once the cut is accepted
The shutter is real motion blur: each moving frame is several seeks across the open shutter, averaged in linear
light; holds are detected and skip it. A capture is a Chrome screenshot (~150 ms; the page itself draws in under 1 ms),
so render.py runs --workers browsers in parallel processes (default cores − 2, ma
…
[truncated for translation]
7 · Oracle — pass before you show
python3 scripts/oracle.py comp.html --ref ana/ref_energy.csv --out oracle.json
The oracle returns a JSON with the following scores (0–1, compared to the reference):
- rhythm: whether the shot length and pacing match the reference's energy map
- carry: whether the film's beats flow into each other (0.86 for the onetake launch film, 0.68 for W1)
- stillness: how much of the film is quiet/still, compared to the reference (0.17 for 34% stillness)
- fill: how much of the frame is filled with content vs. empty ground
- motion_curve: whether the speed curves (t80, smear) match the reference
- verdict: PASS if all scores are ≥ 0.6, otherwise FAIL with notes
Run it on your first draft, not at the end. The oracle is not an editor; it checks what the reference does. If it fails, go back to §1 and re-measure the reference: you missed something.
When it passes, show the stills and the draft to the user before polishing. The oracle verdict is for the maker,
not the viewer. references/oracle.md.
8 · Polish and ship
- Audio: mix the music and the oracle-approved visual timeline with
scripts/sfx.py(sound effects mapped to key moments: landing, open, hit, fade). Narration goes in here if the demo has it, aligned to word times fromscripts/vo_tools.py. - Titles:
scripts/titles.py comp.html --lang en --out subtitles.vttfor platforms that support open captions (or hard-code them into the comp withvar(--display)andLOOK.fontfor Chinese platforms). - Format: export from
draft.mp4(1080p30) to platform-spec: 9:16 for 小红书 / 抖音 / 视频号 (addffmpeg -i draft.mp4 -vf "crop=1080:1920" final.mp4), or leave at 16:9 for YouTube / Bilibili teasers. - Final: run
scripts/render.pywith--final --workers 8for 4K60, then upload. The comp is the source of truth — keep it alongsidefootage/,look.js, andoracle.jsonincases/<my-film>/. Tag the git commit.
How to run a review
- Show three still frames: the hook, the busiest second, the peak.
- Play the draft once with sound, then once without (for movement awareness).
- Ask: "What is this film about?" (If the answer is not the concept from §2, it failed.)
- Ask: "Where did you look?" (If the answer is a label or a box, the material isn't filling the frame.)
- Ask: "Did anything feel even?" (Even=stiff, a sign that rhythm wasn't varied enough.)
- Show the oracle JSON alongside the draft — it is a tool, not a verdict.
Directory structure
longtake/
├── CHANGES.md
├── SKILL.md
├── lib/
│ ├── motion.js # 39 moves (window.OM)
│ └── ui_kit.js # UI rebuild helpers
├── scripts/
│ ├── analyze_ref.py # energy map, cuts, stillness, contact sheets, motion line
│ ├── beat_grid.py # music downbeats, gaps, drop
│ ├── record_footage.py # Playwright recorder
│ ├── probe.py # move analysis
│ ├── look.py # colour extraction and application
│ ├── stills.py # still frame extraction
│ ├── render.py # compositing with real motion blur
│ ├── oracle.py # evaluation against reference
│ ├── sfx.py # sound effect generation
│ ├── titles.py # subtitle extraction
│ ├── vo_tools.py # narration audition, lines, word times
│ └── frame_diff.py # pixel comparison
├── templates/
│ └── comp.html # composition template (motion-web story)
├── references/
│ ├── vertical.md # 9:16 method
│ ├── rhythm.md # rhythm and carry reference
│ ├── reference-deconstruction.md # how to measure a reference
│ ├── composition.md # composition deep dive
│ ├── product-demo.md # narrated feature demo method
│ ├── motion-library.md # move library reference
│ └── oracle.md # oracle scoring reference
├── cases/
│ ├── huazhong-dongtian-22s/ # nested-portal dive case
│ ├── clearing-15s/ # scale-through case
│ └── knockon-15s/ # chain-reaction case
├── looks/ # colour presets (paper, dusk, tabletop, ultramarine, riso, ember)
├── gallery/
│ └── sheets/
│ ├── looks.png # look presets visual sheet
│ └── <move>.png # move curve visuals
└── scripts/
└── __pycache__/ # Python cache (generated)
Credits and license
Based on onetake by Patrick. Modified and extended by bobobo2026.
License: MIT (see LICENSE file). The original onetake protocol is Apache 2.0; changes and additions are MIT.
See CHANGES.md for a full diff from onetake.