Say hi

Promo and explainer videos with AI

The workflow I use to make promo and explainer videos with an AI agent: HyperFrames for most scenes, Python and Blender for the heavy visuals, and ElevenLabs for voice and music.

Type
Workflow · v1.1
Works with
Claude Code, HyperFrames, ElevenLabs, Blender
Updated
8 Nov 2026
Licence
MIT, use it anywhere
Topics
AI, Video
People
The whole toolbox
video-workflow/
  • WORKFLOW.md
  • prompts.md
  • script.example.json
Install in Claude Code
claude plugin marketplace add heygen-com/hyperframes claude plugin install hyperframes@hyperframes unzip video-workflow.zip -d my-video
Then ask
Write a plan for a 30-second promo for my brand: scenes, voice lines, lengths. Don't make anything yet.

How it runs

  1. PlanScenes, voice lines, lengths
  2. VoiceElevenLabs, one file per line
  3. TimelineScenes snapped to the beat
  4. MusicElevenLabs Music to length
  5. PictureHyperFrames, Python, Blender
  6. Mixffmpeg, voice ducked, −14 LUFS
  7. NotesFive or six rounds

I make promo and explainer videos without a camera, an editing app or a motion designer. An AI agent builds every frame and I direct it. My first brand promo took one day this way. This page is the whole workflow behind it, with every prompt.

How it works

Everything lives in one folder, and every step saves its own files: the plan, one voice file per sentence, the music, the scenes, the renders. So when one sentence sounds wrong, I redo that sentence, not the video.

The timeline is built from the music, not fixed by hand later. Each scene is as long as its voice line plus some padding, never shorter than its minimum, then rounded up to whole beats. That's why every cut lands on a beat.

Timeline chart: voice lines as black bars, music beats as ticks, and five picture scenes (Python, HyperFrames, footage) whose cuts all land on a beat at 110 BPM
An example timeline: five scenes at 110 BPM, every cut on a beat.

The picture: HyperFrames first

HyperFrames is an open-source framework from HeyGen that turns HTML, CSS and seekable animation into MP4. A scene is a web page, so the agent writes it the way it writes any page, I can look at single frames before anything renders, and the same scene renders the same way every time.

I use it for most scenes: titles, captions, lower thirds, UI walk-throughs, charts and transitions. Its registry has a few hundred ready blocks. I start from one when it fits and restyle it to my brand, so it doesn't look like a template.

Python for the heavy visuals

HTML gets slow when a scene has thousands of moving parts. For those I have a Python renderer: skia-python for drawing, NumPy and OpenCV for the maths and the colour grades, piped straight into ffmpeg. The 30-second promo's AI brain has about 850 nodes firing signals, and every brand pattern is drawn from the same triangle geometry as my logo.

Three cards: HyperFrames for titles, captions, UI and charts; Python with skia, NumPy and OpenCV for brand patterns, particles and grades; Blender for 3D. All feed one ffmpeg mix at -14 LUFS
Which engine draws what.

Blender for real 3D

When a shot needs real depth, like the big bang, the flight through space or the satellites over Earth, the agent builds it in Blender. I don't open Blender at all: a portable Blender 5.2.3 sits in the project folder, and the agent writes Python scripts that set up the scene, the camera move and the lights, then renders them headless with Cycles on the graphics card (OptiX). The models are free ones: NASA's Earth textures and NASA's glTF satellite models.

Each shot comes out as an image sequence, and the Python renderer composites it with the HUD, the voice and the music. A simple Full HD frame takes about 1 second on my RTX 4070 SUPER. Close-ups through the volumetric atmosphere took 14 to 27 seconds a frame, so previews are 720p and only the shot that changed gets rendered again.

Why render it myself

I could make shots like these with an image or video model such as Nano Banana. Rendering them on my own PC is a good way to test ideas without paying tokens for every try: the agent spends tokens writing the scene once, and every re-render after that is just my graphics card working. Nothing goes to the cloud.

Making it fast on my PC

The renderer started on my Mac and moved to my Windows desktop for the heavy work: an Intel Core Ultra 9 285K (24 cores: 8 performance, 16 efficiency), 64 GB of RAM and an RTX 4070 SUPER with 12 GB. The first render on it was painfully slow. Task Manager showed 7% CPU and 3% GPU: the renderer is single-threaded Python, so it kept one core busy and left the other 23 idle.

The test is my first YouTube video: 4:15, 7,647 frames at 1920x1080 and 30 fps. All numbers below were measured on 7 November 2026.

Setup

Full video, 1080p

Speed

Faster

Skia on the CPU, 1 process (the Mac code as it was)

about 2 h 46 min

0.8 fps

1x

Skia on the CPU, 22 processes

about 15 min

8.4 fps

about 11x

Skia on the GPU, 1 process

1 min 32 s

83 fps

about 108x

Skia on the GPU, 12 processes (the default now)

43 s

175 to 197 fps

about 230x

At 4K (3840x2160), on the GPU and in parallel, the full video takes about 3 to 3.5 minutes (35 to 51 fps, depending on the number of processes).

Fix 1: every core at once

prender.py splits the timeline into chunks on whole frames, renders each chunk in its own process, and joins them with ffmpeg's concat demuxer without encoding again. I checked it frame by frame against a single-process render: the same frame count, no gaps or doubles at the seams. With 22 processes the CPU sits near 100% and the video renders about 11 times faster.

Fix 2: drawing on the GPU

Parallel chunks only hid the real problem. Each frame took 1.3 seconds, and almost all of it was Skia compositing on the CPU: the bloom (two blurred copies of the scene added on top), the vignette and the film grain, about 20 full-frame operations per frame. The Windows build of skia-python is far slower at this than the Mac's, where the same code took about 15 minutes for the whole video.

One full-frame operation, 1920x1080

CPU

GPU (OpenGL)

Fill with a translucent colour

48 to 122 ms

0.04 ms

Bloom pass (blur and additive draw)

56 ms

0.6 ms

Read the frame back for ffmpeg

24 to 30 ms

2.4 ms

Upload an image and draw it

n/a

5 ms

The fix was small. An invisible glfw window gives an OpenGL context, and skia.Surface.MakeRenderTarget replaces skia.Surface.MakeRaster. The drawing code didn't change at all: only the 12 places that create surfaces, plus uploading the grain frames to the GPU once. PETRACH_GPU=0 switches back to the CPU. A frame now takes about 5 ms to draw instead of 1,300 ms.

Does it look the same?

On 11 stills across the video, the GPU render matches the CPU render at 46 to 52 dB PSNR, with under 0.5% of pixels off by more than 8/255, all on antialiased edges. It looks identical. Against the Mac render it's about 40 dB, and the difference is the text antialiasing (macOS draws glyph edges a little differently from FreeType on Windows), not the effects.

Encoding

Final encodes use NVENC (h264_nvenc, preset p7, constant quality) on the graphics card when it's there, and fall back to x264. GeForce cards allow 8 NVENC sessions at once, so with more parallel processes than that, the chunks encode with x264 on the CPU, which was faster at 12 processes anyway. The whole build-yt.sh (render, voice effects and mix) takes 60 seconds.

Voice and music: ElevenLabs

The voice is ElevenLabs, voice Eric on the v4 model, fetched lossless at 48 kHz, one file per sentence. After that a light chain: EQ, gentle compression, a short room and a limiter. The music is ElevenLabs Music, generated to the exact length with a strong beat on the cut points. The prompt is saved next to the file, so I can regenerate it.

The mix places each voice line at its cue, turns the music down under the voice, then measures the loudness and applies one gain to -14 LUFS, which is where YouTube plays it.

Free options

The only paid part you need is a Claude plan with Claude Code. For the rest:

  • Voice: Kokoro runs on your own computer, free for business use. The free ElevenLabs plan needs a credit and isn't for business.
  • Music: a track from the YouTube Audio Library, cut to length.
  • Footage: Pixabay clips, picked from a numbered contact sheet. Keep the credits.

How to use it

  1. Install HyperFrames for Claude Code (the install commands above) and unzip the workflow into a new folder with your logo in it.
  2. Put your API keys in `.env`. Never paste a key into the chat.
  3. Copy the prompts from `prompts.md` one at a time. Check each result before you type the next.
  4. Give notes in plain words, one sentence at a time. Expect five or six rounds.

What broke

  • Pitch-shifting the voice to make it deeper smeared it. Now it's EQ and compression only.
  • Loudness that pumped. A single-pass normaliser kept riding the level. Measuring first and applying one gain fixed it.
  • Re-rendering everything for every note was slow. Now previews are 720p and only the scene that changed gets rendered again.
  • One core at 7%. The first render on the PC would have taken almost three hours for a four-minute video. Parallel chunks and Skia on the GPU brought it to 43 seconds.
  • 16 processes at 4K made some encoders die, most likely out of memory. The default is 12.

What's inside

WORKFLOW.mdMarkdown
# Promo and explainer videos with an AI agent

The agent builds every frame; you direct. Seven steps, each one saved as files in one folder, so any step can be redone without touching the others.

```
my-video/
  plan.md              scenes, voice lines, lengths
  script.json          the same, as data the scripts read
  assets/vo/           one voice file per line
  assets/music/        the score
  assets/footage/      picked stock clips + credits.json
  scenes/              HyperFrames compositions (HTML)
  scripts/             Python scenes for the heavy visuals
  out/                 renders, previews, the final mix
```

## 1. Plan

Ask for a plan, not a video. Scenes, what the voice says in each, how long each one is, and how people should feel at the end. Read it like a director and give notes in plain words until it's right. The plan becomes `script.json`.

## 2. Voice: ElevenLabs

One audio file per sentence, so a bad line is redone alone. Fetch lossless (`pcm_48000`) and keep it 24-bit. A light chain after it: EQ, gentle compression, a short room, a limiter with headroom. No pitch shifting; it smears the voice.
Free option: Kokoro, runs on your own machine.

## 3. Timeline

Each scene is as long as its voice line plus padding, never shorter than its minimum, then snapped to whole beats of the music's tempo. Every cut lands on a beat because the timeline is built from the beat grid, not fixed by hand later.

## 4. Music: ElevenLabs Music

Ask for the mood, the exact length and a strong beat on the cut points. Save the prompt next to the file so the score can be regenerated.
Free option: a track from the YouTube Audio Library, cut to length with a fade.

## 5. Picture: HyperFrames first, Python for the heavy parts

- **HyperFrames** for most scenes: titles, captions, lower thirds, UI walk-throughs, charts, code, transitions. A scene is an HTML page with seekable animation, so the agent writes it like a web page, checks single frames, and HyperFrames renders it to MP4 the same way every time. Its registry has ready blocks to start from; restyle them to the brand instead of using them as they are.
- **Python** (skia-python, NumPy, OpenCV, piped to ffmpeg) for what HTML is bad at: thousands of animated shapes, particle systems, brand patterns drawn from the logo geometry, colour grades on stock footage, bloom. Skia on the GPU draws a frame in a few milliseconds; a chunked renderer splits the video into parts and renders them in parallel.
- **Blender** (Cycles) for real 3D models, rendered as image sequences and composited in.
- **Stock footage** from Pixabay, picked from a numbered contact sheet, graded to the brand. Keep the credits file.

## 6. Mix

Place each voice line at its scene's cue, duck the music under the voice, then measure loudness and apply one gain to -14 LUFS (two-pass loudnorm), which is where YouTube plays it. Export H.264 MP4. On an NVIDIA card, NVENC makes the final encode a lot faster.

## 7. Feedback loop

Watch it and write what bugs you, one sentence at a time. Preview at 720p and re-render only the scene that changed, not the whole video. Expect five or six rounds.

## Rules

- API keys live in `.env`, never in the chat, the code or the repo.
- Brand colours, fonts and shapes in one file the scenes import, so a change lands everywhere.
- Keep the licence or credit for every clip, track and font you didn't make.

Changelog

  • v1.1Blender for real 3D, and how the renderer went from 2 h 46 min to 43 s on my PC: parallel chunks and Skia on the GPU, with the measurements.
  • v1.0First version: HyperFrames for most scenes, the Python renderer for heavy visuals, ElevenLabs for voice and music, every prompt.

Who made it

  • Vedran PetračAuthorI build apps and websites, and the odd maths model.About me

Next in the toolbox

The whole toolbox