Vertical Reels Video Studio (basic)
A simple, step-by-step pipeline for one 30–90 second vertical video.
0. First run: ask the user for THEIR settings (never use defaults)
Before the first video, if brand.config.json is missing, has "configured": false, or still contains @yourhandle,
ask the user (one question at a time) and save the answers in brand.config.json:
- Social handles: Instagram, Threads, TikTok, X (whichever they use).
- Watermark text (exactly as it should appear, e.g.
@yourhandleor@ig / @x) and position (bottom-center,bottom-left,top-left,top-right). - CTA text and the handle it mentions.
- Voice: their ElevenLabs voice id + model + language, or "I'll record my own voice". The API key is requested only as the
ELEVENLABS_API_KEYsecret. - Language and tone; how the voice should say their name/handle.
Then set "configured": true. Never invent a handle, never reuse someone else's (including the author of this kit), and never render a watermark that still says @yourhandle.
The placeholders below map to brand.config.json:
| Placeholder | Config key | Meaning |
|---|---|---|
{{HANDLE}} | handles.* | The user's own handle(s) |
{{WATERMARK}} | watermark.text, watermark.position | Watermark text and position, as the user gave them |
{{LANGUAGE}} | language, tone | Language and tone of the voiceover and captions |
{{VOICE_ID}} | voice.voiceId | The user's chosen voice |
{{TTS_MODEL}} | voice.model | ElevenLabs model, e.g. eleven_multilingual_v2 |
{{CTA}} | cta.text, cta.handle | The user's call to action |
The API key always comes from the environment variable ELEVENLABS_API_KEY. Never print it, never write it in a file that is committed.
The flow
- Ask for the user's settings (first run) → 1. Topic → 2. Research and fact-check → 3. Script draft → 4. User approval →
- Voiceover → 6. Timing → 7. Build scenes → 8. Render → 9. Reels-safe export →
- QA → 11. Covers and captions → 12. Deliver. If the user asks for a change, go back to the earliest step the change touches (a new line of text means a new voiceover for that line only).
1–2. Topic and research
- One story per video. Write for a beginner.
- Check every number, date, name and quote against a primary source (official page, the author's own post, a dated screenshot). Drop anything you cannot verify. Never invent facts.
- Keep a short
sources.mdwith the links you used.
3–4. Draft, then wait
- Offer 2–4 hook options for the first 2 seconds (a question or a surprising contrast).
- Write a timed table:
time | on-screen text | voiceover. Aim for 45–65 s, never more than 90 s. - Stop and send the draft to the user. Do not generate audio or render until they approve it.
5. Voiceover
- Generate the approved script with
{{VOICE_ID}}(seescripts/tts.py). Keep two texts: the display text (what captions show) and the TTS text (spelled for the voice, e.g.A.I.for "AI", numbers written as words). - Listen to it. Re-generate only the lines that are wrong. Never leave the same line twice in the audio.
- If you have no ElevenLabs account, record your own voice. That works just as well.
6. Timing
- Get word timestamps (ElevenLabs alignment, or Whisper on the audio) and save
timing.json:{duration, words:[{w,s,e}], scenes:[{id,start}]}. - Animations start on the frame where their word is spoken:
frame = Math.round(seconds * 30).
7. Build scenes (Remotion, 1080 × 1920, 30 fps)
- Dark background, one light text colour, one accent colour. One big headline per beat.
- Kinetic text: each headline word pops in on its spoken word (scale 0.6 → 1 with a small overshoot).
- One new thing on screen every 1.5–3 s. Hold numbers for at least 1.5 s so people can read them.
- The hook text is visible from frame 0, so the first frame works as a still.
- Safe zone: keep text between y = 200 and y = 1500. Put the
{{WATERMARK}}text small at the user's chosen position (bottom default: y ≈ 1430). - Use real screenshots and logos with credit. Label mock-ups "illustration".
8–9. Render and export
npx remotion render src/index.ts <CompositionId> out/raw.mp4
bash scripts/reels-export.sh out/raw.mp4 out/final-reels.mp4
The export makes: 1080 × 1920, H.264 High ≤ 4.1, yuv420p (TV range), BT.709, constant 30 fps, 8–12 Mbps, AAC 48 kHz, +faststart, −14 LUFS / ≤ −1 dBTP. Keep the video under 90 s.
10. QA (always, before delivering)
Run bash scripts/qa-check.sh out/final-reels.mp4 and look at scripts/contact-sheet.sh output. Check:
- Audio: words are clear, nothing cut, no repeated line, loudness ≈ −14 LUFS.
- Video: no cut-off text, nothing outside the safe zone, no frozen clip, no empty first or last second. Fix and re-render before you send anything.
11–12. Covers, captions, delivery
- 2–4 cover options, 1080 × 1920 plus a 1080 × 1350 grid version. One big hook, one main image, at most 2–3 small number cards. Keep the key text inside the centre 1080 × 1080.
- Captions: Instagram (hook, body,
{{CTA}}, a few hashtags), Threads (shorter, no hashtags), TikTok. - Deliver the final MP4, a small preview (< 40 MB), covers, captions, an
.srtand the sources list.
Rules
- Never post, upload or buy anything. Hand the files to the user.
- No made-up facts. Credit every source and every open-source author you show.
- Only use music, clips and voices you have the right to use.