Skip to content
Back to skills

Reel Story

ASecurity

Use when the user runs /reel-story, or asks for the full-frame, motion-heavy Reel edit — speaker full-screen, cut-aways to their own B-roll clips, stickers and widgets popping on spoken words, a mascot, giant words behind the speaker, no subtitles — on a talking-head take in raw/.

  • 15 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentspythongoreactgit

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add Jenesyx/arta-edit-studio --skill reel-story --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Reel Story?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Reel Story
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jenesyx-reel-story/badge)](https://www.skillsdirectory.com/skills/jenesyx-reel-story)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: reel-story
description: Use when the user runs /reel-story, or asks for the full-frame, motion-heavy Reel edit — speaker full-screen, cut-aways to their own B-roll clips, stickers and widgets popping on spoken words, a mascot, giant words behind the speaker, no subtitles — on a talking-head take in raw/.
argument-hint: <take name in raw/> <what the video is about, comment keyword, names>
---

# Reel — Story edit (full-frame motion)

The speaker stays full-frame. The story is told by cut-aways to the creator's own
clips, stickers/cards/widgets that pop on spoken words, a mascot reacting, and
**depth moments** where giant words or a branded backdrop sit *behind* the speaker
(person matte). Worked example: `examples/story/story_stoodi_inviteraw.py`.

Arguments: `$ARGUMENTS`

## Defaults (change only if the user says so)

Read `reel.config.json` first (falls back to `reel.config.example.json`).

| Thing | Default |
| --- | --- |
| Subtitles | **None.** Key-word graphics are fine; never a running transcript |
| Audio | Take's own mix, untouched — `finish.py` remuxes it. No SFX, no music bed |
| Take | Assume already cut, graded, music added → don't cut or grade. Raw/uncut → ask first |
| B-roll | `broll_dir` from the config; descriptions in `work/_catalog/<folder>/NOTES.md` |
| Brand | `brand` + `palette` from the config. No mascot files → no mascot scenes |
| CTA | Comment keyword huge on screen; follow card = `@<creator.handle>` text only, never a face crop |
| Language | `language` from the config (Whisper + which text class to use) |
| Taste | **The creator's mood board decides the look** — never a default AI style. No approved style brief, no build |
| Safe zones | Nothing to read or see inside Instagram's UI zones (`instagram_safe_zones`, docs/safe-zones.md) |
| Motion | Eased, curved, motion-blurred, overlapping — docs/motion.md, helpers in `tools/motion.js` |

## Inputs

Take name + topic come from the arguments. Ask once, in one message, only what's
missing: is the take already cut/graded/with music; comment keyword; names or
jargon Whisper may mishear; clips they want in or out.

## Pipeline

`PY` = `.venv/Scripts/python.exe -X utf8` (Windows) or `.venv/bin/python -X utf8` (macOS/Linux). Long steps in background.

| # | Step | Command / action | Check |
| --- | --- | --- | --- |
| 1 | Look | ffprobe the take; contact sheet `ffmpeg -i raw/<take> -vf fps=1/5,scale=216:384,tile=9x2 -frames:v 1 work/<take>/sheet.jpg` and look at it | headroom above head, text in frame mirrored?, already graded? |
| 2 | Transcribe | `$PY tools/transcribe.py <take> --prompt "<names, jargon>"` | proofread names; word gaps > 3 s → re-transcribe that window |
| 3 | Face | `$PY tools/face_track.py <take>` | prints `FACE = (x, y)` and head top |
| 3a | **Mood board** | `$PY tools/moodboard.py <take>`. Exit 2 = none exists → **stop and ask the creator to make one** (explain [docs/moodboard.md](../../../docs/moodboard.md) in their language: 5–15 screenshots of Reels they love, 1–3 short clips of motion they like, `notes.md` with mood words, likes, dislikes). Then look at **every** `board_N.jpg`, read `summary.md` | |
| 3b | **Style brief** | write `work/<take>/style.md` from [docs/style-brief.md](../../../docs/style-brief.md) — every line traceable to the board, notes or brand; anti-slop list in Don't. **Show it to the creator and wait for OK** | builders refuse without it |
| 4 | B-roll | `$PY tools/story_assets.py <take> catalog`; read `NOTES.md`; look at the strips of clips not described yet and **add their rows to NOTES.md** | HDR / mirrored / VFR flags |
| 5 | Beat sheet | write `work/<take>/beats.md`: `time \| words \| mode \| what \| board ref`. Rules below, techniques in [references/techniques.md](references/techniques.md), style from `style.md` | every beat pinned to a word |
| 6 | Matte | if any depth moment: `$PY tools/story_assets.py <take> matte` (~8 min CPU for 80 s, background, no parallel ffmpeg) | `work/<take>/matte/fg.webm` |
| 7 | Take module | copy `examples/story/story_stoodi_inviteraw.py` → `tools/story_<slug>.py` (slug: take name, non-alphanumerics → `_`); set `NAME`, `FACE`, `BROLL`, `TILES`, `MIRRORED`, scenes, `SCENES` (`DUR` optional — probed). Mascot names = the files in `assets/mascot` (lower-case, spaces → `-`) | |
| 8 | Assets | `$PY tools/story_assets.py <take> all` (mascot, logo, B-roll trims, tiles) | |
| 9 | Build | `$PY tools/story_build.py <take> --guides`; in `work/<take>/sc`: `npx hyperframes lint public` → 0 errors (`nested_structure` warnings are expected); `npx hyperframes snapshot public -o ../snaps --no-end --describe false --at <every beat>`; read the sheets **with the Instagram zones drawn in**, fix, rebuild | |
| 9a | Checks | rebuild **without** `--guides`; `$PY tools/safezone.py check <take>` → 0 errors; `$PY tools/motion_check.py <take>` → explain or fix every `linear` / `jerky` | `finish.py` blocks on safe-zone errors |
| 10 | Quick render | `$PY tools/finish.py <take> --seconds 12`; read `quick_sheet.jpg` and `quick_sheet_guides.jpg`; watch `quick.mp4` for motion | overlays enter **and leave**; colours not dim; moves smooth |
| 11 | Full render | `$PY tools/finish.py <take>` (~12 min for 80 s, background) → `final/<take>/`, verify, `qa/sheet.jpg` | read the sheet frame by frame |
| 12 | Report | path, length, beats, clips used, anything flipped/tone-mapped, verify result. If something new was learned, add it to this skill | |

## Beat rules

- Something changes every 2–4 s; never more than ~5 s of bare speaker.
- Mix the modes: speaker + stickers · B-roll cut-away (~25–30 % of runtime) · depth moment (4–6 per reel) · full-screen graphic with the speaker as a facecam bubble (1–2 max).
- Cue = start time of the spoken word in `transcript.json`. Each element leaves before the next beat.
- Depth words go **above the head** (head top from step 3): one giant word at a time, the previous word flies out. Stacked lines end up hidden behind the head.
- Safe zones (defaults; the config is the truth): header y < 200, footer y > 1520, action rail x > 920 between y 1000–1520. Text, stickers, cards, mascots and logos stay out; full-screen pictures may run under. Place text between y 220–1480 and x 60–900.
- Motion: entrances `EASE.enter`, exits `EASE.exit` (shorter), cross-screen moves on a curve with blur (`arcIn` / `arcOut` / `whip`), giant words `settle`, camera `camTo`; never `ease:"none"` on a move; overlap with `STAGGER`.
- Look follows `style.md`: its palette, fonts, graphic language and density. Something the board doesn't support doesn't go in.
- Numbers shown as facts must come from the take. Illustrative labels are fine.
- Farsi / Arabic text: `.fa` class (RTL scoped to the element — never `dir="rtl"` on `<html>`, it renders black), `letter-spacing: 0`, digits via `fa()`, a big zero as Latin `0` (Persian zero is a dot). Latin text: `.en`; giant display words: `.blk`.

## Engine contract — bugs already paid for

- Scene = `def scene(c: Comp)`: `c.clip(layer, id, start, end, html, track)`, `c.broll(name, a, b, mstart)`, `c.matte(n, a, b)`, `c.j(js...)`. Layers: `under` (behind the bubble), `tiles`, `behind` (between take and matte), `fw`, `broll`, `over`, `fx`.
- Clip divs get id `k-<id>`; animate `#<id>-i` or inner ids — never a `.clip` itself.
- Anything that slides in from off-screen needs `autoAlpha:0` in its from-state, or it peeks early.
- First tween of an element sets its initial state (`fromTo` renders immediately); later tweens: `.to` or `immediateRender:false`.
- Never `from:"random"` staggers or `Math.random` — shuffle DOM order in Python with `random.Random(seed)`.
- Same property, same element: one tween must end before the next starts (lint `overlapping_gsap_tweens`).
- `#cam` scale/x/y/clipPath/borderRadius drive punch-ins, bubble and mosaic. The matte lives inside `#cam`, so depth moments stay aligned at any camera scale.
- Front-camera B-roll with readable text in frame → add to `MIRRORED`. Never flip the main take.
- HLG/HDR sources are tone-mapped by `story_assets.py`. If `finish.py` stops on "HDR auto-promotion", a source escaped that path.
- `hyperframes snapshot` is not proof of the render — that is what step 10 is for.
- `--guides` builds are for looking only: `finish.py` refuses to render them.
- Motion helpers (`arcIn`, `settle`) set start states with `gsap.set`; don't add another `fromTo` for the same properties. `mblur` owns the element's CSS `filter` while it moves.
- Renderer dies mid-capture with no error = low RAM (Premiere, games, browsers). `finish.py` retries with 1 worker; if it still dies, ask the creator to close heavy apps (or set `PRODUCER_LOW_MEMORY_MODE=1`).

Files in this skill

  • SKILL.md8.6 KB
  • references/techniques.md4.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.