Homecoming
One still, then eight seconds of film with sound.
The scene
Late afternoon in the twelfth lunar month, an old village in western Hunan: grey-tiled wooden houses on a hillside, cooking smoke rising from the roofs into cold mist. A young migrant worker in his twenties in a cheap padded jacket walks up a worn stone path with a large woven travel bag on his shoulder. At the open door of a timber house, his elderly mother in a dark blue cotton jacket waits, one hand on the door frame. Red couplets on the door, dried chillies and cured meat hanging under the eaves. Wide shot, eye level, 40mm.

Elapsed–
Cost$0.835
Recorded run, replayed faster than it ran.
$0.835this recorded run's cost
- 720p, 8 s with sounddefault≈ $0.835
- 1080p, 8 s with sound≈ $1.635
Forking copies the 2 steps into your dashboard. You change the input, press Run, and each call is billed to your balance.
Build it yourself
Each step is one request to the Hyperouter API with your key. A later step reads an earlier one's output through {{steps.<id>…}}, and your inputs through {{vars.<name>}}. Models: bytedance/seedream-5.0-lite, alibaba/wan3.0.
The 2 requests
Draw the opening frame
POST /v1/images/generationsbytedance/seedream-5.0-lite1 image · 2560×1440{ "model": "bytedance/seedream-5.0-lite", "prompt": "{{vars.idea}} Documentary realism shot on 65mm large-format film: natural and practical light only, deep blacks with detail held in the shadows, fine organic film grain, true skin texture with pores and wrinkles, no retouching, no digital sharpening, no beauty filter.", "size": "2560x1440", "n": 1 }Film the homecoming
POST /v1/videosalibaba/wan3.0720p · 8 s · 16:9 · sound{ "model": "alibaba/wan3.0", "prompt": "{{vars.motion}}", "first_frame": "{{steps.still.url[0]}}", "seconds": 8, "resolution": "720p", "ratio": "16:9", "audio": true }
Run the whole pipeline from code
API=https://api.hyperouter.app/v1
call() { curl -s "$API/$1" -H "Authorization: Bearer $HYPEROUTER_API_KEY" -H 'Content-Type: application/json' "${@:2}"; }
LOOK='Documentary realism shot on 65mm large-format film: natural and practical light only, deep blacks with detail held in the shadows, fine organic film grain, true skin texture with pores and wrinkles, no retouching, no digital sharpening, no beauty filter.'
IDEA='Late afternoon in the twelfth lunar month, an old village in western Hunan: grey-tiled wooden houses on a hillside, cooking smoke rising from the roofs into cold mist. A young migrant worker in his twenties in a cheap padded jacket walks up a worn stone path with a large woven travel bag on his shoulder. At the open door of a timber house, his elderly mother in a dark blue cotton jacket waits, one hand on the door frame. Red couplets on the door, dried chillies and cured meat hanging under the eaves. Wide shot, eye level, 40mm.'
MOTION='The young man climbs the last stone steps toward the open door; his mother lets go of the door frame and takes two quick steps toward him, then stops, her hand at her mouth. Cooking smoke drifts across the roofs, the dried chillies sway a little. Slow push-in from behind his shoulder. Sound: cold wind, his footsteps on stone, a dog barking far off, a rooster, the faint crackle of a stove inside. No music, no dialogue, no text.'
# 1. the opening frame
STILL=$(jq -n --arg p "$IDEA $LOOK" '{model:"bytedance/seedream-5.0-lite", prompt:$p, size:"2560x1440", n:1}' | call images/generations -d @- | jq -r '.data[0].url')
# 2. eight seconds with sound from that frame: create, then poll
ID=$(jq -n --arg p "$MOTION" --arg f "$STILL" '{model:"alibaba/wan3.0", prompt:$p, first_frame:$f, seconds:8, resolution:"720p", ratio:"16:9", audio:true}' | call videos -d @- | jq -r .id)
while s=$(call videos/$ID | jq -r .status); [ "$s" = queued ] || [ "$s" = in_progress ]; do sleep 5; done
echo "$s"
call videos/$ID/content -L -o film.mp4
// run.mjs import OpenAI from 'openai'; const c = new OpenAI({ baseURL: 'https://api.hyperouter.app/v1', apiKey: process.env.HYPEROUTER_API_KEY }); const LOOK = 'Documentary realism shot on 65mm large-format film: natural and practical light only, deep blacks with detail held in the shadows, fine organic film grain, true skin texture with pores and wrinkles, no retouching, no digital sharpening, no beauty filter.'; const IDEA = 'Late afternoon in the twelfth lunar month, an old village in western Hunan: grey-tiled wooden houses on a hillside, cooking smoke rising from the roofs into cold mist. A young migrant worker in his twenties in a cheap padded jacket walks up a worn stone path with a large woven travel bag on his shoulder. At the open door of a timber house, his elderly mother in a dark blue cotton jacket waits, one hand on the door frame. Red couplets on the door, dried chillies and cured meat hanging under the eaves. Wide shot, eye level, 40mm.'; const MOTION = 'The young man climbs the last stone steps toward the open door; his mother lets go of the door frame and takes two quick steps toward him, then stops, her hand at her mouth. Cooking smoke drifts across the roofs, the dried chillies sway a little. Slow push-in from behind his shoulder. Sound: cold wind, his footsteps on stone, a dog barking far off, a rooster, the faint crackle of a stove inside. No music, no dialogue, no text.'; // 1. the opening frame const still = (await c.post('/images/generations', { body: { model: 'bytedance/seedream-5.0-lite', prompt: IDEA + ' ' + LOOK, size: '2560x1440', n: 1 } })).data[0].url; // 2. eight seconds with sound from that frame: create, then poll let v = await c.post('/videos', { body: { model: 'alibaba/wan3.0', prompt: MOTION, first_frame: still, seconds: 8, resolution: '720p', ratio: '16:9', audio: true } }); while (['queued', 'in_progress'].includes(v.status)) { await new Promise((ok) => setTimeout(ok, 5000)); v = await c.get('/videos/' + v.id); } if (v.status !== 'completed') throw new Error(JSON.stringify(v.error)); console.log((await c.get('/generations/' + v.id)).data.outputs[0].url);
import os, time from openai import OpenAI c = OpenAI(base_url='https://api.hyperouter.app/v1', api_key=os.environ['HYPEROUTER_API_KEY']) LOOK = 'Documentary realism shot on 65mm large-format film: natural and practical light only, deep blacks with detail held in the shadows, fine organic film grain, true skin texture with pores and wrinkles, no retouching, no digital sharpening, no beauty filter.' IDEA = 'Late afternoon in the twelfth lunar month, an old village in western Hunan: grey-tiled wooden houses on a hillside, cooking smoke rising from the roofs into cold mist. A young migrant worker in his twenties in a cheap padded jacket walks up a worn stone path with a large woven travel bag on his shoulder. At the open door of a timber house, his elderly mother in a dark blue cotton jacket waits, one hand on the door frame. Red couplets on the door, dried chillies and cured meat hanging under the eaves. Wide shot, eye level, 40mm.' MOTION = 'The young man climbs the last stone steps toward the open door; his mother lets go of the door frame and takes two quick steps toward him, then stops, her hand at her mouth. Cooking smoke drifts across the roofs, the dried chillies sway a little. Slow push-in from behind his shoulder. Sound: cold wind, his footsteps on stone, a dog barking far off, a rooster, the faint crackle of a stove inside. No music, no dialogue, no text.' # 1. the opening frame still = c.post('/images/generations', cast_to=object, body={ 'model': 'bytedance/seedream-5.0-lite', 'prompt': IDEA + ' ' + LOOK, 'size': '2560x1440', 'n': 1})['data'][0]['url'] # 2. eight seconds with sound from that frame: create, then poll v = c.post('/videos', cast_to=object, body={ 'model': 'alibaba/wan3.0', 'prompt': MOTION, 'first_frame': still, 'seconds': 8, 'resolution': '720p', 'ratio': '16:9', 'audio': True}) while v['status'] in ('queued', 'in_progress'): time.sleep(5) v = c.get('/videos/' + v['id'], cast_to=object) assert v['status'] == 'completed', v['error'] print(c.get('/generations/' + v['id'], cast_to=object)['data']['outputs'][0]['url'])
Run Homecoming on your account
One still, then eight seconds of film with sound. Fork it, change the input, and run it from the dashboard: ≈ $0.835 per run at the default settings.