# How to Make a Video Changelog with AI, Step by Step

URL: https://nanosolutions.io/how-to-make-a-video-changelog-with-ai
Date: 1791504000
Description: How to turn release notes into a short narrated video in eight steps, with the tools, a sample script, the checks, and eight real example clips.

---


<div class="post-tldr">
  <p class="post-tldr__label">The short version</p>
  <ul>
    <li>A video changelog is a 15 to 45 second narrated clip that says what changed in a release. It reaches the people who never open the release notes.</li>
    <li>You build it with scripts, not a video editor: write one line per change, generate a voice, record the screen, add music and captions.</li>
    <li>There are eight steps below. An AI coding agent can run seven of them. A person approves the words and watches the final cut.</li>
  </ul>
</div>

A video changelog is the watchable version of your release notes. Customers who never read a changelog will watch 30 seconds of one in a client update or on LinkedIn.

This is what you are making:

<figure>
  <video controls preload="none" playsinline width="1280" height="720" poster="/videos/blog/video-changelog-october-desktop-poster.webp" style="width:100%;height:auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-october-desktop.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-october-desktop.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>A monthly roundup of this website's changes. Real pages recorded in a browser, an AI voice, music and captions. 30 seconds, 2.7 MB.</figcaption>
</figure>

## What do you need?

Everything here is free except the optional paid voice.

- **A changelog.** A plain list of what changed in each release. We keep a `CHANGELOG.md` in the [Keep a Changelog](https://keepachangelog.com/) format.
- **Node.js.** Runs the scripts that glue the steps together.
- **ffmpeg.** The free command-line video tool. It joins the scenes, mixes the sound and writes the final file.
- **A headless browser.** We use Playwright. It draws the title cards and records the real site.
- **A voice.** A free macOS voice, a paid stock AI voice, or a clone of your own.
- **A transcriber.** We use Whisper. It listens back to every line so you do not have to.
- **An AI coding agent (optional).** It can write the scripts and run every step. You can also do each step by hand.

## How do you make a video changelog, step by step?

### Step 1: Pick three or four changes

Open the changelog for the release. Pick the three or four changes a customer would notice. Leave out refactors, dependency bumps and anything you would have to explain.

**Check:** every change you picked is in the written changelog. The video must never claim something the release did not do.

### Step 2: Write one scene per change

Each change becomes one scene in a file called `script.json`. A scene has the words on screen and the words spoken:

```json
{
  "id": "post",
  "tag": "ADDED",
  "title": "A new article on WA cyber attacks",
  "say": "We added a new article on this year's W A cyber attacks.",
  "caption": "We added a new article on this year's WA cyber attacks."
}
```

`say` is written for the ear and `caption` for the eye. A voice may read "WA" as one word, so the spoken line spells it out. "0.0.32" becomes "zero point zero point thirty-two".

Add a short intro scene and a short outro. Five scenes is about 30 seconds.

**Check:** read the `say` lines out loud. If you run out of breath, the line is too long.

### Step 3: Generate the voice

Make one audio file per scene, and keep each file until its line changes. Then fixing one word means regenerating one line, not the whole clip.

You have three choices of voice:

| Voice | Cost | Use it for |
| --- | --- | --- |
| macOS voices (Karen, Lee) | Free | Drafts, and anything internal |
| Gemini Australian stock voice | Under a cent a clip | Anything a customer sees |
| Your own voice, cloned in [Voicebox](https://github.com/jamiepine/voicebox) | Free, runs on your Mac | Clips where it matters who is speaking |

The free option is one command per line:

```bash
say -v Karen -r 175 -o intro.wav --file-format=WAVE --data-format=LEI16@48000 "Here's what shipped in release zero point zero point thirty-two."
```

<figure>
  <video controls preload="none" playsinline width="1280" height="720" poster="/videos/blog/video-changelog-voice-comparison-poster.webp" style="width:100%;height:auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-voice-comparison.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-voice-comparison.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>The same changelog line in three voices: Karen and Lee from macOS, then Petr's cloned voice. 19 seconds, 1 MB.</figcaption>
</figure>

<figure>
  <img src="/images/blog/video-changelog-microphone.webp" alt="Studio condenser microphone with a pop filter in a dark room" width="1400" height="933" loading="lazy" />
  <figcaption>A cloned voice starts from a short reading of a sample passage. Photo by <a href="https://unsplash.com/photos/macro-photography-of-silver-and-black-studio-microphone-condenser-c1ZN57GfDB0" rel="nofollow noopener">Jonathan Velasquez on Unsplash</a>.</figcaption>
</figure>

**Check:** a cloned voice needs the person's consent, and a label on the video saying it is an AI voice.

### Step 4: Check every line by transcribing it

AI voices make mistakes you will not notice on the tenth listen. They drop the last word, or add a phrase that was never in the script.

So do not listen. Transcribe each audio file with Whisper and compare the text with your script. If the last word of the line is missing, regenerate that line.

**Check:** the transcript of every line matches its caption.

### Step 5: Show the change

There are two ways to put a change on screen.

- **Title cards.** Small HTML pages in your site's own fonts, saved as images by the headless browser. Quick to make, and enough for most releases.
- **Screen recordings.** The headless browser opens the real page at phone or desktop size, scrolls and taps through it, and saves about 40 screenshots a second. ffmpeg turns those into video.

For a bug fix, record the page twice: once from the code one commit before the fix, and once from the fix itself.

<figure>
  <video controls preload="none" playsinline width="1280" height="720" poster="/videos/blog/video-changelog-before-after-0-0-28-poster.webp" style="width:100%;height:auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-before-after-0-0-28.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-before-after-0-0-28.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>Before and after: release 0.0.28 on two phones, recorded from the code one commit before the fix and from the fix itself. 27 seconds, 1.1 MB.</figcaption>
</figure>

**Check:** the recording shows the real site, not a mock-up.

### Step 6: Set the timing and add music

- **Timing.** Each scene lasts as long as its voice line plus about a second. Put a fade, slide or wipe in the gap between scenes.
- **Music.** Ours is written note by note in code, so there is nothing to license. Use a calm bed for release notes and a brighter 120 to 128 BPM track for social clips.
- **Mix.** Make the music duck under the voice, then level the whole clip to -16 LUFS, a common loudness target for online video. ffmpeg does both with its `sidechaincompress` and `loudnorm` filters.

**Check:** you can follow every word at low volume.

### Step 7: Add captions and export

The scene timings you already have also write the caption file, in WebVTT format. Plenty of people watch on mute, so do not skip this.

For feeds that autoplay without sound, burn the captions into the picture instead:

<figure>
  <video controls preload="none" playsinline width="1280" height="720" poster="/videos/blog/video-changelog-0-0-28-stock-voice-poster.webp" style="width:100%;height:auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-0-0-28-stock-voice.mp4" type="video/mp4" />
  </video>
  <figcaption>Captions burned into the picture for feeds that autoplay on mute. Read by Karen, a free macOS voice. 30 seconds, 1.4 MB.</figcaption>
</figure>

Export as H.264 video with AAC audio, and put the file's index at the front so the clip starts playing before it has finished downloading:

```bash
ffmpeg -i scenes.mp4 -i mix.wav -c:v libx264 -pix_fmt yuv420p -c:a aac -b:a 96k -movflags +faststart changelog.mp4
```

**Check:** the file is under about 3 MB for 30 seconds.

### Step 8: Watch it twice

A person watches the finished clip once with sound and once without. This is the step you do not hand to the agent.

**Check:** the words match what shipped, nothing is cut off, and it makes sense on mute.

## Which format should you make?

Pick by where the clip will be watched.

| Format | Shape | Where it goes |
| --- | --- | --- |
| Monthly roundup | 16:9 | Email and the web |
| Client changelog | 9:16 | Sent straight to a client's phone |
| Feature spotlight | 9:16 | Reels and Shorts |
| Social teaser, no voice | 9:16 | Feeds that autoplay on mute |
| Title-card release | 16:9 | Every release, with the written notes |

The roundup is at the top of this post. Here are the other four.

<figure>
  <video controls preload="none" playsinline width="720" height="1280" poster="/videos/blog/video-changelog-client-declutter-with-kiah-poster.webp" style="display:block;width:100%;max-width:360px;height:auto;margin:0 auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-client-declutter-with-kiah.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-client-declutter-with-kiah.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>Client changelog: what a week of SEO fixes meant for <a href="https://declutterwithkiah.services" rel="noopener">Declutter With Kiah</a>, a Perth professional organiser, told in plain English on her real pages. Shared with Kiah's permission. AI voice, 68 seconds, 5 MB.</figcaption>
</figure>

<figure>
  <video controls preload="none" playsinline width="720" height="1280" poster="/videos/blog/video-changelog-listen-spotlight-poster.webp" style="display:block;width:100%;max-width:360px;height:auto;margin:0 auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-listen-spotlight.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-listen-spotlight.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>Feature spotlight: our "Listen to this article" player, tapped on a phone. Read by the same AI stock voice that narrates our posts. 23 seconds, 1.3 MB.</figcaption>
</figure>

<figure>
  <video controls preload="none" playsinline width="720" height="1280" poster="/videos/blog/video-changelog-llm-teaser-poster.webp" style="display:block;width:100%;max-width:360px;height:auto;margin:0 auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-llm-teaser.mp4" type="video/mp4" />
  </video>
  <figcaption>Social teaser, no narration: big type, the local LLM post in a phone, and a model-written game running, cut to a 128 BPM track. 15 seconds, 1.7 MB.</figcaption>
</figure>

<figure>
  <video controls preload="none" playsinline width="1280" height="720" poster="/videos/blog/video-changelog-0-0-32-petr-poster.webp" style="width:100%;height:auto;border-radius:2px;background:#141618">
    <source src="/videos/blog/video-changelog-0-0-32-petr.mp4" type="video/mp4" />
    <track kind="captions" src="/videos/blog/video-changelog-0-0-32-petr.vtt" srclang="en" label="English" default />
  </video>
  <figcaption>Title-card release: release 0.0.32 narrated by an AI voice cloned from Petr's own recording, with his permission. 34 seconds, 1.7 MB.</figcaption>
</figure>

## What does the AI agent do, and what does a person do?

**The agent:**

- writes the script from the changelog
- generates each voice line and checks it with the transcriber
- records the site and renders the clip

**A person:**

- confirms the words match what shipped
- gives consent for any cloned voice
- watches and signs off the final cut

It's the same split we use in other [AI automation](/services/ai-automation-consulting) work.

## How much does a video changelog cost to make?

Almost nothing per clip. The macOS and cloned-voice clips cost nothing beyond the Mac they ran on. The two Gemini-voiced clips cost about one US cent together.

The real cost is building the pipeline once. After that, a new release is a new `script.json` and one command.

## Where does a video changelog fit in your release process?

At the end, triggered by the same tag that publishes your written notes. That way the video never claims something the release didn't do.

If you'd like that in your own pipeline, it's part of our [DevOps consulting](/services/managed-linux-infrastructure/devops-consulting-perth). You can also see how we run projects on our [process page](/process).

---

**Photo credits.** All images used under the [Unsplash License](https://unsplash.com/license), free for commercial use, attribution appreciated:

- Video editing timeline — [Peter Stumpf](https://unsplash.com/photos/video-editing-timeline-on-dark-screen-yk9VXp4W5-Q)
- Studio microphone — [Jonathan Velasquez](https://unsplash.com/photos/macro-photography-of-silver-and-black-studio-microphone-condenser-c1ZN57GfDB0)
- Perth skyline in the release 0.0.32 video — [Nathan Hurst](https://unsplash.com/photos/high-angle-photography-of-city-during-daytime-ymgOYi8mroc)
