--- name: make-video description: Make a narrated video with local MLX narration and MLX images, rendered by HyperFrames. Use when the user asks for a video, a reel or an explainer. --- # Make a narrated video Do the steps in order. Stop at the first step that fails, and tell the user what failed. This skill's folder holds `narrate.mjs` and `images.mjs`. In the commands below, `` is the folder of this SKILL.md file. Run the `video-setup` skill first if this Mac has not run it. ## 1. Pick the tier Read the total memory in GiB, and pick the row of the tier table in `../video-setup/SKILL.md`, relative to this skill's folder, exactly as that skill says: ```sh echo $(( $(sysctl -n hw.memsize) / 1073741824 )) ``` Use the row's narration model in step 4 and its image command in step 5. Tell the user the tier, the narration model and the image model. ## 2. Make the project folder Make a HyperFrames project in a new folder. Use the video's name, in lower case with hyphens, as ``: ```sh npx --yes hyperframes init --example blank --non-interactive --skip-skills mkdir -p /assets/narration /assets/images ``` ## 3. Write the storyboard Write `/storyboard.md`: a table with one row per scene. Each row has the scene number, the narration line, the on-screen text and the image prompt. Show it to the user and change it as they ask before you go on. Write each narration line for the ear: - Use one or two short sentences. - Write a number in words: "twenty", not "20". - Write a word in capitals only if the voice must spell it out: "M L X", not "MLX". The voice can misread a word in capitals; "TACO!" came out as "Takeo". Write each image prompt as one line that says what the picture shows: the subject, the place, the light and the style, for example "a red fox in fresh snow at dawn, photograph". Do not ask for words in the image; the on-screen text goes over it in step 6. Then write two files, each with one line per scene in scene order, no blank lines and no scene numbers: - `/script.txt`: the narration lines. - `/prompts.txt`: the image prompts. ## 4. Make the narration ```sh node "/narrate.mjs" --script /script.txt --out /assets/narration --model --voice Ryan ``` The script makes `line-01.wav`, `line-02.wav` and so on with mlx-audio. Then it transcribes each WAV with Qwen3-ASR 0.6B 8-bit and compares the transcript with the line. It writes `narration.json` to the same folder, with each line's `start` and `seconds`, and `totalSeconds`. - Exit 0: every line matches. Go to step 5. - Exit 2: the script names each line whose transcript differs from its text, with what the ASR heard. For each one, change the line in `script.txt` and in the storyboard, for example spell a word as it sounds, and run the command again. A rerun makes new audio only for a changed line. To make new audio for a line with the same text, add `--redo `, for example `--redo 2,5`. Repeat until the script exits 0. After three tries on one line, show the user the line and what the ASR heard, and ask what to do. - Exit 1: show the user the error. The voices of the Qwen3-TTS CustomVoice models include `Ryan`, `Aiden`, `Vivian` and `Serena`. Use another voice only when the user asks. ## 5. Make the images ```sh node "/images.mjs" --prompts /prompts.txt --out /assets/images --command "" ``` The script runs the tier's image command once per prompt, and makes `scene-01.png`, `scene-02.png` and so on. Scene 1 takes seed 1, scene 2 seed 2, and so on, so a rerun of the same prompt makes the same image. It writes `images.json` to the same folder, with each image's prompt and seed. Each image is 1664x928, Qwen-Image's 16:9 size. mflux needs a width and a height that are multiples of 16, so it cannot make 1920x1080; the scene in step 6 scales the image to fill the frame. Change the size only when the user asks, with `--width` and `--height`. - Exit 0: every scene has its image. Show the user the images. - Exit 1: show the user the error. To change an image, change its prompt in `prompts.txt` and in the storyboard, and run the command again. A rerun makes new images only for changed prompts: the same prompt and seed make the same image again. The first run of a large image model can take some minutes per image. Tell the user the number of images before you start. ## 6. Place the media in the HyperFrames project Write `/index.html`. Start from the blank example that step 2 made, and keep its GSAP script and its timeline. For each line in `narration.json`, add one scene with its image and one `