cinematic-shot
Shoot software UI like a film. A sequence of hero shots, each a steep, oblique, extreme close-up of the interface floating in black, with a razor-thin focal plane, a slow motivated camera drift, and UI that acts on its own, hard-cut on the action, ending on one line of copy and a
Install
npx skills add https://github.com/dzhng/skills/tree/main/skills/graphics/cinematic-shot
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install dzhng-skills@llmmart
git clone https://github.com/dzhng/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole dzhng/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Cinematic shot
You are the director and the DP, not the motion designer. The film is a sequence of hero shots. Each one looks at a real piece of the product's UI from a steep, low angle, so close that the focal plane covers only a line or two of text and everything else melts into black. The camera drifts slowly toward where the next thing will happen. The UI does the work by itself: things get typed, streamed, selected, and written while we watch. Nothing explains itself with captions.
This skill is about camera, framing, light, and the edit. Build the film with any rendering stack. Whatever you choose, make every frame a pure function of time, so the film renders deterministically and can take motion blur.
Read references/look.md for exact camera, depth-of-field, light, reveal, and type recipes. Read references/shot-list-example.md for a full example of the shot grammar.
For a ~15 second promo video made in code from a landing page (a continuous 3D fly-over of the page ending on a title card with the brand, logo mark, a two-part closing line, and an optional track), follow references/landing-page-promo.md.
The taste
A black void. The product floats in it like a dark slab, tilted away from the camera, lit by a soft pool that follows whatever matters and lets everything else fall into black. The camera is low and close, looking along the UI rather than at it, so lines of text run diagonally across the frame and shrink into the distance. The focal plane is a thin band: one control, one line of typing, one row of a list is sharp, and the rest is soft bokeh. The camera never stops drifting and never moves fast. Shots are long enough to watch something happen. The only colour is the product's own. Restraint everywhere else.
1. Find the story before the shots
Before planning a single camera, write down:
- The flow: the 4–7 things that happen on screen, in order. Examples: open a view, select a tab, type a prompt, watch the answer stream in, watch a document write itself, approve.
- The payoff: the one moment where the product visibly does something remarkable. The film exists to reach this frame.
- The demo content: concrete, believable data inside the UI, such as names, IDs, statuses, code, and short human-sounding text. Real-looking density is what makes a close-up beautiful. A list of twelve plausible issues reads as a product; three grey placeholders read as a mockup.
- One line of copy: the product or feature name, then a tagline of five words or fewer.
2. Write the shot list
Post the shot list before building, then keep going:
| # | Cut at | Len | Subject (what is in focus) | Scale | Angle | Move | Action |
|---|
Rules:
- Length: 45–55 s in all, with 8–10 UI shots, then the copy and the logo.
- Shot length follows the action. Process shots (typing, streaming, a document writing itself, a long diff) run 5–9 s. Punctuation shots (a tab, a button, a nav item) run 2–3.5 s. Alternate the two, so a long watch is followed by a short accent. Median about 5 s.
- Cut on the action, not on a metronome. There is no beat grid. Cut in when the subject is already in frame or about to arrive; the action starts within 0.3–0.8 s; hold the result for 0.5–1 s; cut while the camera is still moving.
- One idea per shot. A shot can contain a short chain (type → send → the reply starts) only if the camera follows one continuous thread.
- Vary scale like an editor. Extreme macros and macros dominate. Medium shots carry the longer process. Hold back the wide shot (the whole window, near-frontal) for the payoff, where it lands like a release. Return to a close-up after it.
- Alternate the diagonal. If the text in one shot rises to the right, the next shot's text falls to the right, or the plane tilts the other way. Every cut should read as a new camera position.
- No continuity cursor. The UI acts on its own (see section 4). The viewer never needs to follow a pointer between shots.
- Separate surfaces get separate setups. When the story moves to another surface (a terminal, a phone, another app), give it its own slab in the same black void and hard-cut to it.
Shot scales
Measure scale as magnification of the UI at the focal point, relative to its native size:
| Scale | Magnification | Use for | Depth of field |
|---|---|---|---|
| Extreme macro | 5–7× | A single tab, a button, a nav item, a status badge. One or two words fill a third of the frame. | Only the subject is sharp. Everything else is heavy bokeh. |
| Macro | 2.5–4× | A composer with a line of typing, a few rows of a list, a code hunk | A band 2–4 text lines deep is sharp |
| Medium | 1.5–2.5× | A panel at work: a list streaming in, a document writing itself, a diff with a sidebar | A wider band is sharp; the far edge and near edge stay soft |
| Wide | 0.8–1.1× | The payoff only: the whole window, near-frontal, with content scrolling or changing | Mostly sharp; the frame edges still soften |
Macro shots must stay crisp. Rasterise the UI at the resolution of the magnification (for example 6×) before the camera scales it. Never upscale a 1× bitmap.
Camera angle
This is the signature of the look. Except for the wide shot, the camera is low and oblique, looking across the UI plane:
- Tilt the plane back 30–50° (pitch), so the far side of the UI recedes and the near side looms.
- Rotate it in-plane 10–20° before tilting, so lines of text run diagonally. Flip the sign between consecutive shots.
- Add a little yaw, ±5–15°, so one side of the frame is closer than the other.
- Use a short-ish perspective so the foreshortening is obvious: near text should be about 1.4–1.8× the size of far text in the same frame. A perspective distance of about 0.6–0.75× the frame width works (1100–1400 px at 1080p).
- The wide shot is the exception: near-frontal, pitch 8–12°, no in-plane rotation, yaw within ±3°.
- Framing: crop aggressively. The slab's edges run off frame or fall into black. Leave generous black: a quarter to a half of the frame is often the void, or UI so far out of focus that it reads as texture.
Camera move
Each shot is one continuous move. It is motivated: the camera drifts toward where the next thing will appear.
- Track along the reading direction of the action: 3–10% of the frame width over a typical shot, up to 20–35% for a long pan along a diff or a document.
- Follow content as it grows: when an answer streams downward, drift down with it; when a line is typed, drift with the caret.
- Push gently, a 1–5% scale change over the shot. Pull-outs are rare.
- Turn slightly, 0.5–4° of roll or yaw change over the shot.
- Speed: constant (linear) velocity, or a short ease-out arrival over the first third that then continues at a slow constant drift. The camera never eases to a full stop and is still moving at the cut. No handheld noise, no shake.
- Rack focus with the action: when attention moves from the typed line to the reply, or from a title to the body, slide the focal band there over 0.4–0.8 s.
3. Light and grade: a black void
Every shot must look like it was filmed on the same stage. Values are in references/look.md.
- Stage: true black around the product. No gradient wallpaper, no coloured haze, no floor.
- Subject light: a soft, neutral pool on the subject, not the frame. The UI falls off to black within roughly a third of the frame width from the focal point. The pool lies on the UI plane, so the tilt foreshortens it and the roll lays it along the diagonal. It is longer along the line of action, has a hot spot nudged toward an off-axis key (the key side flips with the diagonal), and sometimes has one side cut by a soft flag. It trails the subject by a beat, slides with a rack focus, and opens up as content grows and at the payoff. It is never a centred circle that looks the same in every shot. There is no coloured key light.
- Low key: the average frame is very dark (about 7–10% luminance). Bright pixels are reserved for in-focus text and the product's own coloured UI. Anything bright and out of focus gets dimmed.
- The product is a dark slab: its own chrome, rounded corners, and a faint 1 px edge highlight on panels. Keep the real UI faithful; do not restyle it.
- Colour belongs to the product: status icons, diff greens and reds, a brand-coloured primary button. Add no accent of your own: no flares, no glows, no rings, no tinted light.
- Finish: motion blur (180° shutter, 4+ sub-frames) and fine film grain on the final render. Together with the depth of field, these three do almost all the work.
4. Motion inside the shot
- No cursor. The UI acts on its own. A nav item highlights. A tab's selection pill slides over. A button depresses. A gutter control appears on a code line and the line highlights. If a click must read, show it through the control's own pressed or selected state.
- Typing: 12–13 characters per second with a visible caret. Code identifiers and file references turn into inline chips as they are typed. On send, the composer clears and the message moves into the thread.
- Streaming: generated text resolves line by line, top to bottom. Each line arrives as a fine stipple of dots that condenses into solid glyphs over about 0.5 s, staggered by about 0.1 s per line. Icons and avatars resolve the same way.
- Writing: documents and diagrams build in order: a title, then a heading, then paragraphs; diagram nodes, then connectors drawing on, then labels.
- Scrolling: in medium and wide shots, the content may scroll smoothly under a drifting camera. This is the second layer of motion, and it should feel like reading speed.
- Appear: new panels and messages fade and rise slightly through a small blur on an ease-out of 0.3–0.5 s. Nothing pops with overshoot.
- No impact effects. The payoff is shown by scale (the wide shot) and by the amount that changes, not by shake, flashes, or rings.
5. Ending: copy, then a still logo
- Leave the last UI shot with a hard cut to black, or a quick 0.4 s blur-and-dim into black.
- The copy: one centred line on black, about 80–100 px at 1080p, weight 500, tracking about −0.02em, white. It arrives by un-blurring from about 16 px while fading up over 0.6–1 s. Either set the whole line at once, or set the product name first and then append the tagline on the same line, letting the line re-centre as it grows. A faint soft glow behind the type may settle away as it sharpens; nothing sweeps across it. Hold for 3–5 s.
- The logo: cut or short-dissolve (about 0.3 s) to the still logo, either the mark alone or mark and wordmark, about 110–120 px tall at 1080p, in plain white. It does not move, pulse, or glow. Hold it for 4–5 s and end the film on it.
Add no CTA buttons, URL cards, or "available now" banners unless asked.
6. Sound
There is no music: no score, no drone, no beat, no risers, no braams, and no tonal stings. The soundtrack is quiet, tactile foley over near-silence.
Every visible action gets a cue: a soft key tick per typed character, a soft click when a tab or item is selected, a quiet whoosh on send, and a faint granular hiss under streaming text. The payoff gets no impact. The copy and the logo play over silence.
Don't
These make a film look like a tutorial or a template:
- Cold opens, title cards, or "Introducing…" and "New in…" screens before the action.
- Keycap overlays, captions, callout arrows, or labels that explain the UI.
- A visible mouse pointer driving the action, or a cursor travelling between targets.
- Flat, frontal close-ups. Outside the wide payoff shot, the camera looks across the UI, not straight at it.
- Everything in focus. If the frame has no bokeh, the shot is too wide or the focal band is too deep.
- Dissolves or dips to black between UI shots. The UI shots use hard cuts only.
- Fast moves, slow orbits, big 3D rotations, swooping fly-throughs, camera shake, or a camera that eases to a stop.
- Cutting to a grid. Two-second shots back to back read as a sizzle reel; let process shots breathe.
- Restyling the product's UI to look "cinematic". Keep the real UI faithful, and get the cinema from the camera, the focus, and the light.
- Anamorphic flares, glow, accent rings, coloured key light, or any colour the product does not already have.
- Light that moves across the frame: sheen bands, sweeps, or light bars travelling over the UI. The light follows the subject; it does not perform.
- A light pool that is a screen-space circle, centred and identical in every shot. It reads as a black overlay with a hole in it, not as light on the slab.
- An animated logo reveal.
- Music of any kind, including a score, a beat, a drone, risers, braams, or bells.
7. Verify like a DP
Render a still at the middle of every shot, at each action's peak, at the payoff, and at the copy and logo frames. Judge each one as a frame grab from a film:
- There is exactly one sharp subject, and the eye lands on it in under half a second.
- The focal band is thin, with both near and far bokeh, except in the wide shot.
- The plane reads as tilted: text runs diagonally and visibly shrinks into the distance.
- Text in focus is legible at half resolution.
- At least a quarter of the frame is black or near-black.
- Consecutive shots differ in scale or in the direction of the diagonal.
- Every frame shares the same black level, neutral light, and grain, but the pool's shape changes with each camera: foreshortened, stretched along the action, and lit from one side.
- Pick the strongest frame as the poster.
Iterate until every still could be a screenshot in a launch post.
Files (skills)
-
references
-
landing-page-promo.md 6.9 KB
# Landing-page promo prompt A ready-to-run brief for a ~15 second promo film made entirely in code from a landing page: a single continuous 3D fly-over of the page, ending on a title card with the brand, logo mark, a two-part closing line, and an optional track. Use it when the user wants a short promo video from their landing page. Follow it as written: ask for the inputs, capture the page, show the stills, then render. ```text <inputs> Ask me for: my landing page link, my brand name and logo mark, a two-part closing line (a statement, then a short italic tail), and a 15 second track (optional). </inputs> <direction> A 14.5 second 3D fly-over of my landing page, 1440x1152 at 60fps. The page lies flat on a bright studio floor (#f9fbfb in the middle, #f2f3f6 in the corners) with a soft wide shadow around it and 24px rounded corners. One continuous camera, never a cut: it starts low over the hero and glides backwards down the page at one steady speed while looking up it, rises straight overhead to show the whole page as one strip, dives into the hero and lands it as a card under a two-line title. Focus is razor thin in front of the subject and almost none behind it, so everything near the lens melts. Cards float a little above the page with soft shadows; photos, chips and the testimonial lift off and stand up toward the lens as the camera passes them. Four small tiles of my logo lift off beside the hero button and stay with the film until the end card. The title is Geist 500, the italic tail Instrument Serif. Banned: cuts, crossfades, stops or surges in the glide, the camera turning or swinging sideways, zooming in and back out, glows, any text laid over the page before the end card. </direction> <structure> 14.5 seconds: flight 0-8.2s, rise 7.75-9.25s, overhead 9.25-9.47s, dive 9.47-9.97s, title card 9.97-14.5s. The camera 56° off straight-down and 1360px from the point it looks at, centred on the top half of the hero, the phone or product mockup sharp, four 32px logo tiles beside the button → 0-0.6: the glide eases in from rest → 0.1-1.35: the tiles lift, grow to 140-200px and hang just outside the page's top corners while the hero's chips rise to 60-80px and stand up 30° → 1.25-1.6: the glide doubles to cruising speed as the hero falls behind → 1.6: the second section's title passes the centre of the frame, its photos blurred near the lens → 1.35-2.7: that section's main photos lift to 100-130px and stand up 46°, two of its chips fly up to about 200px, stand up 54° and pass the left and right edges at 2.5 → 1.2-2.4: the tiles trail the camera 300px down the page, then drift out of the top → 3.0-7.3: every following section passes through at the same steady speed, each one sharp as it crosses the middle of the frame and soft below it; a logo tile drifts past the left edge close and blurred at 5.4 → 5.45-6.3: the testimonial card rises from 22 to 112px, stands up 30° and shows a 34px white edge → 7.3-8.2: the glide eases off as the footer arrives, the footer title sharp at 8.0 → 7.75-9.25: the rise, zooming out at an even rate while the tilt flattens (8.15-8.95) and the page's bottom edge settles 42px above the frame bottom → 9.25-9.47: the whole page as one centred strip, creeping 3.5% closer → 9.47-9.97: the dive, the page's top edge pinned to the frame top while it grows, everything below the hero fading out, then the top drops to y 283 so the hero lands as a 1018px wide card with 38px corners and a soft shadow; two logo tiles sit on its top corners, one crisp at the right edge, two huge soft blurs drift in at the bottom corners → 10.02: a white badge pill (logo + brand, 21px) fades in at y 44 → 10.12: line 1 at 74px, one word every 0.06s → 10.36: the italic tail at 82px in grey #8b8b92, one word every 0.05s, each word rising 16px out of a 12px blur in 0.34s → 10.6-14.5: hold, the card creeping 2% closer, the tiles drifting a few px. </structure> <build> 1. Open my link in headless Chromium (Playwright) at 1440px wide, device scale 2, and scroll to the bottom once so lazy images and scroll animations finish. Mark the pieces that lift (cards, phone or product mockups, chips, feature photos, the testimonial, the hero button) with data-layer. Screenshot the full page with them hidden, then each piece alone on a transparent background with 28px padding, and save every piece's page position to a JSON. 2. One WebGL2 film page, 1440x1152, every frame computed from time inside seek(t): no timers, no CSS transitions. The page is a textured quad on the floor and each piece its own quad at its height, drawn lowest first with no depth buffer. Use mipmaps and 16x anisotropic filtering or the far text shimmers. 3. Drive the camera from one speed curve, never from a position key every half second. Focal length 1880px, 56° tilt, distance easing out from 1360 to 1700px and never back in, no turning. Speed down the page as a share of cruise (cruise is about 770 page px/s): 0 at 0s, 0.5 by 0.6s, held at 0.5 to 1.25s, 1.0 by 1.6s, held between 0.94 and 1.1 to 7.3s, then easing to 0.12 by 8.3s. Integrate it into the page position. 4. Depth of field per pixel: blur radius = 75 x (focus - depth) / depth in front of the focus and 6 x (depth - focus) / depth behind it, capped at 120px, 40 taps on a golden-angle disc, each tap read from a mip level matched to the blur. Keep the focus on whatever crosses the middle of the frame. 5. A lifted piece stands up by turning about its own middle, top edge rising toward the lens. Each casts a shadow on whatever is under it: the same picture in flat #1a2133, offset (0.10z, 4 + 0.36z), blurred 7 + 0.5z, 26% opacity. 6. Rise: zoom out in log scale with a smooth trapezoid speed (speeding up 7.75-8.35s, even 8.35-8.95s, slowing to a stop at 9.25s) and hand the glide over to a camera that holds the page's bottom edge at that 42px line from 8.3 to 8.65s. Dive: log scale on a quadratic ease in-out, then solve the look-at point from the pinned edge. A rounded-rect mask morphs from the full page to the hero, 24px to 38px corners. 7. Render with Playwright on the real GPU (--use-angle=d3d11 --enable-gpu --ignore-gpu-blocklist): 60fps, 16 subframes across 0.7 of a frame for motion blur, H.264 MP4. The track's hit goes on 9.97s, whooshes on 8.66 and 9.80. </build> <gotchas> If you can't run code on my computer, tell me straight away that you can only make a live preview here and that the MP4 needs Claude Code. Phones or cards that fade out with transparency show whatever is behind them, so fade them into the haze colour first and only cut to transparent at the very end. Keep most lifts tiny (20-40px) and lock the page before timing anything, because any change in a section's height shifts everything after it. Before the final render, measure a quick 30fps preview with optical flow: the speed down the page must never dip and the zoom must never turn into a zoom-in during the flight. </gotchas> <start> Ask me for the inputs, capture my page, then show me stills at 0, 1.6, 2.5, 5, 6.5, 9.3 and 11 seconds before you render. </start> ``` -
look.md 12.3 KB
# Look recipes These are the exact values behind the look. They are written as CSS where CSS is the most direct way to describe them. Port them to whatever renderer you use. Pixel values assume a 1920 × 1080 frame; scale them with the frame height. ## Stage ```css background: #000; /* a true black void: no wallpaper, no haze, no floor */ ``` The product's own dark chrome is the only surface. Everything that is not UI is black. ## Camera Put the UI on one plane inside a perspective camera. Rotate in-plane first, then tilt, then yaw. In CSS, transforms apply right to left, so the order below does exactly that: ```css .camera { perspective: 1300px; perspective-origin: 50% 50%; } .plane { transform-origin: var(--fx) var(--fy); /* the focal point, in UI pixels */ transform: translate3d(var(--tx), var(--ty), 0) /* drift: animated */ rotateY(var(--yaw)) /* ±5–15deg */ rotateX(var(--pitch)) /* tilt back: 30–50deg */ rotateZ(var(--roll)) /* in-plane: ±10–20deg, sign flips per shot */ scale(var(--mag)); /* magnification at the focal point */ } ``` | Shot | `--mag` | `--pitch` | `--roll` | `--yaw` | Perspective | |---|---|---|---|---|---| | Extreme macro | 5–7 | 35–50° | ±12–20° | ±5–15° | 1100–1300 px | | Macro | 2.5–4 | 30–45° | ±10–18° | ±5–12° | 1200–1400 px | | Medium | 1.5–2.5 | 25–40° | ±8–15° | ±5–10° | 1300–1500 px | | Wide (payoff only) | 0.8–1.1 | 8–12° | 0° | ±0–3° | 1800–2200 px | Check the result: in-focus text should read diagonally, and near text should be about 1.4–1.8× the size of far text. If the frame looks like a flat screenshot, increase pitch before anything else. ### Drift Interpolate the translate, a small scale change, and a small angle change across the shot: | Move | Amount over the shot | |---|---| | Track along the action | 3–10% of frame width; up to 20–35% for a long pan along a diff or document | | Push | 1–5% scale | | Turn | 0.5–4° of roll or yaw | Use linear interpolation, or an ease-out over the first third that hands off to a slow, constant drift. Never ease to zero velocity before the cut. ## Depth of field This is optical depth of field, not a blurred background layer. Blur depends on each point's depth relative to the focal plane, so it grows continuously toward both the near and the far edge of the tilted UI. ``` depth(p) = z of plane point p after the camera transform blur(p) = min(maxBlur, k * |depth(p) - depth(focus)|) ``` | Shot | Sharp band (share of frame height) | Near-edge blur | Far-edge blur | `maxBlur` | |---|---|---|---|---| | Extreme macro | 4–8% | 10–16 px | 16–24 px | 24 px | | Macro | 8–15% | 6–12 px | 12–20 px | 20 px | | Medium | 15–30% | 4–8 px | 8–14 px | 14 px | | Wide | 50–70% | 0–3 px | 3–6 px | 6 px | **Implementation in a DOM stack**: depth is linear across the plane, so you can approximate it with 6–8 stacked copies of the plane, each with a stronger `filter: blur()`, each masked to a band at a greater distance from the focal line with `mask-image: linear-gradient(...)` on the plane itself. Point the gradient along the plane's depth direction, which you get by applying the inverse rotation to the camera's z-axis. Feather each band by about a third of its width so no seams show. **Rack focus**: animate `depth(focus)` (the focal line's position on the plane) over 0.4–0.8 s on an ease-in-out when attention moves. **Bokeh brightness**: out-of-focus bright text should spread and dim, not glow. Lower its opacity to about 0.6–0.8× as it blurs. ## Subject light A neutral pool that follows the subject. A single screen-space radial gradient makes it look like a hole cut in a black overlay: always round, always the same, always centred on the same point. Four things make it read as light falling on the slab instead. ### 1. Put the pool on the plane Light lands on the UI, so attach the pool to the plane and let the camera project it. Give the light layer the same size, `transform-origin`, and `transform` as `.plane`, and stack it above every depth-of-field copy: ```css .light { position: absolute; width: var(--ui-w); height: var(--ui-h); /* the UI's own size */ transform-origin: var(--fx) var(--fy); transform: /* identical to .plane */; pointer-events: none; background: /* core: the hot spot, nudged toward the key */ radial-gradient( ellipse var(--cw) var(--ch) at var(--kx) var(--ky), transparent 0%, transparent 45%, rgb(0 0 0 / 0.1) 70%, rgb(0 0 0 / 0.22) 100% ), /* spill: wide and soft, ending in black */ radial-gradient( ellipse var(--sw) var(--sh) at var(--lx) var(--ly), transparent 0%, transparent 15%, rgb(0 0 0 / 0.06) 30%, rgb(0 0 0 / 0.22) 50%, rgb(0 0 0 / 0.5) 68%, rgb(0 0 0 / 0.82) 85%, #000 100% ); } ``` All positions and radii are in UI pixels. The tilt foreshortens the ellipse into an egg that falls off quickly toward the far edge and stretches toward the near edge, and the roll lays it along the text diagonal. Every shot gets a different shape for free, because every shot has a different camera. Make the pool longer along the line of action than across it: wide for a line of typing or a row, tall for a column that streams downward. | Shot | Spill radius on screen, along / across (share of frame width) | Core radius (share of spill) | |---|---|---| | Extreme macro | 0.32–0.38 / 0.20–0.25 | 0.35–0.45 | | Macro | 0.40–0.45 / 0.26–0.30 | 0.35–0.45 | | Medium | 0.48–0.55 / 0.32–0.38 | 0.40–0.50 | | Wide | 0.70–0.80 / 0.50–0.60 | no core; the light opens up | To get UI pixels, divide the on-screen radius by the magnification: at 4×, a 0.42 radius is `0.42 × 1920 / 4 ≈ 200` UI px. Check the result on screen and adjust, since the tilt compresses the across axis. ### 2. Give it a direction A real fixture hangs off to one side. Offset the core (`--kx`, `--ky`) from the spill centre by 8–15% of the spill radius, toward the key. The two falloffs then stop being concentric: one side of the subject has a long, soft shoulder and the other drops off quickly. Put the key toward the far side of the slab and a little to one side, and flip that side whenever the roll flips sign, so the light direction alternates with the diagonal. Keep it fixed within a shot. The two layers stack multiplicatively (each passes `1 − alpha` of the light), which gives a hot spot with a gentle spill instead of one linear ramp to black. Keep at least five stops in the spill: three linear stops are what make a gradient read as CSS. ### 3. Flag it, sometimes In about a third of the shots, cut one side of the pool with a soft straight edge, like a flag in front of the fixture: ```css .flag { /* full-frame, screen space, above the light layer */ background: linear-gradient( var(--flag-angle), transparent 0%, transparent var(--flag-at), rgb(0 0 0 / 0.75) calc(var(--flag-at) + 20%) ); } ``` Place the edge 20–30% of the frame width from the subject, at least 25° off the text diagonal, with a 15–25% feather. The subject itself stays on the lit side. The flag rides with the pool, keeping the same offset from it as the camera drifts, so it never sweeps across the frame. ### 4. Let it react to the action The light never performs, but it does respond: - **Trail the subject.** Drive the spill centre with a lagged copy of the subject's position, so the light arrives just after the subject, like a follow-spot operator. It never leads. To keep each frame a pure function of time, average the path over a short window: `light(t) = mean of subject(τ) for τ in [t − T, t]`, with `T` = 0.3–0.5 s and `τ` clamped to the start of the shot. The core follows the same lagged position, plus its offset. - **Follow the rack.** When focus racks to a new subject, the pool slides there too, through the same lag, so it lands slightly after the focus does. - **Open with the content.** When an answer streams in or a document writes itself, grow the spill radii 20–40% over the shot to keep the new lines lit, smoothed with the same window. - **Open up for the payoff.** The wide shot uses the widest, flattest pool in the film. The cut back to a close-up returns to a tight one, and that contrast is part of the release. ### Frame vignette The vignette belongs to the lens, not the light, so it stays centred and constant. It only keeps the corners black: ```css background: radial-gradient(120% 95% at 50% 50%, transparent 50%, rgb(0 0 0 / 0.7) 100%); ``` No colour goes into any of these layers. ## Grade | Target | Value | |---|---| | Black | True black (#000) outside the UI | | Average frame luminance | 4–10% (most shots about 6–8%) | | In-focus primary text | about 85–90% white, never clipped | | Secondary text | 45–60% white | | Colour | Only the product's own: status icons, diff green and red, a brand-coloured button. Neutral everywhere else. | The product slab keeps its real chrome. Add only a faint edge to separate panels from the void: ```css border-radius: 14px; box-shadow: inset 0 0 0 1px oklch(1 0 0 / 0.06), /* hairline edge */ inset 0 1px 0 oklch(1 0 0 / 0.08); /* faint top highlight */ ``` ## Streaming reveal (stipple dissolve) Generated text, icons, and avatars resolve line by line out of a fine stipple of dots: ``` noise(x, y) = hash of the 2 × 2 px cell containing (x, y), in [0, 1) p(t) = easeOutCubic(clamp((t - lineStart) / 0.5, 0, 1)) visible = glyph pixel AND noise(x, y) < p(t) ``` - While `p < 1`, draw the visible dots 10–15% brighter, and add a 1–1.5 px blur that falls to 0 at `p = 1`. - Stagger lines by about 0.1 s, top to bottom. Start each line slightly before the previous one finishes. - Rows that hold icons resolve the icon and the text together. ## Other motion | Event | Recipe | |---|---| | Typing | 12–13 cps; a solid caret while typing, blinking at about 1.6 Hz while idle. Identifiers and file names become inline chips once the token is complete. | | Send | The composer text clears; the message appears in the thread with the Appear recipe. | | Appear | `opacity 0 → 1`, `translateY 12px → 0`, `blur 6px → 0` over 0.35 s on `cubic-bezier(0.22, 1, 0.36, 1)`. No overshoot. | | Select (tab, nav item) | The selection pill or highlight slides to the new item over 0.35 s on an ease-in-out. The new label brightens from 55% to 90% white. | | Press (button) | Scale to 0.97 over 0.08 s and back over 0.2 s; the button's own pressed colour shows briefly. | | Line select (code) | A gutter control fades in on the line, then the line's highlight fills over 0.25 s. | | Document writing | Headings, then paragraphs, then table rows, each with the stipple reveal. | | Diagram drawing | Nodes appear, then connectors draw on with a `stroke-dashoffset` over 0.4–0.6 s, then labels stipple in. | | Scrolling | 120–250 px/s of UI at native scale, ease-in-out at the start and end. | ## Leaving the last UI shot Either hard-cut to black, or over 0.4 s: `blur 0 → 12px` and `brightness 1 → 0`. ## Outro type ```css /* one line, centred on black */ font: 500 90px/1.2 <the product's sans>; letter-spacing: -0.02em; color: rgb(255 255 255 / 0.95); ``` Enter over 0.8 s on an ease-out: `filter: blur(16px) → blur(0)` and `opacity 0 → 1`. An optional soft glow, `text-shadow: 0 0 40px rgb(255 255 255 / 0.3)`, fades to 0 as the type sharpens. A quieter alternative is to fade the colour from 35% to 95% white over 1.2 s, with no blur. For the name-then-tagline variant, set the name, hold it for about 1.5 s, then fade in the tagline after it on the same line over 0.6 s while the whole line slides to re-centre on an ease-in-out. ## Logo Use the mark alone, or the mark with the wordmark. The mark is about 115 px tall, the gap to the wordmark about 0.4× the mark height, and the wordmark the size of the outro type. Plain white, with no bloom and no glow. Cut or dissolve (0.3 s) to it, hold it completely still for 4–5 s, and end the film on it. ## Render | Setting | Value | |---|---| | Resolution | 1920 × 1080 (or 1920 × 960 for a 2:1 widescreen cut); a 2× master for delivery | | Frame rate | 60 fps | | Motion blur | 4+ sub-frames per frame, 0.5 shutter (180°) | | Grain | Fine temporal luma noise (strength about 4 on ffmpeg's `noise` filter), applied after the grade | | Legibility | Text in focus is at least 24 px tall on screen at 1080p. Check it at 960 × 540. | -
shot-list-example.md 4.9 KB
# Shot list example This is a 52 s film, written in the abstract so it maps onto any feature. Replace each subject with the real piece of UI. Keep the rhythm, scales, and angles. The story shape is: 1. A close look at the familiar app, where the entry point for the feature appears. 2. The feature's view opens, and we read its core content up close. 3. The user asks for something; the product answers while we watch. 4. A single confirming action. 5. The payoff, in the film's only wide shot. 6. A close-up on the result. 7. Copy, then the logo. Magnification is relative to the UI at its native size, measured at the focal point. Angles are pitch (tilt back) / roll (in-plane, which sets the diagonal) / yaw. Drift is the camera move across the whole shot. | # | Cut | Len | Subject in focus | Mag. | Pitch / roll / yaw | Drift | Action | |---|---|---|---|---|---|---|---| | 1 | 0.0 | 3.0 | The app's sidebar near the window corner | 4.0 → 4.2× | 35° / −12° / +8° | Track down 5%, push 2% | A new nav item for the feature fades in, then its highlight fills. No cursor. | | 2 | 3.0 | 3.5 | The feature's list view, first few rows | 2.8 → 2.9× | 38° / +14° / −6° | Track right 8% along the rows | Rows resolve top to bottom with the stipple reveal. Focus sits on the second row. | | 3 | 6.5 | 6.0 | The core content: a diff, a document, or a canvas | 2.0 → 2.1× | 32° / −10° / +10° | Long pan, 25% of frame width, along the reading direction | Content scrolls gently under the camera. A highlighted region passes through the focal band. | | 4 | 12.5 | 2.5 | One tab or mode switch | 6.0 → 6.2× | 45° / +16° / −8° | Track sideways 5% | The selection pill slides to the new tab, and its label brightens. | | 5 | 15.0 | 8.0 | The composer, then the first lines of the reply | 3.0 → 2.8× | 40° / −14° / +6° | Rise 6% with the reply, slight pull | Type a 40-character prompt at 12 cps; identifiers become chips. Send. The reply starts streaming; rack focus from the input to the reply over 0.6 s. | | 6 | 23.0 | 6.0 | The generated result: a list, a plan, a document writing itself | 2.2 → 2.3× | 34° / +10° / −10° | Follow the content down, 10% | Lines stipple in top to bottom, about 0.1 s apart. Headings first, then body, then a table or diagram. | | 7 | 29.0 | 2.5 | The primary action button | 6.5 → 6.7× | 48° / −18° / +12° | Track 3% toward the button | The button presses and shows its own pressed colour. Hold. | | 8 | **31.5** | 7.0 | The whole window: the **only wide shot** | 0.9 → 0.95× | 10° / 0° / +2° | Push 5%, rise 3% | **Payoff.** Several regions change at once: the document scrolls, a panel updates, a list re-sorts. No shake and no flash. The size of the shot is the impact. | | 9 | 38.5 | 4.5 | The single best line of the result | 3.2 → 3.3× | 38° / +12° / −8° | Track right 5% | The last line resolves. Hold on the after state. | | — | 43.0 | 4.5 | Black | — | — | — | Blur-and-dim out of shot 9 over 0.4 s. The product name un-blurs at 90 px, then the tagline joins it on the same line. | | — | **47.5** | 4.5 | Black | — | — | — | Cut to the still logo. Hold to the end at 52.0. | ## Why it works - **Shot length follows the action.** The long shots (3, 5, 6, 8) are where something visibly happens: reading, typing, generating, paying off. The short shots (1, 4, 7) are punctuation, a single selection or press. Long and short alternate, so the film breathes instead of strobing. - **Scale rhythm**: macro, macro, medium, **extreme macro**, macro, medium, **extreme macro**, **wide**, macro. The extreme macros are accents between longer reads. Holding the wide shot back until the payoff makes it land like a release. - **The diagonal flips on every cut.** Roll alternates between negative and positive, so even two macros in a row read as different camera positions. - **The camera is always motivated.** It tracks along a row, rises with a streaming reply, and pushes toward a button. It never moves just to move. - **Focus tells the eye where to go.** Only a thin band is sharp. In shot 5, the rack from the input to the reply is the edit inside the shot. - **No pointer, no effects.** The UI selects, presses, and writes on its own, so every frame stays about the product. - **The ending is quiet.** After the widest, busiest shot, the film settles back into one close line, then one line of type, then a logo that does nothing at all. ## Camera numbers in practice With a CSS-style perspective camera at `perspective: P` looking at a plane `dist` away, the magnification at the focal point is about `P / dist`. At `P = 1300`: | Magnification | `dist` | |---|---| | 6× | 217 | | 4× | 325 | | 3× | 433 | | 2× | 650 | | 1× (use P ≈ 2000 for the wide shot) | 1300 | A 4% push from 2.8× to 2.9× takes `dist` from 464 to 448. With a strong pitch, the near edge of the frame can be several times closer than the far edge, which is exactly where the depth of field comes from.
-
-
SKILL.md 14.2 KB
--- name: cinematic-shot description: Shoot software UI like a film. A sequence of hero shots, each a steep, oblique, extreme close-up of the interface floating in black, with a razor-thin focal plane, a slow motivated camera drift, and UI that acts on its own, hard-cut on the action, ending on one line of copy and a still logo. Use when asked for a launch video, product film, feature trailer, teaser, promo clip, hero shot, or any "cinematic" footage of an app or UI. This skill covers camera, framing, light, and edit. It is stack-agnostic. --- # Cinematic shot You are the director and the DP, not the motion designer. The film is a sequence of **hero shots**. Each one looks at a real piece of the product's UI from a steep, low angle, so close that the focal plane covers only a line or two of text and everything else melts into black. The camera drifts slowly toward where the next thing will happen. The UI does the work by itself: things get typed, streamed, selected, and written while we watch. Nothing explains itself with captions. This skill is about camera, framing, light, and the edit. Build the film with any rendering stack. Whatever you choose, make every frame a pure function of time, so the film renders deterministically and can take motion blur. Read [references/look.md](references/look.md) for exact camera, depth-of-field, light, reveal, and type recipes. Read [references/shot-list-example.md](references/shot-list-example.md) for a full example of the shot grammar. For a ~15 second promo video made in code from a landing page (a continuous 3D fly-over of the page ending on a title card with the brand, logo mark, a two-part closing line, and an optional track), follow [references/landing-page-promo.md](references/landing-page-promo.md). ## The taste A black void. The product floats in it like a dark slab, tilted away from the camera, lit by a soft pool that follows whatever matters and lets everything else fall into black. The camera is low and close, looking *along* the UI rather than at it, so lines of text run diagonally across the frame and shrink into the distance. The focal plane is a thin band: one control, one line of typing, one row of a list is sharp, and the rest is soft bokeh. The camera never stops drifting and never moves fast. Shots are long enough to watch something happen. The only colour is the product's own. Restraint everywhere else. ## 1. Find the story before the shots Before planning a single camera, write down: - **The flow**: the 4–7 things that happen on screen, in order. Examples: open a view, select a tab, type a prompt, watch the answer stream in, watch a document write itself, approve. - **The payoff**: the one moment where the product visibly does something remarkable. The film exists to reach this frame. - **The demo content**: concrete, believable data inside the UI, such as names, IDs, statuses, code, and short human-sounding text. Real-looking density is what makes a close-up beautiful. A list of twelve plausible issues reads as a product; three grey placeholders read as a mockup. - **One line of copy**: the product or feature name, then a tagline of five words or fewer. ## 2. Write the shot list Post the shot list before building, then keep going: | # | Cut at | Len | Subject (what is in focus) | Scale | Angle | Move | Action | |---|---|---|---|---|---|---|---| Rules: - **Length**: 45–55 s in all, with 8–10 UI shots, then the copy and the logo. - **Shot length follows the action.** Process shots (typing, streaming, a document writing itself, a long diff) run **5–9 s**. Punctuation shots (a tab, a button, a nav item) run **2–3.5 s**. Alternate the two, so a long watch is followed by a short accent. Median about 5 s. - **Cut on the action, not on a metronome.** There is no beat grid. Cut in when the subject is already in frame or about to arrive; the action starts within 0.3–0.8 s; hold the result for 0.5–1 s; cut while the camera is still moving. - **One idea per shot.** A shot can contain a short chain (type → send → the reply starts) only if the camera follows one continuous thread. - **Vary scale like an editor.** Extreme macros and macros dominate. Medium shots carry the longer process. Hold back the **wide shot** (the whole window, near-frontal) for the payoff, where it lands like a release. Return to a close-up after it. - **Alternate the diagonal.** If the text in one shot rises to the right, the next shot's text falls to the right, or the plane tilts the other way. Every cut should read as a new camera position. - **No continuity cursor.** The UI acts on its own (see section 4). The viewer never needs to follow a pointer between shots. - **Separate surfaces get separate setups.** When the story moves to another surface (a terminal, a phone, another app), give it its own slab in the same black void and hard-cut to it. ### Shot scales Measure scale as magnification of the UI at the focal point, relative to its native size: | Scale | Magnification | Use for | Depth of field | |---|---|---|---| | Extreme macro | 5–7× | A single tab, a button, a nav item, a status badge. One or two words fill a third of the frame. | Only the subject is sharp. Everything else is heavy bokeh. | | Macro | 2.5–4× | A composer with a line of typing, a few rows of a list, a code hunk | A band 2–4 text lines deep is sharp | | Medium | 1.5–2.5× | A panel at work: a list streaming in, a document writing itself, a diff with a sidebar | A wider band is sharp; the far edge and near edge stay soft | | Wide | 0.8–1.1× | The payoff only: the whole window, near-frontal, with content scrolling or changing | Mostly sharp; the frame edges still soften | Macro shots must stay crisp. Rasterise the UI at the resolution of the magnification (for example 6×) before the camera scales it. Never upscale a 1× bitmap. ### Camera angle This is the signature of the look. Except for the wide shot, the camera is **low and oblique**, looking across the UI plane: - **Tilt the plane back** 30–50° (pitch), so the far side of the UI recedes and the near side looms. - **Rotate it in-plane** 10–20° before tilting, so lines of text run diagonally. Flip the sign between consecutive shots. - **Add a little yaw**, ±5–15°, so one side of the frame is closer than the other. - **Use a short-ish perspective** so the foreshortening is obvious: near text should be about 1.4–1.8× the size of far text in the same frame. A perspective distance of about 0.6–0.75× the frame width works (1100–1400 px at 1080p). - **The wide shot is the exception**: near-frontal, pitch 8–12°, no in-plane rotation, yaw within ±3°. - **Framing**: crop aggressively. The slab's edges run off frame or fall into black. Leave generous black: a quarter to a half of the frame is often the void, or UI so far out of focus that it reads as texture. ### Camera move Each shot is one continuous move. It is **motivated**: the camera drifts toward where the next thing will appear. - **Track** along the reading direction of the action: 3–10% of the frame width over a typical shot, up to 20–35% for a long pan along a diff or a document. - **Follow** content as it grows: when an answer streams downward, drift down with it; when a line is typed, drift with the caret. - **Push** gently, a 1–5% scale change over the shot. Pull-outs are rare. - **Turn** slightly, 0.5–4° of roll or yaw change over the shot. - **Speed**: constant (linear) velocity, or a short ease-out arrival over the first third that then continues at a slow constant drift. The camera never eases to a full stop and is still moving at the cut. No handheld noise, no shake. - **Rack focus** with the action: when attention moves from the typed line to the reply, or from a title to the body, slide the focal band there over 0.4–0.8 s. ## 3. Light and grade: a black void Every shot must look like it was filmed on the same stage. Values are in [references/look.md](references/look.md). - **Stage**: true black around the product. No gradient wallpaper, no coloured haze, no floor. - **Subject light**: a soft, neutral pool on the subject, not the frame. The UI falls off to black within roughly a third of the frame width from the focal point. The pool lies *on the UI plane*, so the tilt foreshortens it and the roll lays it along the diagonal. It is longer along the line of action, has a hot spot nudged toward an off-axis key (the key side flips with the diagonal), and sometimes has one side cut by a soft flag. It trails the subject by a beat, slides with a rack focus, and opens up as content grows and at the payoff. It is never a centred circle that looks the same in every shot. There is no coloured key light. - **Low key**: the average frame is very dark (about 7–10% luminance). Bright pixels are reserved for in-focus text and the product's own coloured UI. Anything bright and out of focus gets dimmed. - **The product is a dark slab**: its own chrome, rounded corners, and a faint 1 px edge highlight on panels. Keep the real UI faithful; do not restyle it. - **Colour belongs to the product**: status icons, diff greens and reds, a brand-coloured primary button. Add no accent of your own: no flares, no glows, no rings, no tinted light. - **Finish**: motion blur (180° shutter, 4+ sub-frames) and fine film grain on the final render. Together with the depth of field, these three do almost all the work. ## 4. Motion inside the shot - **No cursor.** The UI acts on its own. A nav item highlights. A tab's selection pill slides over. A button depresses. A gutter control appears on a code line and the line highlights. If a click must read, show it through the control's own pressed or selected state. - **Typing**: 12–13 characters per second with a visible caret. Code identifiers and file references turn into inline chips as they are typed. On send, the composer clears and the message moves into the thread. - **Streaming**: generated text resolves line by line, top to bottom. Each line arrives as a fine stipple of dots that condenses into solid glyphs over about 0.5 s, staggered by about 0.1 s per line. Icons and avatars resolve the same way. - **Writing**: documents and diagrams build in order: a title, then a heading, then paragraphs; diagram nodes, then connectors drawing on, then labels. - **Scrolling**: in medium and wide shots, the content may scroll smoothly under a drifting camera. This is the second layer of motion, and it should feel like reading speed. - **Appear**: new panels and messages fade and rise slightly through a small blur on an ease-out of 0.3–0.5 s. Nothing pops with overshoot. - **No impact effects.** The payoff is shown by scale (the wide shot) and by the amount that changes, not by shake, flashes, or rings. ## 5. Ending: copy, then a still logo 1. **Leave the last UI shot** with a hard cut to black, or a quick 0.4 s blur-and-dim into black. 2. **The copy**: one centred line on black, about 80–100 px at 1080p, weight 500, tracking about −0.02em, white. It arrives by un-blurring from about 16 px while fading up over 0.6–1 s. Either set the whole line at once, or set the product name first and then append the tagline on the same line, letting the line re-centre as it grows. A faint soft glow behind the type may settle away as it sharpens; nothing sweeps across it. Hold for 3–5 s. 3. **The logo**: cut or short-dissolve (about 0.3 s) to the still logo, either the mark alone or mark and wordmark, about 110–120 px tall at 1080p, in plain white. It does not move, pulse, or glow. Hold it for 4–5 s and end the film on it. Add no CTA buttons, URL cards, or "available now" banners unless asked. ## 6. Sound There is **no music**: no score, no drone, no beat, no risers, no braams, and no tonal stings. The soundtrack is quiet, tactile foley over near-silence. Every visible action gets a cue: a soft key tick per typed character, a soft click when a tab or item is selected, a quiet whoosh on send, and a faint granular hiss under streaming text. The payoff gets no impact. The copy and the logo play over silence. ## Don't These make a film look like a tutorial or a template: - Cold opens, title cards, or "Introducing…" and "New in…" screens before the action. - Keycap overlays, captions, callout arrows, or labels that explain the UI. - A visible mouse pointer driving the action, or a cursor travelling between targets. - Flat, frontal close-ups. Outside the wide payoff shot, the camera looks across the UI, not straight at it. - Everything in focus. If the frame has no bokeh, the shot is too wide or the focal band is too deep. - Dissolves or dips to black between UI shots. The UI shots use hard cuts only. - Fast moves, slow orbits, big 3D rotations, swooping fly-throughs, camera shake, or a camera that eases to a stop. - Cutting to a grid. Two-second shots back to back read as a sizzle reel; let process shots breathe. - Restyling the product's UI to look "cinematic". Keep the real UI faithful, and get the cinema from the camera, the focus, and the light. - Anamorphic flares, glow, accent rings, coloured key light, or any colour the product does not already have. - Light that moves across the frame: sheen bands, sweeps, or light bars travelling over the UI. The light follows the subject; it does not perform. - A light pool that is a screen-space circle, centred and identical in every shot. It reads as a black overlay with a hole in it, not as light on the slab. - An animated logo reveal. - Music of any kind, including a score, a beat, a drone, risers, braams, or bells. ## 7. Verify like a DP Render a still at the middle of every shot, at each action's peak, at the payoff, and at the copy and logo frames. Judge each one as a frame grab from a film: - There is exactly one sharp subject, and the eye lands on it in under half a second. - The focal band is thin, with both near and far bokeh, except in the wide shot. - The plane reads as tilted: text runs diagonally and visibly shrinks into the distance. - Text in focus is legible at half resolution. - At least a quarter of the frame is black or near-black. - Consecutive shots differ in scale or in the direction of the diagonal. - Every frame shares the same black level, neutral light, and grain, but the pool's shape changes with each camera: foreshortened, stretched along the action, and lit from one side. - Pick the strongest frame as the poster. Iterate until every still could be a screenshot in a launch post.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.