本文へ移動
cccskills
無料GitHub で公開

video-storytelling

Design and build the visual layer of a long-form talking-head video as one persistent world the camera moves through, instead of a sequence of separate graphics. Use when asked to edit a video, add motion graphics, design the visuals for a script, plan an edit, or fix an edit judged confusing, text-heavy, hard to follow, or "clearly made by an AI". Covers the persistent world, camera grammar, the spotlight rule, spatial open loops, ornament and token discipline, transcript timing, and the verification gates.

インストール方法を見る

含まれるファイル(5)

  • SKILL.md19.0 KB
  • reference/design-system.md7.3 KB
  • reference/patterns/wall-of-slots/geom.py3.5 KB
  • reference/patterns/wall-of-slots/README.md3.3 KB
  • reference/patterns/wall-of-slots/wall.py13.4 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Video storytelling

How to build the visual layer of a long-form video so a viewer is still oriented at minute nine. Applies to any talking-head video with a script: a news take, a single-topic deep dive, a comparison, a tutorial, a listicle.

The failure this replaces is scene-thinking. A new graphic every few seconds makes the viewer restart comprehension every few seconds, and no individual graphic is at fault, which is why the feedback comes back as the vague "confusing" or "too much going on" rather than as a specific defect.

For a neutral practice beat sheet, read docs/STORYTELLING-WORKBOOK.md at the repository root. The reusable design system is in this skill's reference/design-system.md; the worked open-loop geometry is in reference/patterns/wall-of-slots/. Private source videos are not required.

This is not hyperframes-video-beats. That skill places overlay cards on top of a talking head. This one designs the thing the video is about.

1 · The four principles

One persistent world

The video lives in a single space, and it never resets. Everything the viewer has already seen still exists where they left it, and new material is added to it rather than replacing it. An element, once drawn, is never redrawn, moved, or relabelled.

Everything else in this skill depends on that. The camera has nowhere to go if the space keeps changing, a spotlight means nothing if there is nothing else on screen, and an open loop cannot stay open in a world that resets.

The world also has to be worth staying in, so decide the spatial grammar before building anything and hold it for the whole runtime. In the reference build: left to right is toward the outcome, up is toward a human and is the only warm thing on screen, down is into a system of record. A viewer who learns that in the first two minutes reads the rest of the video for free.

Break the grammar exactly once, deliberately, for meaning. The reference build's only right-to-left move in ten minutes is a resolved ticket reversing back into the queue on the words "reopen rate". It lands without a word because direction had meant something for the previous three minutes.

The camera is the edit

Cutting to a new graphic costs the viewer their bearings every time. Moving through a space that stays put costs them nothing. A push-in then reads as "look closer at the part of the thing you already understand", and the pull-back is where the work pays off, because everything built so far is still there.

Work in three altitudes and move between adjacent ones:

AltitudeShowsUsed for
Worldthe whole spaceorienting, payoffs, "here is where we are"
Regionthe subgraph under discussionmost of the runtime
Detailone elementa number, a state change, a decision

Jumping detail to world is disorienting unless it is a deliberate payoff beat, in which case it is the best move available.

Rules that cost a rebuild each to learn:

  • Name framings as exact world windows, not as scale factors. Window boundaries must fall between labels. Specifying a framing as "scale 0.6" slices words in half at the frame edge.
  • Reuse the same window for the same purpose. If the orient shot is a particular window, always use that exact window. Near-identical framings read as drift.
  • Vary duration with distance travelled, not one global preset.
  • Camera and full-frame wipes sequence, never overlap. Concurrent, they guillotine content. Camera first, then wipe.
  • A cover layer goes opaque before the camera moves underneath it. Reversed, part of the move is exposed and reads as a jump cut.
  • No label within 60px of the frame edge. An element may bleed and read as "the world continues"; a word cut mid-glyph reads as a bug. Solve it by placement, not by masking, since a feather cannot catch a blade travelling ~1800 px/s.
  • Two sequential moves on the same subject read as a glitch. A reframe that finishes and THEN a wipe that starts is a zoom, a dead stop, and a second motion — the client calls it "a glitch and a pause". Merge them into ONE gesture: shared symmetric ease (power2.inOut), landing on the same frame, so the panel reads as pushing the footage aside. Related: front-loaded eases (power3/4.out) on a visible footage move front-load ~90% of the travel and crawl to a stop; reserve them for element entrances, where the crawl reads as settling. (Cost a client-flagged revision on the worked example intro.)

Attention is a spotlight

Exactly one element at full brightness at any moment. Everything else already drawn stays quiet but legible. Not optional. This is the rule that lets a world accrete to a dozen elements without ever feeling busy, and it is what makes the pull-back readable rather than overwhelming.

Hierarchy comes from the RATIO between active and quiet, never from making everything dark. The first prototype of the reference build had a brightest pixel of 101/255 and was unreadable at 960x540; the fix was brighter ink, not more dim.

StateTarget luma (Y, 16-235)Opacity in the reference
Active stroke + label200-2351.0
Context, drawn and still relevant120-1500.56
Spent, said its piece85-1050.33
Any label, any statenever below 90

Implementation is one function, called at every narration beat with the ids being talked about (build_s01.py, lit()):

def lit(t, active, warm=(), dur=0.5, floor=FLOOR):
    active = list(active) + [g + "-l" for g in active if g + "-l" in order]
    for gid in order:
        if gid not in opac:      # never drawn: nothing to light
            continue
        tgt = 1.0 if gid in active else (WARM if gid in warm else floor)
        if gid not in active:
            tgt = min(tgt, MUTED.get(gid, 1.0))
        ...

Three details in there are load-bearing:

  • A label always inherits its element's state (the -l suffix fold-in). A lit element with an unreadable label under it is the exact defect being fixed.
  • A prop that is finished retires to opacity 0, via a MUTED cap, not to 0.3. Muting to 0.3 leaves unexplained confetti on screen for the rest of the section. Generator rule: emit the mute() before any later-starting lit(), or the mute is overwritten when its tween completes.
  • Opacity events must be emitted in timeline order or the tracker sees stale state and computes the wrong target. Keep a seq() guard that raises on out-of-order emission.
  • One opacity authority per element per window. Two simultaneously-active tweens driving the same element's opacity to different values render smoothly in a standalone section but strobe at ~10Hz in the assembled master, where the winning tween alternates per frame. The reference build shipped this defect at every dock. When a sweep like lit() overlaps an explicit brighten or mute, the later-starting tween is the sole driver and the sweep skips those ids (lit(..., skip=(...))). Gate it: scan assembled renders for one-frame out-and-back luminance pops in every transition window (qa/v4/flicker/qa-flicker.mjs in the reference build).

Open loops are spatial

Never say "we'll come back to this." Leave something visibly incomplete in the world and return to it. A promise the viewer can see is a promise they can feel outstanding.

The mechanic is identical whatever the shape:

  1. Plant it in the hook, in the space, on the line that makes the promise.
  2. Re-show it at every boundary. Any section handoff is a boundary. The re-show costs about two seconds and is the retention mechanic; skipping it is how a payoff ends up paying off nothing.
  3. Advance it visibly. The viewer must see the incompleteness shrink.
  4. Close on the image you opened on.

Pick the shape from the script:

Script shapeThe worldWhat is incomplete
N parallel itemsN sockets on a spineempty slots (see reference/patterns/wall-of-slots/)
One process, deepthe full pipeline, laid outa broken or missing link
Levels or tiersa stack that builds upwardthe top of the stack is a ghost
Comparisontwo columns on one shared axisone column empty, or an unfilled scorecard
News or announcementa timeline, or a landscape mapthe right side, the future, is blank
Tutorial or build-alongthe finished architecture, ghostedevery node not yet built

Handing an item to its slot is a live camera move, ~1.4s, never a cut to a pre-made picture of the filled state. The viewer watches the thing they just learned become the tile. If the video has a numeral or counter, roll it inside that same move, as an odometer, with the same start, duration and ease for both digits or they merge into one band mid-roll.

The counter needs a name, not just a number. A corner numeral tells the viewer where they are in the sequence but not what the current item is; nine minutes in, "03" carries nothing. Pair the numeral with a 1-2 word label naming the current item (SUPPORT, VOICE AI), in the same plate chemistry, moving as one rigid fixture with the numeral, swapping inside the same odometer roll. Client review of the reference build asked for exactly this: the visuals were good and the viewer still lost track of which use case was on screen.

2 · Discipline

If it doesn't get a word, it doesn't get drawn

Every shape is a labelled element, a connector between labelled elements, the travelling subject, or the ambient ground. Nothing else.

This came from a mute-test review that scored comprehension 7/10 and named the cause: the diagram was clean, the decorations were not. A dozen unlabeled shapes drawn in the same weight and palette as the meaningful ones, so a first-time viewer cannot tell signal from texture and spends real attention decoding things that were never meant to be decoded. That is "too much going on" relocated from words into shapes.

Budget: ~20 on-screen words per section. No sentences. Labels are 1-2 words, under their element. The reference section 1 is 21 words in 84 seconds.

Corollary: an anti-pattern visual never overlays the recommendation. Take the world to near-black first, or put the counter-example where the good diagram isn't.

Give the viewer one thing to follow

Carry the story on a single travelling subject whose state visibly changes: a chip with data rows and a score bar, a document, a request. Rows fill, a bar moves, a border changes colour. A viewer must be able to follow an entire section by watching that one object, and it must never teleport; it moves along drawn connectors at a constant speed.

One global token set

Full detail in reference/design-system.md.

TokenValues
Stroke1.5 / 2.5 / 4 / 7, and nothing else
Type22 / 30 / 42 / 60 / 84
Radius10 / 22 / 40, always superellipse(2)

Five colours, five fixed meanings, zero decoration. Warm means a human is involved and nothing else is ever warm. Never pure white for type; it halates on dark.

The failure this prevents, from the craft review of the first build: "every decision was made locally and correctly; no decision was made globally." 18 stroke weights and 9 type sizes, most of them 0.2 apart, individually invisible and collectively fatal. The eye gets noise instead of hierarchy. Gate it with a token linter that fails the build.

Motion

Entrances on cubic-bezier(0.16,1,0.3,1), exits faster than entrances, duration varies with mass so a 290px node and a 40px label do not decelerate identically, and back.out exactly once per section, on the beat that deserves it.

No cross-fade, ever. Full-bleed layers enter and exit by clip on an already opaque background. At any instant a pixel is either graphic or footage.

3 · Build contract

  • One generator per section. scripts/build_<id>.py writes only compositions/<id>.html. Edit the generator, never the generated HTML. Section roots index-*.html are hand-maintained, so framing changes go there.
  • Shared modules stay shared. Anything that defines shared geometry is imported by every section. If sections are built by parallel agents, forbid them from touching shared modules; divergent geometry silently breaks every handoff.
  • Namespace the SVG defs before assembly. Each section defines its own gEdge, shadow, edgeFade. In one assembled DOM url(#id) resolves to the first match in document order, so once an earlier composition unmounts, every later graphic paints nothing. Cost in the reference build: 35 seconds of empty screen with every gate green. Only looking at the assembled render caught it.
  • Time everything to word starts from a word-level transcript, entering 0.15-0.25s ahead of the anchor word. Never divide a section evenly into beats.
  • Audit gaps. Any stretch over ~1.5s with nothing happening is a dead screen; have the generator print them.
  • Leave air in the cut. Aggressive pause-capping produces near-zero gaps at sentence boundaries that the client hears as "stutters" and jump-cuts. Calibrate against the speaker's own norm: flag sentence-boundary gaps that are ~10x tighter than their median (the reference speaker's was 470ms; the flagged junctions sat at 20-40ms), and repair by inserting 4-8 frames of air, words never touched. Air is a donor slice of the track's real room tone with 10ms fades, never anullsrc: digital silence against a -50dBFS floor is an audible dropout. Video holds the frame; between sentences a talking head is near-still and 4-8 frames of hold is invisible. Insertion-only changes shift the transcript deterministically, so no re-transcription is needed. An insert's edges must respect the speech envelope: butting donor tone against a word tail in 1ms amputates a decay that naturally takes 60-120ms, and the client hears the cliff as a stutter. Splice with a 40ms equal-power crossfade into the tail's own decay, never a hard butt.
  • Baked times mean scripted shifts. Generators bake hundreds of proto-time literals, and section offsets, seam tables, and root tweens all hold absolute times. Any timeline change after graphics exist (even a 2s air pass) must go through a reviewed AST/parse-level transform that shifts every literal after each edit point, then a diff review, never hand edits. Derive every shift from the canonical edit list itself; the reference pass caught a 2-frame error in its own audit's precomputed offsets by re-deriving.
  • --workers 1 on render. Parallel workers make the video layer paint black.

4 · Gates

Run all of them, then look anyway.

node scripts/qa-tokens.mjs          # 0 off-system strokes / type sizes / radii
node scripts/qa-no-crossfade.mjs    # 0 full-bleed layers animating opacity
node scripts/qa-legibility.mjs <render>
node scripts/qa-seamjump.mjs <render> plan/cover-seams.json --control <cut>
node scripts/qa-deadframe.mjs <render> --control <cut>
node scripts/qa-presence.mjs <render> --every 1      # speaker on-screen share
node scripts/integrate.mjs --check                   # 0 gaps, 0 stale mounts
npx hyperframes lint

Gates do not replace looking, and gates that have never failed are not gates.

  • Motion smoothness is verified on contiguous frames, never on beat frames. A single frame per beat proves composition; every motion defect — a jump into a move, a crawl to a dead stop before a second move, a freeze, a one-frame pop — lives between beat frames and survives every other gate. Before any delivery, tile a contiguous strip across EVERY transition window (camera move, wipe, reframe, dock, section seam) and read the strips:

    ffmpeg -i render.mp4 -vf "select='between(n,A,B)',scale=480:270,tile=layout=6x7" \
      -frames:v 1 tile-<window>.png
    

    Defect signatures to read for: adjacent tiles with a large jump then several near-identical tiles (front-loaded ease / dead stop); motion that halts and a different motion that then begins (two moves that should be one gesture); any single tile unlike both neighbours (pop). The worked example intro shipped a zoom-freeze glitch that passed tokens, cross-fade, legibility, dead-gap and per-beat frame reads; the client caught it in one viewing. This class recurs — treat this strip-read as load-bearing, not optional.

  • Legibility is not automatable. Absolute pixel-share thresholds measure text volume, not legibility; a wordy build scores higher than a sparse one. Read a 960x540 downscale of every major beat by eye.

  • Validate every gate against a control known to trip it. A seam gate that reports zero on a broken build is worse than no gate.

  • Verify the assembled artifact, never section prototypes. Most of the bugs that survived this build's gates existed only in the assembly.

  • Audit audio at the acoustic level, not the transcript level. A transcript derived from the pre-edit source is structurally blind to artifacts the edit created, and a text sweep over it will report "clean" while the client hears stutters. What actually finds them, in yield order from the reference build: a whole-track dead-span scan (runs of digital-zero samples inside pauses whose real floor is ~-70dBFS read as dead holes; fill with room tone), 1ms-resolution envelope forensics at every junction edge (a sample-derivative click check passes an envelope cliff that the ear flags instantly), and a fresh ASR pass on the delivered audio diffed against the expected text. Phoneme-repeat autocorrelation found nothing: what clients call "stutters" are usually truncation cliffs and dead holes, not doubled words.

Presence: aim for ~40% speaker-on-screen across a graphics-led video. Long absences are fine at payoff beats that need full width; audit them rather than capping them.

5 · Order of work

  1. Lock the cut and get a word-level transcript. Everything is timed to it.
  2. Choose the world, the spatial grammar, and the travelling subject. Write them down before building.
  3. Choose the open loop from the script shape and build its shared module first. Its geometry is referenced by the hook, every boundary, and the payoff.
  4. Build one section end to end and render it. Prove the system there before touching the others.
  5. Review that section by eye, muted, for ornament and legibility. Fix the system, not the section.
  6. Build the rest against the proven section. Then namespace, assemble, render, gate, and read the assembled render.

Steps 4 and 5 are where the quality comes from. The reference build's entire visual system is the output of reviewing its first section three times.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Agent 2 of the video editing pipeline. Finds and removes spoken mistakes — stutters, repeated words, false starts, and retakes (re-recorded lines) — from a talking-head recording. Use after cut-silences, when asked to cut mistakes, remove stutters / repeats / filler restarts, clean up flubs, or keep the best take. Works review-gated: it proposes every cut with context and a reason for approval, then renders only the approved cuts via ffmpeg. Requires a word-level transcript.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

Agent 1 of the video editing pipeline. Removes silences and dead air from a talking-head recording. Use when asked to cut silences, trim pauses, remove dead air / gaps, or tighten the pacing of a raw video, given a word-level transcript. Produces an edit list (EDL), a re-timed transcript for downstream agents, and optionally the cut video via ffmpeg. Does NOT cut mistakes, repeats, or false starts — that is the cut-mistakes agent.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

Edit a raw talking-head video through transcription, silence trimming, mistake review, visual storytelling, motion graphics, and verified HyperFrames rendering. Use for a complete edit; route a single requested operation directly to its specialist skill.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

gsap

無料

GSAP animation reference for HyperFrames. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, timelines (gsap.timeline(), position parameter, labels, nesting, playback), and performance (transforms, will-change, quickTo). Use when writing GSAP animations in HyperFrames compositions.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

Create video compositions, animations, title cards, overlays, captions, voiceovers, audio-reactive visuals, and scene transitions in HyperFrames HTML. Use when asked to build any HTML-based video content, add captions or subtitles synced to audio, generate text-to-speech narration, create audio-reactive animation (beat sync, glow, pulse driven by music), add animated text highlighting (marker sweeps, hand-drawn circles, burst lines, scribble, sketchout), or add transitions between scenes (crossfades, wipes, reveals, shader transitions). Covers composition authoring, timing, media, and the full video production workflow. For CLI commands (init, lint, preview, render, transcribe, tts) see the hyperframes-cli skill.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

HyperFrames CLI tool — hyperframes init, lint, preview, render, transcribe, tts, doctor, browser, info, upgrade, compositions, docs, benchmark. Use when scaffolding a project, linting or validating compositions, previewing in the studio, rendering to video, transcribing audio, generating TTS, or troubleshooting the HyperFrames environment.

日本語の概要は準備中です。原文の説明を表示しています。

nateherkai/hyperframes-student-kit1,3372026年9月28日 更新

nateherkai のスキルをすべて見る

このスキルの問題を報告する