Free Setup Guide

How I made a 10-second AI cyborg burst-out reel in 10 minutes (with two keyframes and one video model)

Most people who try AI video give up after a few generations because the same prompt produces a totally different result every time. The character drifts. The lighting changes. The room rearranges itself. You spend an hour fighting the dice.

Adam BurgeAdam BurgeNano Flow

There's a trick that fixes this, and almost nobody is using it: start frame + end frame.

You generate the first frame of your video. You generate the last frame. Then you hand both to a video model that supports keyframe interpolation, and it builds a coherent motion between the two anchors. The model doesn't drift, because it can't — it has to land on the end frame you gave it.

I used this technique to make a 10-second reel of a feminine cyborg bursting out of a computer monitor. Two keyframes, one video gen, one audio mux, one CTA overlay. About 10 minutes of work, about $0.80 in credits. Here's the full setup.

Watch it on YouTube Shorts: youtu.be/-3LRsLB32z8

The stack

  • Higgsfield (image gen via MCP) — nano_banana for the keyframes
  • Higgsfield seedance_2_0 — video model with start+end frame support
  • Apify Instagram Scraper — to download the original audio from a reference reel
  • ffmpeg — to mux audio onto the rendered video and overlay the CTA
  • Playwright — to render the Nanoflow CTA pill as a transparent PNG

Total third-party cost: roughly $0.80 in Higgsfield credits (two stills + one 10s 1080p video at standard mode). Apify, ffmpeg, and Playwright are free.

Step 1: Generate the start frame

The start frame establishes everything: the character, the room, the framing, the lighting. Spend your prompt budget here.

For a cyborg-trapped-in-monitor shot, I gave nano_banana this prompt at 9:16:


Cinematic photoreal 9:16 vertical photograph, 35mm with shallow
depth of field, moody high-contrast lighting. Bottom foreground:
a cluttered home desk seen from a low slightly-tilted angle —
black mechanical keyboard with red-tinted keycaps, circuit-pattern
mousepad, coiled black cable. Center mid-ground: a wide ultrawide
monitor sitting on the desk, screen showing a feminine cyborg
trapped inside — slender chrome-plated armor with Nanoflow
pink-magenta-cyan gradient accents at shoulders and collar, long
silver-pink hair, a faint dark crown of thorn-vines around her
head, glossy slim visor, mysterious and rebellious. Background:
dim apartment, cyan and violet ambient light, thin LED light bar
above the screen, dark curtain. Right-edge foreground: a man's
index finger reaching in from off-frame, fingertip pressed flush
against the monitor glass at the cyborg's chest level. Ultra-
detailed, photographic realism, no text.

A few rules I follow with nano_banana:

  1. 9:16 explicitly. If you skip the aspect ratio param it defaults to 1:1 and you'll have to crop.
  2. Lock the prop list early. Describing the desk objects in concrete nouns (mechanical keyboard, coiled cable, circuit-pattern mousepad) gives the model anchors. Vague descriptions ("a cluttered desk") drift wildly between gens.
  3. No text in the prompt. Adding "no text" cuts down on rendered-on captions and watermarks the model occasionally hallucinates.

Step 2: Generate the end frame (using the start frame as a reference)

This is the step that locks identity. You're going to ask the model to render the same character in the same room with the same camera angle, but in a different state. The only way the model can preserve the character is if you feed the start frame in as a reference image and keep your prompt short.

For the end frame I used nano_banana_flash with the start frame attached as medias[] and this prompt (deliberately under 80 words):


Same desk, same room, same camera angle and framing. The cyborg
has now burst out of the monitor and leans forward over the desk,
both hands gripping the wooden desk edge. Glass shards float
around the broken screen. Her eyes flare bright white-pink,
glowing intensely. The entire room is flooded in deep red light.
The monitor behind her is dark and faintly fractured, showing a
tiny recursive copy of the same scene. No human hand from
off-frame. Crown of thorns clearly visible. Same character
identity, hair, armor, gradient accents.

The rule that matters: describe what's changing, not what's the same. The reference image holds the identity. Re-describing the character's features in the prompt actively fights the reference and produces drift. "Same character identity" + "same room" + a short list of what's different is enough.


Step 3: Generate the motion (Seedance 2.0 with both frames as keyframes)

This is the move. Seedance 2.0 accepts two reference media with role: "start_image" and role: "end_image", and renders a coherent 10-second motion between them.

json
{
"model": "seedance_2_0",
"aspect_ratio": "9:16",
"resolution": "1080p",
"mode": "std",
"duration": 10,
"genre": "epic",
"medias": [
{ "role": "start_image", "value": "<start-frame-id>" },
{ "role": "end_image", "value": "<end-frame-id>" }
],
"prompt": "Cinematic transition with continuous camera, no cuts.
First 3 seconds: cyborg trapped inside the monitor turns her head
slightly toward camera, hand pressed against the glass from inside,
the off-frame human finger remains touching the screen, cool cyan
and violet light. Seconds 3-5: monitor glass cracks dramatically
with pink and cyan glowing shards, the off-frame finger retracts,
the cyborg pushes through the screen plane. Seconds 5-8: red light
floods the room from behind her, eyes flare bright white-pink, she
leans forward menacingly. Final 2 seconds: chrome hands plant on
the wooden desk edge, deep red wash, intense glowing eyes."

What seedance gives you here is a timeline-aware motion prompt. The "first 3 seconds / seconds 3-5 / seconds 5-8" structure tells the model where to put the dramatic beats. Without it, you get either a slow drift or a sudden cut at the end.

Render time: about 2-3 minutes. Cost: about $0.50 at 1080p / std mode for 10 seconds.

Step 4: Get the audio from a reference reel

If you're chasing a specific trending sound, the cleanest way to grab it is the Apify Instagram Scraper. One POST gets you the direct mp4 URL of any public reel.

bash
curl -s -X POST \
"https://api.apify.com/v2/acts/apify~instagram-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN&timeout=900" \
-H "Content-Type: application/json" \
-d '{
"directUrls": ["https://www.instagram.com/reel/SHORTCODE/"],
"resultsType": "details",
"resultsLimit": 1
}' > apify-response.json

Then download the videoUrl from the response and strip the audio:

bash
curl -L -o source.mp4 "$(jq -r '.[0].videoUrl' apify-response.json)"
ffmpeg -y -i source.mp4 -vn -c:a copy source-audio.m4a

The -c:a copy keeps the audio bit-exact — no re-encoding, no quality loss, no codec drift.

Step 5: Mux the audio onto the rendered video

Seedance generates its own audio (and it's surprisingly good), but if you're matching a trend you want the original. Replace the seedance audio track in a single ffmpeg command:

bash
ffmpeg -y -i motion.mp4 -i source-audio.m4a \
-c:v copy -c:a aac -b:a 192k \
-map 0:v:0 -map 1:a:0 \
-shortest \
final.mp4

The -shortest flag is the safety net — if your motion video is 10.05s and the audio is 10.10s, it stops at the shorter one and you don't get a black tail.

Step 6: Render the Nanoflow CTA pill

For Instagram in particular, the CTA pill at the bottom-third of the screen is what converts viewers into DMs. Here's the pattern I use — write the pill as HTML, render it with Playwright to a transparent PNG, then overlay with ffmpeg.

js
// render-pill.mjs
import { chromium } from 'playwright';
import fs from 'node:fs/promises';

const W = 1080, H = 1920;
const html = `<!DOCTYPE html>
<html><head><style>
body { width:${W}px; height:${H}px; background:transparent;
font-family:'Arial Black',Impact,sans-serif; color:#fff; }
.pill-wrap { position:absolute; left:50%; top:${Math.round(H*2/3)}px;
transform:translate(-50%,-50%); }
.pill { display:flex; flex-direction:column; align-items:center;
padding:28px 64px; border-radius:80px; border:3px solid transparent;
background-image:
linear-gradient(rgba(11,11,12,0.96), rgba(11,11,12,0.96)),
linear-gradient(135deg, #a855f7 0%, #ec4899 50%, #f97316 100%);
background-origin:border-box; background-clip:padding-box, border-box;
box-shadow: 0 10px 40px rgba(168,85,247,0.45); }
.pre, .post { font-weight:900; font-size:56px; text-transform:uppercase;
white-space:nowrap; }
.post { font-size:42px; opacity:0.92; }
.keyword { font-weight:900; font-size:140px; text-transform:uppercase;
background:linear-gradient(90deg, #a855f7 0%, #ec4899 50%, #f97316 100%);
-webkit-background-clip:text; color:transparent; }
</style></head>
<body><div class="pill-wrap"><div class="pill">
<div class="pre">comment</div>
<div class="keyword">AI</div>
<div class="post">for the setup</div>
</div></div></body></html>`;

await fs.writeFile('pill.html', html);
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: W, height: H } });
await page.goto('file://' + process.cwd() + '/pill.html');
await page.screenshot({ path: 'cta-pill.png', type: 'png', omitBackground: true });
await browser.close();

Run with node render-pill.mjs and you get a 1080x1920 PNG with a transparent background.

Step 7: Overlay the CTA on the last few seconds

bash
ffmpeg -y -i final.mp4 -loop 1 -i cta-pill.png \
-filter_complex "[0:v][1:v]overlay=0:0:enable='gte(t,7)':format=auto,format=yuv420p" \
-c:v libx264 -profile:v high -level:v 4.0 -pix_fmt yuv420p \
-preset medium -crf 18 \
-c:a copy -movflags +faststart -shortest \
final-with-cta.mp4

Two non-obvious bits:

  1. -pix_fmt yuv420p is mandatory. Without it, ffmpeg defaults to yuv444p when there's a PNG input in the chain, and a lot of players (QuickTime, parts of the Adobe stack, some browsers) refuse to play yuv444p H.264. Set it explicitly.
  2. -loop 1 -i cta-pill.png turns the PNG into an infinite virtual video stream. Without -loop 1, the PNG is one frame and the overlay disappears immediately.

The enable='gte(t,7)' clause makes the pill appear at 7 seconds and persist through the end of the video.

Why the keyframe trick works

Here's the mental model. Most AI video models are essentially "predict the next frame given the previous frames and the prompt." Without an end frame, the model has to invent its own ending — which means it drifts toward whatever it considers an interesting attractor, often unrelated to your intent.

Give it an end frame, and the problem changes. Now the model is solving an interpolation problem with hard constraints on both ends. It can't drift, because it has to land on your specified final state. The motion in between is the model's job, but the destination is yours.

This is the same reason inbetweening works in traditional animation. The keyframes are the contract. Everything else is just smoothing.

What I'd change next time

  • Two takes of the end frame. I got lucky on the first try with the end frame, but the cyborg's eye color is a tiny detail you can't see in a thumbnail-sized still. Worth generating 2-3 candidates and picking the one with the brightest glow.
  • A 5-second cut for TikTok. This 10s version is great for IG and YouTube Shorts but TikTok rewards faster hooks. The seedance prompt would just compress the timeline beats.
  • Hard cut on the CTA. I used gte(t,7) which is an instant on. A 0.3s alpha fade-in would be smoother — I tried it first but it broke the ffmpeg alpha pipeline, and a hard cut at the moment the cyborg's eyes flare actually reads as deliberate.

Try it

Comment AI on the Instagram reel and I'll DM you the prompts as a copy-paste pack.

Want a hand?

Book a 30-min call.

Walk through your stack with us. We'll find the bottleneck and map out the exact wiring you need — free.

Book the callFree intro · 30 min · cal.com
Nano Flow

© 2026 Nano Flow. All rights reserved.