13. Dynamic scenes
So far every listing has exactly three rooms. Real properties have variable counts โ sometimes 2 rooms, sometimes 10. The iterate property on a scene tells JSON2Video to repeat that scene once per item in an array, exposing each item as a scoped variable. This chapter renders a video with one scene per room, where the rooms come from a single array.
Prerequisites: chapter 12. Iterate scenes use the same {{ variable }} syntax to read the current item.
Step 1 โ Define the rooms array
Add a rooms variable at movie level. Each item is an object with whatever fields the iterating scene needs.
{
"variables": {
"address": "123 Oak Street",
"rooms": [
{ "name": "Exterior", "image": "https://cdn.json2video.com/assets/images/sample-house-front.jpg" },
{ "name": "Chef's Kitchen", "image": "https://cdn.json2video.com/assets/images/sample-house-kitchen.jpg" },
{ "name": "Master Bedroom", "image": "https://cdn.json2video.com/assets/images/sample-house-bedroom.jpg" },
{ "name": "Living Room", "image": "https://cdn.json2video.com/assets/images/sample-house-living.jpg" },
{ "name": "Backyard", "image": "https://cdn.json2video.com/assets/images/sample-house-backyard.jpg" }
]
}
}
Step 2 โ A single iterating scene
A scene with iterate: "rooms" (where "rooms" is a variable name pointing at an array) is expanded into N scenes โ one per array item. Inside the scene, the current item is exposed under a scope you pick with iterate-as. If omitted, the default name is item.
{
"duration": 4,
"transition": { "style": "fade", "duration": 0.5 },
"iterate": "rooms",
"iterate-as": "room",
"elements": [
{ "type": "image", "src": "{{ room.image }}" },
{ "type": "text", "text": "{{ room.name }}", "position": "top-left", "x": 60, "y": 60 }
]
}
If rooms has 5 items, this single definition expands to 5 scenes, each rendering its own image and label.
Step 3 โ Keep the title card scene as-is
The opening title card has no iteration โ it appears once. Place it before the iterating scene; the iterating scene comes second.
{
"scenes": [
{
"duration": 4,
"elements": [
{
"type": "component",
"component": "basic/000",
"settings": { "headline": "FOR SALE", "subline": "{{address}}" }
}
]
},
{
"duration": 4,
"transition": { "style": "fade", "duration": 0.5 },
"iterate": "rooms",
"iterate-as": "room",
"elements": [
{ "type": "image", "src": "{{ room.image }}" },
{ "type": "text", "text": "{{ room.name }}", "position": "top-left", "x": 60, "y": 60 }
]
}
]
}
The final movie is title card + N room scenes.
Step 4 โ Voice-over that names each room
The chapter-9 voice line was static. Move the voice element into the iterating scene so each room scene gets its own short narration. Now we have one voice line per room.
{
"duration": 4,
"transition": { "style": "fade", "duration": 0.5 },
"iterate": "rooms",
"iterate-as": "room",
"elements": [
{ "type": "image", "src": "{{ room.image }}" },
{ "type": "text", "text": "{{ room.name }}", "position": "top-left", "x": 60, "y": 60 },
{
"type": "voice",
"text": "Step inside {{ room.name }}.",
"voice": "en-US-EmmaMultilingualNeural"
}
]
}
Note โ scene-level voice elements use the scene-local timeline. With no
start, they begin at scene start.
The complete final JSON
{
"resolution": "full-hd",
"variables": {
"address": "123 Oak Street",
"rooms": [
{ "name": "Exterior", "image": "https://cdn.json2video.com/assets/images/sample-house-front.jpg" },
{ "name": "Chef's Kitchen", "image": "https://cdn.json2video.com/assets/images/sample-house-kitchen.jpg" },
{ "name": "Master Bedroom", "image": "https://cdn.json2video.com/assets/images/sample-house-bedroom.jpg" },
{ "name": "Living Room", "image": "https://cdn.json2video.com/assets/images/sample-house-living.jpg" },
{ "name": "Backyard", "image": "https://cdn.json2video.com/assets/images/sample-house-backyard.jpg" }
]
},
"elements": [
{
"type": "audio",
"src": "https://cdn.json2video.com/assets/audios/uplifting-corporate.mp3",
"volume": 0.4
},
{
"type": "subtitles",
"language": "en",
"settings": {
"style": "boxed-word",
"font-family": "Inter",
"font-size": 90,
"font-color": "#FFFFFF",
"position": "bottom-center",
"all-caps": true,
"box-color": "#0E7C66"
}
}
],
"scenes": [
{
"duration": 4,
"elements": [
{
"type": "component",
"component": "basic/000",
"settings": { "headline": "FOR SALE", "subline": "{{address}}" }
}
]
},
{
"duration": 4,
"transition": { "style": "fade", "duration": 0.5 },
"iterate": "rooms",
"iterate-as": "room",
"elements": [
{ "type": "image", "src": "{{ room.image }}" },
{ "type": "text", "text": "{{ room.name }}", "position": "top-left", "x": 60, "y": 60 },
{
"type": "voice",
"text": "Step inside {{ room.name }}.",
"voice": "en-US-EmmaMultilingualNeural"
}
]
}
]
}
Expected output
A 24-second listing: title card (4 s) + five room scenes (4 s each), each with its own narration. To render a property with three rooms instead of five, change rooms.length โ the movie automatically resizes. Sample render: tutorial-13.mp4 (placeholder).
What you learned
iterate: "<variable-name>"repeats a scene once per item in that array.iterate-asnames the per-iteration scope; default isitem.- Inside the iterating scene,
{{ scope.field }}reads the current item's fields. - The number of scenes becomes data-driven without re-writing the movie.
Going further
Iteration combined with templates (chapter 11) is the killer pattern for bulk video generation: store the template once, drive 1000 properties through the same POST /v2/movies with different rooms arrays.