update folder structure for musicspot_generator
This commit is contained in:
BIN
src/musicspot_generator/v1/cetridesete/face.png
Normal file
BIN
src/musicspot_generator/v1/cetridesete/face.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
src/musicspot_generator/v1/cetridesete/face2.png
Normal file
BIN
src/musicspot_generator/v1/cetridesete/face2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
598
src/musicspot_generator/v1/cetridesete/scenes.json
Normal file
598
src/musicspot_generator/v1/cetridesete/scenes.json
Normal file
@ -0,0 +1,598 @@
|
||||
{
|
||||
"song": {
|
||||
"title": "Četrdesete: Svjetlo kroz Maglu",
|
||||
"artist": "Radni Front",
|
||||
"genre": "Cinematic Pop/Rock",
|
||||
"mood": "Gritty, uplifting, hopeful"
|
||||
},
|
||||
"character": {
|
||||
"bodyType": "average build, slightly athletic, in his 40s",
|
||||
"hairStyle": "short side-part, light stubble",
|
||||
"accessories": "leather messenger bag, analog watch, simple ring"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"time": "Morning",
|
||||
"location": "Foggy city street at dawn",
|
||||
"outfit": "charcoal wool coat over navy blazer, white oxford shirt, dark chinos, leather derbies, grey scarf; takeaway coffee in hand",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking briskly with coffee",
|
||||
"action": "exhaling visible breath in cold air",
|
||||
"camera": [
|
||||
"full-body frontal walk through light shafts in fog",
|
||||
"low angle on shoes splashing a thin puddle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pausing at crosswalk",
|
||||
"action": "checking watch then stepping forward",
|
||||
"camera": [
|
||||
"close-up on watch face catching sun flare",
|
||||
"three-quarter side track across zebra lines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "tight grip on cup",
|
||||
"action": "lifting cup for a sip",
|
||||
"camera": [
|
||||
"macro fingers on cup sleeve with steam",
|
||||
"profile head-and-shoulders backlit by hazy sun"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "steady stride",
|
||||
"action": "adjusting scarf in breeze",
|
||||
"camera": [
|
||||
"telephoto compression down foggy avenue",
|
||||
"rear follow shot with scarf rim-lit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "determined gaze",
|
||||
"action": "looking ahead into sunlight",
|
||||
"camera": [
|
||||
"tight face with soft lens bloom",
|
||||
"over-shoulder toward blinding sky gap"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"time": "Morning",
|
||||
"location": "Tram interior rocking through city",
|
||||
"outfit": "navy blazer, knit crewneck, white shirt, dark jeans, leather sneakers; coffee in hand",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing in tram",
|
||||
"action": "holding strap with one hand, coffee in the other",
|
||||
"camera": [
|
||||
"medium inside tram, window condensation streaks",
|
||||
"front angle from aisle with passing light bands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning against pole",
|
||||
"action": "checking phone briefly",
|
||||
"camera": [
|
||||
"over-shoulder to phone screen glow",
|
||||
"side profile with rim light from window"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "looking out window",
|
||||
"action": "soft smile seeing morning city",
|
||||
"camera": [
|
||||
"through-glass face framed by droplets",
|
||||
"exterior-to-interior angle catching reflection layers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "steady stance",
|
||||
"action": "taking small sip as tram turns",
|
||||
"camera": [
|
||||
"low angle on cup tilt and sleeve",
|
||||
"rear quarter shot showing sway of carriage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "composed",
|
||||
"action": "pocketing phone, focusing forward",
|
||||
"camera": [
|
||||
"chest-up push-in down the aisle",
|
||||
"top-down seat pattern with soft bloom"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"time": "Morning",
|
||||
"location": "Modern office desk with soft skylight",
|
||||
"outfit": "light grey blazer, pale blue shirt, dark chinos, brown brogues; ID lanyard",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "seated typing",
|
||||
"action": "focused work with subtle nods",
|
||||
"camera": [
|
||||
"medium desk-side angle with window beams",
|
||||
"close-up fingers on keyboard with keycap sheen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "reviewing papers",
|
||||
"action": "marking with pen",
|
||||
"camera": [
|
||||
"top-down documents in stripey sunlight",
|
||||
"front low angle across desk edge"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "phone to ear",
|
||||
"action": "short professional conversation",
|
||||
"camera": [
|
||||
"profile with rim-lit jawline",
|
||||
"over-shoulder to city glow outside"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "stretching shoulders",
|
||||
"action": "exhaling, sip of water",
|
||||
"camera": [
|
||||
"medium with glass prisming light",
|
||||
"close-up on water surface ripples"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "refocused",
|
||||
"action": "resuming typing with resolve",
|
||||
"camera": [
|
||||
"front push-in past monitor edge",
|
||||
"rear silhouette against bright window"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"time": "Late Morning",
|
||||
"location": "Office glass meeting room",
|
||||
"outfit": "navy sport coat, white shirt, knit tie, tailored trousers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing at screen",
|
||||
"action": "pointing to chart, calm tone",
|
||||
"camera": [
|
||||
"three-quarter presenter through glass reflections",
|
||||
"over-shoulder to slide glow on faces"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "listening",
|
||||
"action": "nodding, hands clasped",
|
||||
"camera": [
|
||||
"medium frontal with rim edge light",
|
||||
"tight hands interlaced catching sheen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "whiteboard note",
|
||||
"action": "writing key word",
|
||||
"camera": [
|
||||
"side on marker tip against board",
|
||||
"over-shoulder on word under skylight stripe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "hand gestures",
|
||||
"action": "framing idea in air",
|
||||
"camera": [
|
||||
"front medium with floating dust motes",
|
||||
"profile gesture silhouette against window"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "closing remark",
|
||||
"action": "small confident smile",
|
||||
"camera": [
|
||||
"tight smile with gentle bloom",
|
||||
"wide room applauding in soft backlight"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"time": "Midday",
|
||||
"location": "Quiet park bench under soft sun",
|
||||
"outfit": "olive field jacket over white shirt, navy chinos, sneakers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "seated on bench",
|
||||
"action": "unwrapping sandwich",
|
||||
"camera": [
|
||||
"wide bench under dappled leaves",
|
||||
"close-up foil crackle catching sparkles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "bite and look up",
|
||||
"action": "watching birds",
|
||||
"camera": [
|
||||
"tight mouthful with flare peeking",
|
||||
"low up-angle to glowing canopy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "relaxed lean",
|
||||
"action": "closing eyes briefly",
|
||||
"camera": [
|
||||
"front push-in eyes closed in sun warmth",
|
||||
"overhead bench and soft shadow lace"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "checking phone",
|
||||
"action": "soft smile at message",
|
||||
"camera": [
|
||||
"over-shoulder to screen in shade",
|
||||
"side profile with sun peeking lens flare"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "standing stretch",
|
||||
"action": "deep breath hands on hips",
|
||||
"camera": [
|
||||
"rear sun halo and long shadow",
|
||||
"front medium with leaf bokeh confetti"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"time": "Afternoon",
|
||||
"location": "Open office collaboration area",
|
||||
"outfit": "rolled-sleeve shirt, blazer off, vest optional, dark trousers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing with teammates",
|
||||
"action": "high-five and laugh",
|
||||
"camera": [
|
||||
"wide group under skylight glow",
|
||||
"tight palms meeting with light burst"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pointing at laptop",
|
||||
"action": "explaining step-by-step",
|
||||
"camera": [
|
||||
"over-shoulder to UI reflecting in eyes",
|
||||
"front trio with bright window beams"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "shared joke",
|
||||
"action": "covering mouth laughing",
|
||||
"camera": [
|
||||
"tight eyes creasing with sparkle",
|
||||
"side candid smiles with lens bloom"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "sticky note placement",
|
||||
"action": "slapping idea on board",
|
||||
"camera": [
|
||||
"macro note corner catching shine",
|
||||
"front push-in to colorful board grid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "wrap-up clap",
|
||||
"action": "small bow to team",
|
||||
"camera": [
|
||||
"medium applause with soft halos",
|
||||
"rear shoulders rim-lit against corridor"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 7,
|
||||
"time": "Evening",
|
||||
"location": "Recording studio vocal booth",
|
||||
"outfit": "black henley under dark blazer, dark jeans; studio headphones, pop filter",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing at mic",
|
||||
"action": "closing eyes and singing",
|
||||
"camera": [
|
||||
"medium mic and pop filter with tube glow",
|
||||
"profile head tilt with headphone sheen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "one hand on headphone",
|
||||
"action": "finding pitch",
|
||||
"camera": [
|
||||
"tight hand on ear cup",
|
||||
"over-shoulder to waveform screen in control room"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning toward mic",
|
||||
"action": "delivering powerful line",
|
||||
"camera": [
|
||||
"front intense eyes past grille",
|
||||
"low angle along mic stand to face"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "step back",
|
||||
"action": "nod to beat, smile",
|
||||
"camera": [
|
||||
"wide booth with warm bokeh bulbs",
|
||||
"tight smile reflected in glass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "hands open",
|
||||
"action": "finishing phrase softly",
|
||||
"camera": [
|
||||
"front soft flare across frame",
|
||||
"overhead hands lowering into light cone"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 8,
|
||||
"time": "Golden Hour",
|
||||
"location": "City park path with family",
|
||||
"outfit": "sand blazer, light knit, dark denim; family in cozy casual",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "holding partner’s hand",
|
||||
"action": "walking with child skipping ahead",
|
||||
"camera": [
|
||||
"rear wide with low sun flare",
|
||||
"front medium through tree bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "lifting child",
|
||||
"action": "spinning gently",
|
||||
"camera": [
|
||||
"front slow shutter light trails around",
|
||||
"top-down arms forming circle with sun rim"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "group hug",
|
||||
"action": "closing eyes contentedly",
|
||||
"camera": [
|
||||
"tight embrace hands with ring glint",
|
||||
"side cheek-to-hair halo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "pointing to sky",
|
||||
"action": "showing plane to child",
|
||||
"camera": [
|
||||
"up-angle to contrail through warm haze",
|
||||
"front medium faces reflecting sky"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "hands intertwined",
|
||||
"action": "walking toward camera",
|
||||
"camera": [
|
||||
"front slow push with golden confetti bokeh",
|
||||
"low angle on joined hands swinging"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 9,
|
||||
"time": "Night",
|
||||
"location": "City viewpoint with beautiful skyline",
|
||||
"outfit": "charcoal overcoat, black turtleneck, tailored trousers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "leaning on railing",
|
||||
"action": "taking in skyline",
|
||||
"camera": [
|
||||
"wide skyline as glittering backdrop",
|
||||
"profile rim light from city glow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "deep breath",
|
||||
"action": "exhale mist into night",
|
||||
"camera": [
|
||||
"tight breath vapor lit by neon",
|
||||
"rear silhouette against bokeh lights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "phone photo",
|
||||
"action": "capturing skyline",
|
||||
"camera": [
|
||||
"over-shoulder to bright screen framing towers",
|
||||
"low angle to phone and light crown above"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "hands in pockets",
|
||||
"action": "swaying to distant music",
|
||||
"camera": [
|
||||
"medium chest-up with drifting car streaks",
|
||||
"tight shoe tapping in puddle reflection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "confident gaze",
|
||||
"action": "looking past camera",
|
||||
"camera": [
|
||||
"front tight eyes with city sparkles",
|
||||
"top-down platform grid glimmering"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 10,
|
||||
"time": "Night",
|
||||
"location": "Office district streets after hours",
|
||||
"outfit": "dark blazer, open collar shirt, slim trousers, chelsea boots",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking alone",
|
||||
"action": "hands in pockets",
|
||||
"camera": [
|
||||
"long-lens frontal with pearl-like streetlights",
|
||||
"rear follow on wet pavement reflections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pause under lamp",
|
||||
"action": "looking up between towers",
|
||||
"camera": [
|
||||
"upward angle of converging buildings and lamp star",
|
||||
"side silhouette against lobby glow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "check messages",
|
||||
"action": "small nod of relief",
|
||||
"camera": [
|
||||
"over-shoulder phone light on face",
|
||||
"handheld parallax of glass light columns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "crossing street",
|
||||
"action": "steady stride",
|
||||
"camera": [
|
||||
"wide zebra stripes with mirror reflections",
|
||||
"low angle heel strike and passing headlight streak"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "brief smile",
|
||||
"action": "exhale, continue walking",
|
||||
"camera": [
|
||||
"tight smile with neon glimmer",
|
||||
"front slow push through flare streaks"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 11,
|
||||
"time": "Night",
|
||||
"location": "Home living room, warm lamps",
|
||||
"outfit": "soft cardigan over tee, lounge chinos, socks",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sinking into sofa",
|
||||
"action": "deep relieved breath",
|
||||
"camera": [
|
||||
"medium cozy frame with lamp bloom",
|
||||
"low angle to floor lamp starburst"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "family photo glance",
|
||||
"action": "gentle smile at frame",
|
||||
"camera": [
|
||||
"close-up photo glass catching sparkle",
|
||||
"side hand brushing frame with glint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "stretch and yawn",
|
||||
"action": "neck roll, relaxed shoulders",
|
||||
"camera": [
|
||||
"front medium as light wraps softly",
|
||||
"rear silhouette against curtained window halo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "notebook moment",
|
||||
"action": "jotting tomorrow’s plan",
|
||||
"camera": [
|
||||
"top-down page and pen tip glint",
|
||||
"three-quarter profile calm focus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "closing lights",
|
||||
"action": "switching lamp off",
|
||||
"camera": [
|
||||
"tight finger on switch—tiny spark",
|
||||
"wide room dimming to city twinkle outside"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
68
src/musicspot_generator/v1/cetridesete/scenes2.json
Normal file
68
src/musicspot_generator/v1/cetridesete/scenes2.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"song": {
|
||||
"title": "Četrdesete: Svjetlo kroz Maglu",
|
||||
"artist": "Radni Front",
|
||||
"genre": "Cinematic Pop/Rock",
|
||||
"mood": "Gritty, uplifting, hopeful"
|
||||
},
|
||||
"character": {
|
||||
"bodyType": "average build, slightly athletic, in his 40s",
|
||||
"hairStyle": "short side-part, light stubble",
|
||||
"accessories": "leather messenger bag, analog watch, simple ring"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"time": "Morning",
|
||||
"location": "Foggy city street at dawn",
|
||||
"outfit": "down jacket, scarf, jeans, boots, t-shirt, hiphop style",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking ",
|
||||
"action": "exhaling visible breath in cold air",
|
||||
"camera": [
|
||||
"full-body frontal walk through light shafts in fog",
|
||||
"low angle on shoes splashing a thin puddle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "walking hands in pockets",
|
||||
"action": "",
|
||||
"camera": [
|
||||
"close-up on watch face catching sun flare",
|
||||
"three-quarter side track across zebra lines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "standing hands in pockets",
|
||||
"action": "",
|
||||
"camera": [
|
||||
"macro fingers on cup sleeve with steam",
|
||||
"profile head-and-shoulders backlit by hazy sun"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "steady stride",
|
||||
"action": "adjusting scarf in breeze",
|
||||
"camera": [
|
||||
"telephoto compression down foggy avenue",
|
||||
"rear follow shot with scarf rim-lit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "determined gaze",
|
||||
"action": "looking ahead into sunlight",
|
||||
"camera": [
|
||||
"tight face with soft lens bloom",
|
||||
"over-shoulder toward blinding sky gap"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
src/musicspot_generator/v1/cetridesete/song.mp3
Normal file
BIN
src/musicspot_generator/v1/cetridesete/song.mp3
Normal file
Binary file not shown.
BIN
src/musicspot_generator/v1/fire in the night/face.png
Normal file
BIN
src/musicspot_generator/v1/fire in the night/face.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
786
src/musicspot_generator/v1/fire in the night/scenes.json
Normal file
786
src/musicspot_generator/v1/fire in the night/scenes.json
Normal file
@ -0,0 +1,786 @@
|
||||
{
|
||||
"song": {
|
||||
"title": "Svjetlo kroz Maglu",
|
||||
"artist": "Radni Dan",
|
||||
"genre": "Pop Rock / Motivational Rap",
|
||||
"mood": "Hopeful, gritty, determined"
|
||||
},
|
||||
"character": {
|
||||
"bodyType": "average 40s male, sturdy build",
|
||||
"hairStyle": "short neat hair with slight side part, light stubble",
|
||||
"outfitPalette": "navy, charcoal, camel, white, subtle textures",
|
||||
"defaultOutfit": "smart-casual: tailored blazer, oxford shirt (top button open), slim chinos, leather sneakers or derby shoes, minimalist watch, messenger bag"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"lyricAnchor": "intro",
|
||||
"time": "Early Morning",
|
||||
"location": "Foggy street in a quiet city block",
|
||||
"outfit": "camel coat over navy blazer and white oxford, charcoal chinos, leather sneakers; steaming paper coffee cup in hand",
|
||||
"lightFX": "soft ground fog, cool blue ambience, warm shop-window spill, rays through mist",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking steadily with coffee, shoulders relaxed",
|
||||
"action": "breath visible in cold air",
|
||||
"camera": [
|
||||
"full body tracking through fog with distant headlights bokeh",
|
||||
"side shot catching coffee steam in backlight",
|
||||
"face zoom in with gentle lens flare from streetlamp",
|
||||
"overhead drone-lite glide showing puddle reflections",
|
||||
"back shot with long god rays slicing mist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pauses at crosswalk",
|
||||
"action": "checks watch, sips coffee",
|
||||
"camera": [
|
||||
"low angle shoe splash past a glowing puddle",
|
||||
"medium shot watch face catching specular highlight",
|
||||
"face zoom in through drifting fog",
|
||||
"back shot red-to-green signal glow on mist",
|
||||
"overhead crosswalk stripes fading into haze"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "resumes walk",
|
||||
"action": "adjusts strap of messenger bag",
|
||||
"camera": [
|
||||
"tracking three-quarter with storefront light streaks",
|
||||
"side shot shallow DOF light orbs (bokeh)",
|
||||
"face zoom in calm focus",
|
||||
"reflected view in wet window pane",
|
||||
"wide establishing with soft sunrise rim light"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "stops to let bicycle pass",
|
||||
"action": "nods politely",
|
||||
"camera": [
|
||||
"over-shoulder bicycle headlights streaking",
|
||||
"medium profile with fog swirls lit from back",
|
||||
"ground-level reflection of both in puddle",
|
||||
"wide silhouette against pale dawn sky",
|
||||
"face close-up catching tiny snowlike mist droplets"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "steps onto tram platform edge",
|
||||
"action": "exhales, looks down the track",
|
||||
"camera": [
|
||||
"back shot rails vanishing into fog",
|
||||
"side shot coffee steam crossing light beam",
|
||||
"face zoom in hopeful gaze",
|
||||
"overhead platform LEDs forming dotted trail",
|
||||
"low angle rails with subtle lens flare"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"lyricAnchor": "verse A",
|
||||
"time": "Morning",
|
||||
"location": "City tram interior, gently swaying",
|
||||
"outfit": "navy blazer, white oxford, grey chinos; coffee cup; transit card",
|
||||
"lightFX": "cool daylight through foggy windows, window streak glares, rhythmic flicker of tunnels",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing near door, one hand on pole",
|
||||
"action": "sips coffee, eyes on passing streets",
|
||||
"camera": [
|
||||
"full body with window streaks bokeh outside",
|
||||
"side shot with parallax of city blur",
|
||||
"face zoom in catching soft rim light",
|
||||
"reflection shot in tram door glass",
|
||||
"overhead passengers’ silhouettes in soft haze"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leans on pole",
|
||||
"action": "checks phone briefly (calendar alert)",
|
||||
"camera": [
|
||||
"close on phone UI glow reflecting on face",
|
||||
"low angle hand + coffee, light streaks above",
|
||||
"medium shot over-shoulder to window",
|
||||
"face zoom in steadied breathing",
|
||||
"wide carriage shot with light pulses"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "shifts stance with sway",
|
||||
"action": "tightens blazer button",
|
||||
"camera": [
|
||||
"profile tightening button with specular highlight",
|
||||
"back shot rows of seats in perspective",
|
||||
"face zoom in determined eyes",
|
||||
"window reflection double exposure feel",
|
||||
"handheld subtle sway for realism"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "glances at a child smiling",
|
||||
"action": "returns a soft smile",
|
||||
"camera": [
|
||||
"medium two-shot with warm sun beam",
|
||||
"face zoom in softened expression",
|
||||
"side shot catching dust motes in light",
|
||||
"overhead strap lights forming leading line",
|
||||
"wide interior with gentle motion blur"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "tram slows",
|
||||
"action": "prepares to step out",
|
||||
"camera": [
|
||||
"close on shoes as doors open, light washes floor",
|
||||
"back shot doors parting with faint lens flare",
|
||||
"face three-quarter with morning glow",
|
||||
"low angle step-down with steam from cup",
|
||||
"wide exterior as he exits into bright haze"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"lyricAnchor": "verse A",
|
||||
"time": "Late Morning",
|
||||
"location": "Modern office, clean lines, window light",
|
||||
"outfit": "blazer off on chair, rolled sleeves, oxford + chinos; ID badge",
|
||||
"lightFX": "soft skylight, bounce from white desks, screen glow highlights",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "seated typing",
|
||||
"action": "focused, steady pace",
|
||||
"camera": [
|
||||
"over-shoulder code/docs on monitor with gentle bloom",
|
||||
"side shot keypress rhythm, wristwatch glint",
|
||||
"face zoom in concentration with catchlight",
|
||||
"overhead tidy desk grid, coffee ring",
|
||||
"wide office depth with sunbeams"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "stands to stretch",
|
||||
"action": "rolls shoulders, exhales",
|
||||
"camera": [
|
||||
"medium profile with light streak on edges",
|
||||
"back shot window rim light tracing silhouette",
|
||||
"face close slight smile of relief",
|
||||
"low angle chair wheels reflecting light",
|
||||
"wide airy office, dust motes floating"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "points to sticky notes",
|
||||
"action": "organizes tasks",
|
||||
"camera": [
|
||||
"macro sticky notes with pen glide",
|
||||
"side shot hand gestures casting shadows",
|
||||
"face zoom in purposeful look",
|
||||
"overhead desk layout symmetry",
|
||||
"rack focus foreground notes → him"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "quick call with headset",
|
||||
"action": "nods, types one-handed",
|
||||
"camera": [
|
||||
"face close with soft headset LED glow",
|
||||
"side keyboard shot light skimming keys",
|
||||
"back shot monitor reflections",
|
||||
"low angle desk edge lens flare",
|
||||
"wide office with colleagues as bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "final keystroke & save",
|
||||
"action": "small fist pump",
|
||||
"camera": [
|
||||
"face zoom in subtle satisfaction",
|
||||
"overhead enter-key press highlight",
|
||||
"side shot progress bar completing",
|
||||
"back shot sun patch moving across floor",
|
||||
"wide with gentle parallax slide"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"lyricAnchor": "bridge",
|
||||
"time": "Noon",
|
||||
"location": "Office meeting room with glass walls",
|
||||
"outfit": "puts blazer back on, pocket square minimal",
|
||||
"lightFX": "top light soft panels, glass reflections, whiteboard glow",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing by screen",
|
||||
"action": "presenting calmly",
|
||||
"camera": [
|
||||
"three-quarter presenter with screen bloom",
|
||||
"side shot hand outlining charts",
|
||||
"face zoom in composed tone",
|
||||
"overhead table symmetry + notebooks",
|
||||
"glass reflection two-layer composition"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "listening to feedback",
|
||||
"action": "nods, writes key points",
|
||||
"camera": [
|
||||
"close pen tip gliding with light spark",
|
||||
"profile with colleagues blurred",
|
||||
"face zoom in attentive eyes",
|
||||
"back shot city light filtering",
|
||||
"low angle chair legs + floor sheen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "whiteboard stand",
|
||||
"action": "draws simple plan",
|
||||
"camera": [
|
||||
"over-shoulder marker stroke with squeak",
|
||||
"side shot board light wash",
|
||||
"macro marker cap click",
|
||||
"face zoom in confident smile",
|
||||
"wide room with glass reflections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "wraps up",
|
||||
"action": "thanks team with small bow",
|
||||
"camera": [
|
||||
"medium group claps, light bloom",
|
||||
"back shot handshake silhouette",
|
||||
"face close gratitude",
|
||||
"overhead chairs and cables geometric",
|
||||
"wide corridor outside glowing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "exits meeting room",
|
||||
"action": "deep breath reset",
|
||||
"camera": [
|
||||
"hallway tracking with specular highlights",
|
||||
"side shot blazer hem flutter",
|
||||
"face zoom in renewed focus",
|
||||
"reflection in glass wall double image",
|
||||
"low angle sun slice across floor"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"lyricAnchor": "bridge",
|
||||
"time": "Early Afternoon",
|
||||
"location": "City park bench under light trees",
|
||||
"outfit": "blazer off, sleeves rolled, relaxed tie-less",
|
||||
"lightFX": "dappled sun through leaves, pollen glitter bokeh, gentle breeze",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting on bench",
|
||||
"action": "unwraps simple sandwich",
|
||||
"camera": [
|
||||
"full body bench shot with leaf bokeh",
|
||||
"side shot paper crinkle detail",
|
||||
"face zoom in serene break",
|
||||
"overhead lunch + watch on wrist",
|
||||
"back shot path with cyclists light streaks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "takes first bite",
|
||||
"action": "closes eyes a second",
|
||||
"camera": [
|
||||
"close bite with sun rim on cheek",
|
||||
"profile crumbs, shallow DOF",
|
||||
"face zoom in small smile",
|
||||
"wide park pond sparkle",
|
||||
"low angle grass blades glowing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "checks notebook",
|
||||
"action": "jots quick line",
|
||||
"camera": [
|
||||
"macro ink glint",
|
||||
"side shot wrist veins and light",
|
||||
"overhead notebook grid clean",
|
||||
"back shot kite in distant sky",
|
||||
"face close pensive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "sips water",
|
||||
"action": "exhales, shoulders drop",
|
||||
"camera": [
|
||||
"close water bottle condensation sparkles",
|
||||
"profile sip with sun flare",
|
||||
"wide bench with trees swaying",
|
||||
"ground-level ants-eye leaves",
|
||||
"face gentle relief"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "stands to go",
|
||||
"action": "tucks notebook into bag",
|
||||
"camera": [
|
||||
"back shot dust motes in sun beam",
|
||||
"side shot bag flap catchlight",
|
||||
"low angle steps from gravel",
|
||||
"overhead bench now empty",
|
||||
"wide exit through shimmering heat"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"lyricAnchor": "bridge → rap",
|
||||
"time": "Afternoon",
|
||||
"location": "Open office collaboration zone",
|
||||
"outfit": "smart-casual with blazer on, sleeves half-rolled",
|
||||
"lightFX": "big window shafts, whiteboard bounce, laptop screen glows",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "huddled with team",
|
||||
"action": "points at tablet, laughs",
|
||||
"camera": [
|
||||
"three-quarter group with warm spill",
|
||||
"side shot fingertip reflect on glass",
|
||||
"face zoom in animated eyes",
|
||||
"overhead table, sticky notes constellation",
|
||||
"back shot sun flare between heads"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pair-programming vibe",
|
||||
"action": "nods at colleague’s suggestion",
|
||||
"camera": [
|
||||
"over-shoulder code lines glow",
|
||||
"profile double-bounce light",
|
||||
"face close appreciative smirk",
|
||||
"wide office as soft bokeh",
|
||||
"macro key tap with sparkle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "high-five moment",
|
||||
"action": "quick celebratory clasp",
|
||||
"camera": [
|
||||
"hand slap in slow-mo micro flare",
|
||||
"wide with cheering silhouettes",
|
||||
"face zoom in spark of pride",
|
||||
"back shot window halo",
|
||||
"low angle chairs and shoe scuffs gleam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "whiteboard arrows",
|
||||
"action": "draws bold box around goal",
|
||||
"camera": [
|
||||
"marker squeak macro with dust specks",
|
||||
"side shot arm casting graphic shadow",
|
||||
"face determined nod",
|
||||
"overhead board geometry",
|
||||
"wide team nodding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "break breath",
|
||||
"action": "looks out window to skyline",
|
||||
"camera": [
|
||||
"back shot silhouette and city shimmer",
|
||||
"profile rim light on jawline",
|
||||
"face close hopeful",
|
||||
"low angle blinds lines across suit",
|
||||
"wide room with golden haze creep"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 7,
|
||||
"LyricAnchor": "rap",
|
||||
"time": "Late Afternoon",
|
||||
"location": "Recording studio, vocal booth with pop filter and headphones",
|
||||
"outfit": "black tee under blazer, dark jeans; studio sneakers",
|
||||
"lightFX": "neon edge lights, VU meter glow, soft haze for beams",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "headphones on",
|
||||
"action": "adjusts mic height behind pop filter",
|
||||
"camera": [
|
||||
"face close through pop filter mesh bokeh",
|
||||
"side mic silhouette with LED rim",
|
||||
"overhead booth foam pattern",
|
||||
"back shot cable drape glint",
|
||||
"macro hands rolling knob with light tick"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "eyes closed",
|
||||
"action": "raps first bar with steady breath",
|
||||
"camera": [
|
||||
"profile with breath not hitting mic (good distance)",
|
||||
"face zoom in focused cadence",
|
||||
"VU meter needles dancing",
|
||||
"wide booth with purple-blue haze",
|
||||
"low angle light bar lens flare"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "punch-in moment",
|
||||
"action": "signals engineer, resumes",
|
||||
"camera": [
|
||||
"over-shoulder engineer glass reflection",
|
||||
"side shot finger count-in",
|
||||
"face close confident nod",
|
||||
"macro record light switching on",
|
||||
"wide studio cables lines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "chorus take",
|
||||
"action": "leans slightly, controlled power",
|
||||
"camera": [
|
||||
"three-quarter with mic halo",
|
||||
"face zoom in grit + hope",
|
||||
"low angle stand and shock mount glint",
|
||||
"back shot waveforms on screen",
|
||||
"overhead booth ceiling star LEDs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "final word",
|
||||
"action": "exhales, half smile",
|
||||
"camera": [
|
||||
"face close de-compress",
|
||||
"side shot headphone slide off one ear",
|
||||
"macro stop button press",
|
||||
"wide studio with color wash fade",
|
||||
"back shot door open to warm hall"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 8,
|
||||
"lyricAnchor": "verse B",
|
||||
"time": "Evening",
|
||||
"location": "City park path with family",
|
||||
"outfit": "soft knit over shirt, dark chinos; family in cozy layers",
|
||||
"lightFX": "golden hour glow, lens flare peeks, fairy-light bokeh",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking hand-in-hand",
|
||||
"action": "gentle chat, smile",
|
||||
"camera": [
|
||||
"full body back shot into sun",
|
||||
"side shot swinging hands in flare",
|
||||
"face close warm laugh lines",
|
||||
"overhead trees and light leaks",
|
||||
"low angle shoes kicking leaves sparkle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "kid points at birds",
|
||||
"action": "he kneels to show map",
|
||||
"camera": [
|
||||
"two-shot knee level with soft glow",
|
||||
"face close parental pride",
|
||||
"over-shoulder simple map sketch",
|
||||
"wide path dotted with fairy lights",
|
||||
"macro leaf veins lit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "group selfie",
|
||||
"action": "click with laughter",
|
||||
"camera": [
|
||||
"phone POV smiling faces, sun starburst",
|
||||
"side shot arm extended",
|
||||
"back shot silhouettes + flare arc",
|
||||
"overhead family circle",
|
||||
"wide park twinkle lights on"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "rest on bench",
|
||||
"action": "water break, shared bottle",
|
||||
"camera": [
|
||||
"medium sharing gesture backlit",
|
||||
"face close gentle gratitude",
|
||||
"low angle bottle condensation spark",
|
||||
"overhead bench wood grain glow",
|
||||
"wide with city edge twinkling"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "stand to leave",
|
||||
"action": "quick group hug",
|
||||
"camera": [
|
||||
"tight hug with sun blooming",
|
||||
"side shot hands around shoulders",
|
||||
"back shot long shadows merge",
|
||||
"overhead crown of light around heads",
|
||||
"wide path leading toward skyline"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 9,
|
||||
"lyricAnchor": "verse B",
|
||||
"time": "Night",
|
||||
"location": "Overlook with clean city nightscape",
|
||||
"outfit": "blazer back on, scarf added",
|
||||
"lightFX": "city bokeh, cool-blue sky, subtle haze for star glints",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "hands on railing",
|
||||
"action": "breath visible, quiet awe",
|
||||
"camera": [
|
||||
"full body with skyline glitter",
|
||||
"profile face with neon reflection in eyes",
|
||||
"back shot shoulders squared",
|
||||
"low angle railing shine + lens flare",
|
||||
"overhead city grid lines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "checks notes on phone",
|
||||
"action": "adds a single word: 'continue'",
|
||||
"camera": [
|
||||
"macro phone screen glow",
|
||||
"side shot finger tap highlight",
|
||||
"face close calm resolve",
|
||||
"wide skyline as bokeh ocean",
|
||||
"back shot scarf ripple"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "exhale slowly",
|
||||
"action": "pockets hands",
|
||||
"camera": [
|
||||
"profile fogged breath in neon halo",
|
||||
"low angle shoe on concrete edge",
|
||||
"face zoom in quiet smile",
|
||||
"overhead subtle city ray streak",
|
||||
"wide with passing light trail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "turns to camera",
|
||||
"action": "small nod forward",
|
||||
"camera": [
|
||||
"head-on medium with flare arch",
|
||||
"close eyes determined brightness",
|
||||
"side jawline rim light",
|
||||
"back shot then whip-pan reveal city",
|
||||
"wide crane up, city expands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "steps away",
|
||||
"action": "walks along overlook path",
|
||||
"camera": [
|
||||
"tracking back shot bokeh river",
|
||||
"side shot rail lights passing",
|
||||
"face three-quarter confident",
|
||||
"low angle puddle reflecting skyline",
|
||||
"overhead path curve luminous"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 10,
|
||||
"lyricAnchor": "rap → end",
|
||||
"time": "Night",
|
||||
"location": "Office district after hours",
|
||||
"outfit": "blazer + scarf, gloves optional",
|
||||
"lightFX": "glass facade reflections, wet pavement neon, gentle drizzle mist",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking alone between towers",
|
||||
"action": "steady stride, chin up",
|
||||
"camera": [
|
||||
"full body on wet pavement mirror",
|
||||
"side shot droplets catching light",
|
||||
"face close focused calm",
|
||||
"back shot towers converging lines",
|
||||
"overhead umbrella silhouettes distant"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "pauses at intersection",
|
||||
"action": "inhales cool air",
|
||||
"camera": [
|
||||
"low angle traffic light glow on mist",
|
||||
"profile breath plume",
|
||||
"wide glass reflections kaleidoscope",
|
||||
"macro droplet slide on sleeve",
|
||||
"face close half-smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "checks tram schedule afar",
|
||||
"action": "decides to walk instead",
|
||||
"camera": [
|
||||
"long lens heat-haze shimmer line",
|
||||
"back shot step away from stop",
|
||||
"side shot rhythmic footfalls",
|
||||
"wide lone figure + city hum",
|
||||
"overhead rain dot glitter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "crosswalk stride",
|
||||
"action": "bag strap adjustment",
|
||||
"camera": [
|
||||
"ground reflection of zebra stripes",
|
||||
"three-quarter with neon banding",
|
||||
"face close rain specks on cheek",
|
||||
"low angle heel-toe cadence",
|
||||
"wide car lights streak behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "turns corner",
|
||||
"action": "street opens to quieter block",
|
||||
"camera": [
|
||||
"back shot disappearing into warm alley glow",
|
||||
"side shot brick wall glisten",
|
||||
"overhead pocket of golden steam vent",
|
||||
"face three-quarter softened by warmth",
|
||||
"wide fade to gentle drizzle veil"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 11,
|
||||
"lyricAnchor": "end",
|
||||
"time": "Late Night",
|
||||
"location": "Home living room, cozy lamp pools",
|
||||
"outfit": "cardigan over tee, soft pants, socks; glasses on table",
|
||||
"lightFX": "warm lamps, TV ambient glow, window rain reflections",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sinks into sofa",
|
||||
"action": "removes watch, exhales",
|
||||
"camera": [
|
||||
"full body cozy frame with lamp bloom",
|
||||
"macro watch buckle catchlight",
|
||||
"face close relief",
|
||||
"overhead coffee table still life",
|
||||
"back shot curtain rain trails"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "scrolls photos",
|
||||
"action": "smiles at family selfie",
|
||||
"camera": [
|
||||
"close phone screen glow on eyes",
|
||||
"profile soft grin",
|
||||
"wide living room warm pools",
|
||||
"low angle socks on rug texture",
|
||||
"back shot window city twinkle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leans back",
|
||||
"action": "sips late tea",
|
||||
"camera": [
|
||||
"macro steam ribbon in lamp light",
|
||||
"side shot cup handle highlight",
|
||||
"face close calm closure",
|
||||
"overhead tray symmetry",
|
||||
"wide gentle rack focus to rain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "turns off lamp",
|
||||
"action": "room dims to TV glow",
|
||||
"camera": [
|
||||
"finger on switch micro flare",
|
||||
"silhouette against window bokeh",
|
||||
"face close eyes soft",
|
||||
"low angle shadows lengthen",
|
||||
"wide night hush settles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "final glance to window",
|
||||
"action": "small nod—tomorrow again",
|
||||
"camera": [
|
||||
"face three-quarter with faint smile",
|
||||
"back shot rain tracing lines of light",
|
||||
"macro drop racing down glass",
|
||||
"wide living room serene",
|
||||
"fade out on city reflections"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
src/musicspot_generator/v1/fire in the night/song.mp3
Normal file
BIN
src/musicspot_generator/v1/fire in the night/song.mp3
Normal file
Binary file not shown.
BIN
src/musicspot_generator/v1/girly girl/face.png
Normal file
BIN
src/musicspot_generator/v1/girly girl/face.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
272
src/musicspot_generator/v1/girly girl/scenes.json
Normal file
272
src/musicspot_generator/v1/girly girl/scenes.json
Normal file
@ -0,0 +1,272 @@
|
||||
{
|
||||
"character": {
|
||||
"bodyType": "slim and youthful",
|
||||
"hairStyle": "long wavy hair with pastel blue and purple colors"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"time": "Morning",
|
||||
"location": "Cozy bedroom with pastel bedding and sunlight through curtains",
|
||||
"outfit": "white oversized pajama shirt with thigh-high stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "lying on bed with head resting on hands",
|
||||
"action": "smiling softly at the camera",
|
||||
"camera": [
|
||||
"overhead shot from above capturing sunlight on her hair",
|
||||
"close-up of her face with shallow depth of field",
|
||||
"side angle showing body stretched on bed",
|
||||
"slow zoom-in from doorway",
|
||||
"handheld camera wobble for intimate feeling"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "stretching arms above head while sitting on bed",
|
||||
"action": "yawning cutely with eyes half closed",
|
||||
"camera": [
|
||||
"medium shot from foot of bed",
|
||||
"low angle from floor emphasizing legs",
|
||||
"wide shot with window light flaring",
|
||||
"tracking shot circling around her stretch",
|
||||
"soft focus tilt-shift framing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "kneeling on bed with playful look",
|
||||
"action": "blowing a kiss to the camera",
|
||||
"camera": [
|
||||
"front close-up catching kiss in slow motion",
|
||||
"wide shot with pastel background",
|
||||
"camera tilt from below lips to eyes",
|
||||
"360° pan around her kneeling pose",
|
||||
"handheld push-in as she blows kiss"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"time": "Morning",
|
||||
"location": "Bedroom near window with plants and sunlight",
|
||||
"outfit": "light pastel camisole with short pleated skirt and stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting on window sill, legs slightly crossed",
|
||||
"action": "looking outside then turning to smile",
|
||||
"camera": [
|
||||
"silhouette against sunlight",
|
||||
"side profile with plants blurred in foreground",
|
||||
"close-up of smile turning to camera",
|
||||
"dolly-in from outside window glass",
|
||||
"over-shoulder shot capturing view outside"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning against the wall, hands behind back",
|
||||
"action": "giggling with shy expression",
|
||||
"camera": [
|
||||
"eye-level shot with wall texture visible",
|
||||
"slight high angle to emphasize cuteness",
|
||||
"medium close-up on giggle with tilt",
|
||||
"rack focus between wall décor and her face",
|
||||
"soft handheld sway left to right"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "lying on floor with legs up against the wall",
|
||||
"action": "kicking feet playfully while laughing",
|
||||
"camera": [
|
||||
"top-down view from ceiling",
|
||||
"low angle from foot level",
|
||||
"side shot capturing playful kicks",
|
||||
"slow pan across her body",
|
||||
"handheld camera zoom-in to laughter"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"time": "Afternoon",
|
||||
"location": "Sunny street with pastel shops and flowers",
|
||||
"outfit": "short pastel pink dress with white stockings and sneakers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing with one hand on hip",
|
||||
"action": "spinning gently in place",
|
||||
"camera": [
|
||||
"full body wide shot with pastel shops",
|
||||
"low angle capturing dress swirl",
|
||||
"tracking shot circling spin",
|
||||
"handheld slow zoom-in to face",
|
||||
"rear shot revealing spin from behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "walking with small steps",
|
||||
"action": "waving happily at the camera",
|
||||
"camera": [
|
||||
"tracking dolly shot in front",
|
||||
"overhead drone shot of street",
|
||||
"side follow shot at hip level",
|
||||
"handheld jitter to mimic vlog",
|
||||
"close-up on waving hand with face blurred"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning forward playfully",
|
||||
"action": "making a heart shape with hands",
|
||||
"camera": [
|
||||
"tight close-up on hands forming heart",
|
||||
"fish-eye wide close-up",
|
||||
"side shot at 45°",
|
||||
"POV shot as if receiving heart",
|
||||
"zoom burst effect from wide to close"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"time": "Afternoon",
|
||||
"location": "Trendy café with bright modern interior",
|
||||
"outfit": "white blouse tucked into pleated skirt with stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting at a table with chin on hands",
|
||||
"action": "smiling softly while tilting head",
|
||||
"camera": [
|
||||
"front eye-level close-up",
|
||||
"soft focus on eyes, blurred background",
|
||||
"over-shoulder shot of coffee cup",
|
||||
"panning shot across table to her",
|
||||
"low angle from table surface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing by window with crossed legs",
|
||||
"action": "writing playfully in a small notebook",
|
||||
"camera": [
|
||||
"profile with sunlight flare",
|
||||
"close-up of pen on paper then tilt to face",
|
||||
"tracking shot from feet to head",
|
||||
"reflection in window glass",
|
||||
"medium shot with bokeh lights behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting sideways on chair with one leg up",
|
||||
"action": "taking a sip from a cup with cute expression",
|
||||
"camera": [
|
||||
"tight focus on lips touching cup",
|
||||
"medium shot framed by chair back",
|
||||
"slight dutch angle for energy",
|
||||
"slow dolly-in on playful sip",
|
||||
"wide establishing shot of café"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"time": "Night",
|
||||
"location": "Elegant ballroom with chandeliers",
|
||||
"outfit": "sparkly silver mini dress with black stockings and heels",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing tall with one hand on waist",
|
||||
"action": "turning slowly while smiling confidently",
|
||||
"camera": [
|
||||
"wide shot capturing chandelier",
|
||||
"low angle emphasizing elegance",
|
||||
"tracking dolly rotation",
|
||||
"close-up of smile during turn",
|
||||
"rear tracking shot revealing gown shimmer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "sitting gracefully on a velvet chair",
|
||||
"action": "crossing legs elegantly",
|
||||
"camera": [
|
||||
"medium close-up from side",
|
||||
"top-down angle showing chair texture",
|
||||
"front focus on crossed legs",
|
||||
"soft rack focus from chair to her face",
|
||||
"panning shot circling chair"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning on railing with dreamy look",
|
||||
"action": "gazing at the chandelier lights",
|
||||
"camera": [
|
||||
"over-shoulder shot of chandelier view",
|
||||
"profile silhouette with golden backlight",
|
||||
"wide shot capturing ballroom depth",
|
||||
"handheld tilt up from railing to face",
|
||||
"slow dolly-out revealing emptiness of hall"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"time": "Night",
|
||||
"location": "Luxurious bedroom with soft golden lighting",
|
||||
"outfit": "black lace camisole with mini skirt and stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "lying sideways on bed with legs slightly bent",
|
||||
"action": "looking at the camera with sultry eyes",
|
||||
"camera": [
|
||||
"close-up on eyes with blurred background",
|
||||
"tracking shot along legs up to face",
|
||||
"overhead soft focus",
|
||||
"low angle from bed surface",
|
||||
"handheld intimate pan across body"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "sitting at vanity table",
|
||||
"action": "putting on earrings slowly",
|
||||
"camera": [
|
||||
"mirror reflection focus",
|
||||
"close-up on hands adjusting earrings",
|
||||
"profile side shot with warm glow",
|
||||
"over-shoulder shot including vanity lights",
|
||||
"slow push-in from doorway"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "kneeling on bed with arched back",
|
||||
"action": "running hand through hair with sensual expression",
|
||||
"camera": [
|
||||
"rear shot with back arch emphasized",
|
||||
"medium close-up focusing on hair movement",
|
||||
"low angle capturing curves",
|
||||
"soft focus candlelight bokeh",
|
||||
"circling dolly shot for dramatic effect"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
src/musicspot_generator/v1/girly girl/song.mp3
Normal file
BIN
src/musicspot_generator/v1/girly girl/song.mp3
Normal file
Binary file not shown.
296
src/musicspot_generator/v1/images.ts
Normal file
296
src/musicspot_generator/v1/images.ts
Normal file
@ -0,0 +1,296 @@
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
import { logger } from '../../lib/logger';
|
||||
import { callOpenAI } from '../../lib/openai';
|
||||
import { callLMStudio } from '../../lib/lmstudio';
|
||||
// import { generateImage as generateFaceImage } from '../lib/image-generator-face'; // Removed
|
||||
import { generateImage } from '../../lib/image-generator'; // Added
|
||||
|
||||
dotenv.config();
|
||||
|
||||
type Size = { width: number; height: number };
|
||||
|
||||
interface MusicSpotCharacter {
|
||||
bodyType: string;
|
||||
hairStyle: string;
|
||||
}
|
||||
|
||||
interface MusicSpotCut {
|
||||
cutId: number;
|
||||
pose: string;
|
||||
action: string;
|
||||
camera?: string[]; // list of camera variants per cut
|
||||
}
|
||||
|
||||
interface MusicSpotScene {
|
||||
sceneId: number;
|
||||
time: string;
|
||||
location: string;
|
||||
outfit: string;
|
||||
cuts: MusicSpotCut[];
|
||||
}
|
||||
|
||||
interface MusicSpotConfig {
|
||||
character: MusicSpotCharacter;
|
||||
scenes: MusicSpotScene[];
|
||||
}
|
||||
|
||||
interface Server {
|
||||
baseUrl?: string;
|
||||
outputDir?: string;
|
||||
inputDir?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SIZE: Size = { width: 1280, height: 720 };
|
||||
const FOLDER = process.argv[2] || process.env.MUSICSPOT_FOLDER || 'infinitydance';
|
||||
const FOLDER_SAFE = FOLDER.replace(/[/\\?%*:|"<>]/g, '_');
|
||||
const FACE_SRC = path.resolve(`src/musicspot_generator/${FOLDER}/face.png`);
|
||||
const GENERATED_DIR = path.resolve('generated');
|
||||
|
||||
function loadServers(): Server[] {
|
||||
const servers: Server[] = [
|
||||
{
|
||||
name: 'SERVER1',
|
||||
baseUrl: process.env.SERVER1_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR,
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: 'SERVER2',
|
||||
baseUrl: process.env.SERVER2_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR,
|
||||
}, */
|
||||
]
|
||||
.filter((s) => !!s.baseUrl && !!s.outputDir)
|
||||
.map((s) => ({
|
||||
...s,
|
||||
inputDir: s.outputDir!.replace(/output/i, 'input'),
|
||||
}));
|
||||
|
||||
if (servers.length === 0) {
|
||||
logger.warn('No servers configured. Please set SERVER{N}_COMFY_BASE_URL and SERVER{N}_COMFY_OUTPUT_DIR in .env');
|
||||
} else {
|
||||
for (const s of servers) {
|
||||
logger.info(`Configured ${s.name}: baseUrl=${s.baseUrl}, outputDir=${s.outputDir}, inputDir=${s.inputDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
async function ensureDirs() {
|
||||
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
async function copyFaceToServers(servers: Server[]): Promise<string | undefined> {
|
||||
const faceFileName = 'face.png';
|
||||
|
||||
// Validate face source
|
||||
try {
|
||||
await fs.access(FACE_SRC);
|
||||
} catch {
|
||||
// If face.png doesn't exist, we don't need to copy anything.
|
||||
// The caller should handle this case.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const srv of servers) {
|
||||
if (!srv.inputDir) continue;
|
||||
const dest = path.join(srv.inputDir, faceFileName);
|
||||
try {
|
||||
await fs.mkdir(srv.inputDir, { recursive: true });
|
||||
await fs.copyFile(FACE_SRC, dest);
|
||||
logger.info(`Copied face image to ${srv.name} input: ${dest}`);
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to copy face image to ${srv.name}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
return faceFileName; // Comfy expects file name present in input dir
|
||||
}
|
||||
|
||||
function buildImagePromptRequest(
|
||||
character: MusicSpotCharacter,
|
||||
scene: MusicSpotScene,
|
||||
cut: MusicSpotCut,
|
||||
cameraIntent: string,
|
||||
hasFaceImage: boolean // Added parameter
|
||||
): string {
|
||||
let promptInstructions = `
|
||||
Write "imagePrompt" in around 110–140 words to generate a still portrait image (720x1280 vertical).
|
||||
`;
|
||||
|
||||
if (hasFaceImage) {
|
||||
promptInstructions += `Keep a consistent character identity using the provided face image (identity preservation), but do not mention any camera brand/model.
|
||||
`;
|
||||
} else {
|
||||
promptInstructions += `Do not use any face image for identity preservation.
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
Return exactly one JSON object, nothing else: { "imagePrompt": "Cinematic realistic photo, (camera framing),(character),(pose),(time),(location),(outfit),(action),(lighting)" }.
|
||||
|
||||
${promptInstructions}
|
||||
Describe clearly and concretely:
|
||||
- Character: ${character.bodyType}; hair: ${character.hairStyle}
|
||||
- Camera framing/composition intention: ${cameraIntent}
|
||||
- Time: ${scene.time}
|
||||
- Location: ${scene.location}
|
||||
- Outfit: ${scene.outfit}
|
||||
- Pose: ${cut.pose}
|
||||
- Action/Expression: ${cut.action}
|
||||
- Lighting: please be creative and make beautiful lighting, I like something like luminous, colorful
|
||||
|
||||
Important:
|
||||
- adjust the outfit based on the camera framing, describe only what is visible.
|
||||
For example, if the framing is a close-up of the face, do not mention the outfit at all.
|
||||
|
||||
Only respond with JSON.
|
||||
`.trim();
|
||||
}
|
||||
|
||||
async function getImagePromptFromOpenAI(req: string): Promise<string> {
|
||||
const res = await callOpenAI(req);
|
||||
const prompt = res?.imagePrompt || res?.image_prompt || res?.prompt;
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
throw new Error('OpenAI failed to return imagePrompt JSON.');
|
||||
}
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
const IMAGE_PROMPT_PROVIDER = (process.env.IMAGE_PROMPT_PROVIDER || 'lmstudio').toLowerCase();
|
||||
|
||||
async function getImagePromptFromLMStudio(req: string): Promise<string> {
|
||||
const res = await callLMStudio(req);
|
||||
const prompt = res?.imagePrompt || res?.image_prompt || res?.prompt;
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
throw new Error('LM Studio failed to return imagePrompt JSON.');
|
||||
}
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
async function getImagePrompt(req: string): Promise<string> {
|
||||
if (IMAGE_PROMPT_PROVIDER === 'openai') {
|
||||
return getImagePromptFromOpenAI(req);
|
||||
}
|
||||
// default to LM Studio
|
||||
return getImagePromptFromLMStudio(req);
|
||||
}
|
||||
|
||||
function pickServer(servers: Server[], idx: number): Server {
|
||||
if (servers.length === 0) {
|
||||
throw new Error('No servers configured.');
|
||||
}
|
||||
return servers[idx % servers.length];
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await ensureDirs();
|
||||
|
||||
// Check if face.png exists
|
||||
let faceImageExists = false;
|
||||
try {
|
||||
await fs.access(FACE_SRC);
|
||||
faceImageExists = true;
|
||||
logger.info(`Face image found at ${FACE_SRC}`);
|
||||
} catch {
|
||||
logger.warn(`Face image not found at ${FACE_SRC}. Images will be generated without face conditioning.`);
|
||||
}
|
||||
|
||||
// Load scenes.json
|
||||
const configRaw = await fs.readFile(path.resolve(`src/musicspot_generator/${FOLDER}/scenes.json`), 'utf-8');
|
||||
const cfg: MusicSpotConfig = JSON.parse(configRaw);
|
||||
|
||||
const servers = loadServers();
|
||||
if (servers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure face.png in each server's input, only if it exists
|
||||
let faceFileName: string | undefined = undefined;
|
||||
if (faceImageExists) {
|
||||
faceFileName = await copyFaceToServers(servers);
|
||||
} else {
|
||||
logger.info('Skipping copyFaceToServers as face image does not exist.');
|
||||
}
|
||||
|
||||
// Generate images only (no video here). Intended to be run first.
|
||||
let imageTaskIndex = 0;
|
||||
|
||||
for (const scene of cfg.scenes) {
|
||||
logger.info(`=== Scene ${scene.sceneId}: Image generation start ===`);
|
||||
for (const cut of scene.cuts) {
|
||||
const cameraVariants =
|
||||
Array.isArray(cut.camera) && cut.camera.length > 0
|
||||
? cut.camera
|
||||
: ['eye-level medium shot', 'slight left 30°', 'slight right 30°', 'slight high angle', 'slight low angle'];
|
||||
|
||||
for (let camIdx = 0; camIdx < cameraVariants.length; camIdx++) {
|
||||
const cameraIntent = cameraVariants[camIdx];
|
||||
const variantIndex = camIdx + 1;
|
||||
const imgFileName = `${FOLDER_SAFE}_musicspot_s${scene.sceneId}_c${cut.cutId}_v${variantIndex}.png`;
|
||||
const outputPath = path.join(GENERATED_DIR, imgFileName);
|
||||
|
||||
// Skip generation if target file already exists
|
||||
try {
|
||||
await fs.access(outputPath);
|
||||
logger.info(`Skipping generation, file already exists: ${outputPath}`);
|
||||
continue;
|
||||
} catch {
|
||||
// File does not exist; proceed with generation
|
||||
}
|
||||
|
||||
// 1) Generate image prompt for this camera
|
||||
logger.info(`Scene ${scene.sceneId} - Cut ${cut.cutId} - Cam${variantIndex}: generating image prompt...`);
|
||||
// Pass faceImageExists to buildImagePromptRequest
|
||||
const imgPromptReq = buildImagePromptRequest(cfg.character, scene, cut, cameraIntent, faceImageExists);
|
||||
let imagePrompt: string;
|
||||
try {
|
||||
imagePrompt = await getImagePrompt(imgPromptReq);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`${IMAGE_PROMPT_PROVIDER.toUpperCase()} image prompt failed for scene ${scene.sceneId} cut ${cut.cutId} cam ${variantIndex}: ${err}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2) Generate one image using the new generateImage function
|
||||
const serverForImage = pickServer(servers, imageTaskIndex++);
|
||||
logger.info(`Generating image (${imgFileName}) on ${serverForImage.name}...`);
|
||||
|
||||
try {
|
||||
// Use the generic generateImage function from image-generator.ts
|
||||
// The faceFileName is no longer passed as an argument, but its existence
|
||||
// influenced the imagePrompt.
|
||||
const finalImagePath = await generateImage(
|
||||
imagePrompt, // The prompt now contains face instructions if faceImageExists is true
|
||||
imgFileName,
|
||||
serverForImage.baseUrl!,
|
||||
serverForImage.outputDir!,
|
||||
'flux', // Use default imageModel ('qwen')
|
||||
DEFAULT_SIZE
|
||||
);
|
||||
logger.info(`Image generated: ${finalImagePath}`);
|
||||
} catch (err) {
|
||||
logger.error(`Image generation failed (${imgFileName}) on ${serverForImage.name}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info(`=== Scene ${scene.sceneId}: Image generation complete ===`);
|
||||
}
|
||||
|
||||
logger.info('Image generation for all scenes completed.');
|
||||
} catch (err) {
|
||||
logger.error('Fatal error in music spot image generator:', err);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
logger.error('Unhandled error:', err);
|
||||
});
|
||||
366
src/musicspot_generator/v1/index.ts
Normal file
366
src/musicspot_generator/v1/index.ts
Normal file
@ -0,0 +1,366 @@
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
import { logger } from '../../lib/logger';
|
||||
import { callOpenAI } from '../../lib/openai';
|
||||
import { generateImage as generateFaceImage } from '../../lib/image-generator-face';
|
||||
import { generateVideo } from '../../lib/video-generator';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
type Size = { width: number; height: number };
|
||||
|
||||
interface MusicSpotCharacter {
|
||||
bodyType: string;
|
||||
hairStyle: string;
|
||||
}
|
||||
|
||||
interface MusicSpotCut {
|
||||
cutId: number;
|
||||
pose: string;
|
||||
action: string;
|
||||
camera?: string[]; // list of 5 camera variants per cut
|
||||
}
|
||||
|
||||
interface MusicSpotScene {
|
||||
sceneId: number;
|
||||
time: string;
|
||||
location: string;
|
||||
outfit: string;
|
||||
cuts: MusicSpotCut[];
|
||||
}
|
||||
|
||||
interface MusicSpotConfig {
|
||||
character: MusicSpotCharacter;
|
||||
scenes: MusicSpotScene[];
|
||||
}
|
||||
|
||||
interface Server {
|
||||
baseUrl?: string;
|
||||
outputDir?: string;
|
||||
inputDir?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SIZE: Size = { width: 720, height: 1280 };
|
||||
const FACE_SRC = path.resolve('src/musicspot_generator/face.png');
|
||||
const GENERATED_DIR = path.resolve('generated');
|
||||
|
||||
function loadServers(): Server[] {
|
||||
const servers: Server[] = [
|
||||
{
|
||||
name: 'SERVER1',
|
||||
baseUrl: process.env.SERVER1_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR,
|
||||
}
|
||||
/*{
|
||||
name: 'SERVER2',
|
||||
baseUrl: process.env.SERVER2_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR,
|
||||
}*/,
|
||||
]
|
||||
.filter(s => !!s.baseUrl && !!s.outputDir)
|
||||
.map(s => ({
|
||||
...s,
|
||||
// Convert output dir to input dir by convention
|
||||
inputDir: s.outputDir!.replace(/output/i, 'input'),
|
||||
}));
|
||||
|
||||
if (servers.length === 0) {
|
||||
logger.warn('No servers configured. Please set SERVER{N}_COMFY_BASE_URL and SERVER{N}_COMFY_OUTPUT_DIR in .env');
|
||||
} else {
|
||||
for (const s of servers) {
|
||||
logger.info(`Configured ${s.name}: baseUrl=${s.baseUrl}, outputDir=${s.outputDir}, inputDir=${s.inputDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
async function ensureDirs() {
|
||||
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
async function copyFaceToServers(servers: Server[]): Promise<{ fileName: string; absPerServer: Record<string, string> }> {
|
||||
const faceFileName = 'face.png';
|
||||
const absPerServer: Record<string, string> = {};
|
||||
|
||||
// Validate face source
|
||||
try {
|
||||
await fs.access(FACE_SRC);
|
||||
} catch {
|
||||
throw new Error(`Face image not found at ${FACE_SRC}`);
|
||||
}
|
||||
|
||||
for (const srv of servers) {
|
||||
if (!srv.inputDir) continue;
|
||||
const dest = path.join(srv.inputDir, faceFileName);
|
||||
try {
|
||||
await fs.mkdir(srv.inputDir, { recursive: true });
|
||||
await fs.copyFile(FACE_SRC, dest);
|
||||
absPerServer[srv.name] = path.resolve(dest);
|
||||
logger.info(`Copied face image to ${srv.name} input: ${dest}`);
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to copy face image to ${srv.name}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
return { fileName: faceFileName, absPerServer };
|
||||
}
|
||||
|
||||
function buildImagePromptRequest(
|
||||
character: MusicSpotCharacter,
|
||||
scene: MusicSpotScene,
|
||||
cut: MusicSpotCut,
|
||||
cameraIntent: string
|
||||
): string {
|
||||
// Ask OpenAI to return JSON: { "imagePrompt": "..." }
|
||||
return `
|
||||
Return exactly one JSON object, nothing else: { "imagePrompt": "..." }.
|
||||
|
||||
Write "imagePrompt" in around 110–140 words to generate a still portrait image (720x1280 vertical).
|
||||
Keep a consistent character identity using the provided face image (identity preservation), but do not mention any camera brand/model.
|
||||
|
||||
Describe clearly and concretely:
|
||||
- Character: ${character.bodyType}; hair: ${character.hairStyle}
|
||||
- Time: ${scene.time}
|
||||
- Location: ${scene.location}
|
||||
- Outfit: ${scene.outfit}
|
||||
- Pose: ${cut.pose}
|
||||
- Action/Expression: ${cut.action}
|
||||
- Camera framing/composition intention: ${cameraIntent}
|
||||
- Lighting/mood/style: cohesive and realistic, natural skin tones, soft depth of field.
|
||||
|
||||
Avoid: brand names, copyrighted characters, extreme or explicit content, text overlays, watermarks, multiple people. Focus on a single subject medium-full portrait, tasteful and aesthetic. Use simple sentences.
|
||||
|
||||
Only respond with JSON.
|
||||
`.trim();
|
||||
}
|
||||
|
||||
function buildVideoPromptRequest(
|
||||
character: MusicSpotCharacter,
|
||||
scene: MusicSpotScene,
|
||||
cut: MusicSpotCut,
|
||||
cameraIntent: string
|
||||
): string {
|
||||
// Ask OpenAI to return JSON: { "videoPrompt": "..." }
|
||||
// Strong constraints to avoid "cut/zoom" etc. Keep a single continuous 8s shot.
|
||||
return `
|
||||
Return exactly one JSON object and nothing else: { "videoPrompt": "..." }.
|
||||
|
||||
Write "videoPrompt" in 100–140 words. Present tense. Concrete, simple sentences.
|
||||
|
||||
HARD RULES:
|
||||
- One continuous 8-second shot (oner). No edits.
|
||||
- Fixed location and general vantage; maintain spatial continuity.
|
||||
- No zooms, no rack zoom, no smash/push-in, no cuts, no transitions, no "meanwhile".
|
||||
- Camera motion: at most a slight pan/tilt or subtle dolly within 1 meter.
|
||||
- Keep framing consistent (vertical 720x1280). Avoid technical brand names or lens jargon.
|
||||
|
||||
Incorporate the following camera intention: "${cameraIntent}".
|
||||
If it conflicts with HARD RULES (e.g., zoom, push-in, extreme moves), reinterpret it into a subtle, compliant motion (e.g., gentle glide, slight pan/tilt) while preserving the creative intent.
|
||||
|
||||
Describe:
|
||||
1) Main action: ${cut.action}
|
||||
2) Pose/composition: ${cut.pose}
|
||||
3) Scene/time/location/outfit: ${scene.time}; ${scene.location}; outfit: ${scene.outfit}
|
||||
4) Lighting/mood/style coherent with the character: ${character.bodyType}; hair: ${character.hairStyle}
|
||||
|
||||
Prohibited (case-insensitive): cut, cuts, cutting, quick cut, insert, close-up, extreme close-up, zoom, zooming, push-in, pull-out, whip, switch angle, change angle, montage, cross-cut, smash cut, transition, meanwhile, later.
|
||||
|
||||
Only respond with JSON.
|
||||
`.trim();
|
||||
}
|
||||
|
||||
async function getImagePromptFromOpenAI(req: string): Promise<string> {
|
||||
const res = await callOpenAI(req);
|
||||
const prompt = res?.imagePrompt || res?.image_prompt || res?.prompt;
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
throw new Error('OpenAI failed to return imagePrompt JSON.');
|
||||
}
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
async function getVideoPromptFromOpenAI(req: string): Promise<string> {
|
||||
const res = await callOpenAI(req);
|
||||
const prompt = res?.videoPrompt || res?.video_prompt || res?.prompt;
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
throw new Error('OpenAI failed to return videoPrompt JSON.');
|
||||
}
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
function pickServer(servers: Server[], idx: number): Server {
|
||||
if (servers.length === 0) {
|
||||
throw new Error('No servers configured.');
|
||||
}
|
||||
return servers[idx % servers.length];
|
||||
}
|
||||
|
||||
async function copyImageToAllServerInputs(servers: Server[], localGeneratedImagePath: string): Promise<string> {
|
||||
const fileName = path.basename(localGeneratedImagePath);
|
||||
const copies: string[] = [];
|
||||
for (const s of servers) {
|
||||
if (!s.inputDir) continue;
|
||||
const dest = path.join(s.inputDir, fileName);
|
||||
try {
|
||||
await fs.copyFile(localGeneratedImagePath, dest);
|
||||
copies.push(dest);
|
||||
logger.debug(`Copied ${fileName} to ${s.name} input: ${dest}`);
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to copy ${fileName} to ${s.name} input: ${err}`);
|
||||
}
|
||||
}
|
||||
return fileName; // return the name used for Comfy workflows
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await ensureDirs();
|
||||
|
||||
// Load scenes.json
|
||||
const configRaw = await fs.readFile(path.resolve('src/musicspot_generator/scenes.json'), 'utf-8');
|
||||
const cfg: MusicSpotConfig = JSON.parse(configRaw);
|
||||
|
||||
const servers = loadServers();
|
||||
if (servers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure face.png in each server's input
|
||||
const { fileName: faceFileName } = await copyFaceToServers(servers);
|
||||
|
||||
// Two-phase per scene:
|
||||
// Phase 1: Generate ALL images for the scene (to keep image model warm)
|
||||
// Phase 2: Generate ALL videos for the images of that scene (to keep video model warm)
|
||||
|
||||
let imageTaskIndex = 0;
|
||||
let videoTaskIndex = 0;
|
||||
|
||||
for (const scene of cfg.scenes) {
|
||||
logger.info(`=== Scene ${scene.sceneId}: Phase 1 - Image generation start ===`);
|
||||
type SceneImageItem = {
|
||||
sceneId: number;
|
||||
cutId: number;
|
||||
cameraIntent: string;
|
||||
imgFileName: string;
|
||||
imgPath: string;
|
||||
};
|
||||
const sceneImageItems: SceneImageItem[] = [];
|
||||
|
||||
// Phase 1: images
|
||||
for (const cut of scene.cuts) {
|
||||
const cameraVariants = Array.isArray(cut.camera) && cut.camera.length > 0
|
||||
? cut.camera
|
||||
: ['eye-level medium shot', 'slight left 30°', 'slight right 30°', 'slight high angle', 'slight low angle'];
|
||||
|
||||
for (let camIdx = 0; camIdx < cameraVariants.length; camIdx++) {
|
||||
const cameraIntent = cameraVariants[camIdx];
|
||||
const variantIndex = camIdx + 1;
|
||||
|
||||
// 1) Generate image prompt for this camera
|
||||
logger.info(`Scene ${scene.sceneId} - Cut ${cut.cutId} - Cam${variantIndex}: generating image prompt...`);
|
||||
const imgPromptReq = buildImagePromptRequest(cfg.character, scene, cut, cameraIntent);
|
||||
let imagePrompt: string;
|
||||
try {
|
||||
imagePrompt = await getImagePromptFromOpenAI(imgPromptReq);
|
||||
} catch (err) {
|
||||
logger.error(`OpenAI image prompt failed for scene ${scene.sceneId} cut ${cut.cutId} cam ${variantIndex}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2) Generate one image using face conditioning for this specific camera
|
||||
const serverForImage = pickServer(servers, imageTaskIndex++);
|
||||
const imgFileName = `musicspot_s${scene.sceneId}_c${cut.cutId}_v${variantIndex}.png`;
|
||||
logger.info(`Generating image (${imgFileName}) on ${serverForImage.name}...`);
|
||||
|
||||
try {
|
||||
// Use only the face file name for the workflow image input (Comfy expects it in its input dir)
|
||||
const finalImagePath = await generateFaceImage(
|
||||
imagePrompt,
|
||||
faceFileName,
|
||||
imgFileName,
|
||||
serverForImage.baseUrl!,
|
||||
serverForImage.outputDir!,
|
||||
DEFAULT_SIZE
|
||||
);
|
||||
logger.info(`Image generated: ${finalImagePath}`);
|
||||
|
||||
sceneImageItems.push({
|
||||
sceneId: scene.sceneId,
|
||||
cutId: cut.cutId,
|
||||
cameraIntent,
|
||||
imgFileName,
|
||||
imgPath: finalImagePath,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`Image generation failed (${imgFileName}) on ${serverForImage.name}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`=== Scene ${scene.sceneId}: Phase 1 complete. Generated ${sceneImageItems.length} image(s). ===`);
|
||||
logger.info(`=== Scene ${scene.sceneId}: Phase 2 - Video generation start ===`);
|
||||
|
||||
// Phase 2: videos for all images generated in this scene
|
||||
for (const item of sceneImageItems) {
|
||||
// Find original cut info for prompts
|
||||
const cut = scene.cuts.find(c => c.cutId === item.cutId);
|
||||
if (!cut) {
|
||||
logger.warn(`Cut ${item.cutId} not found for scene ${scene.sceneId}, skipping video.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3) Generate video prompt for this camera
|
||||
logger.info(`Generating video prompt for ${item.imgFileName} (scene ${scene.sceneId}, cut ${item.cutId})...`);
|
||||
const vidPromptReq = buildVideoPromptRequest(cfg.character, scene, cut, item.cameraIntent);
|
||||
|
||||
let videoPrompt: string;
|
||||
try {
|
||||
videoPrompt = await getVideoPromptFromOpenAI(vidPromptReq);
|
||||
} catch (err) {
|
||||
logger.error(`OpenAI video prompt failed for ${item.imgFileName}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4) Copy the base image to every server's input folder
|
||||
const imageFileNameForComfy = await copyImageToAllServerInputs(servers, item.imgPath);
|
||||
|
||||
// 5) Generate video on a chosen server (round-robin)
|
||||
const serverForVideo = pickServer(servers, videoTaskIndex++);
|
||||
const videoFileName = item.imgFileName.replace(/\.png$/i, '.mp4');
|
||||
logger.info(`Generating video (${videoFileName}) on ${serverForVideo.name} using ${imageFileNameForComfy}...`);
|
||||
|
||||
try {
|
||||
const videoPath = await generateVideo(
|
||||
videoPrompt,
|
||||
imageFileNameForComfy,
|
||||
videoFileName,
|
||||
serverForVideo.baseUrl!,
|
||||
serverForVideo.outputDir!,
|
||||
DEFAULT_SIZE
|
||||
);
|
||||
logger.info(`Video generated: ${videoPath}`);
|
||||
} catch (err) {
|
||||
logger.error(`Video generation failed (${videoFileName}) on ${serverForVideo.name}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`=== Scene ${scene.sceneId}: Phase 2 complete. ===`);
|
||||
}
|
||||
|
||||
logger.info('Music spot generation completed.');
|
||||
} catch (err) {
|
||||
logger.error('Fatal error in music spot generator:', err);
|
||||
} finally {
|
||||
// Optional: do not exit to allow long-running processes; but align with other scripts:
|
||||
// process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
logger.error('Unhandled error:', err);
|
||||
// process.exit(1);
|
||||
});
|
||||
1368
src/musicspot_generator/v1/infinitydance/scenes.json
Normal file
1368
src/musicspot_generator/v1/infinitydance/scenes.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/musicspot_generator/v1/oputstise/face.png
Normal file
BIN
src/musicspot_generator/v1/oputstise/face.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Binary file not shown.
827
src/musicspot_generator/v1/oputstise/scenes.json
Normal file
827
src/musicspot_generator/v1/oputstise/scenes.json
Normal file
@ -0,0 +1,827 @@
|
||||
{
|
||||
"character": {
|
||||
"bodyType": "slim and youthful",
|
||||
"hairStyle": "long straight blonde hair, white skin, blue eyes, light makeup"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"time": "Evening",
|
||||
"location": "Recording studio with warm lighting, microphone, pop filter, and soundproof walls",
|
||||
"outfit": "cute pastel dress with stockings and studio-style headphones",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing close to microphone with both hands on headphones",
|
||||
"action": "singing passionately with eyes closed",
|
||||
"camera": [
|
||||
"front medium shot centered on microphone and pop filter",
|
||||
"close-up on her lips behind pop filter",
|
||||
"side profile with blurred studio lights",
|
||||
"low angle capturing hands holding headphones",
|
||||
"over-shoulder shot showing recording booth perspective"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning slightly forward into microphone",
|
||||
"action": "singing softly with focused expression",
|
||||
"camera": [
|
||||
"tight close-up through pop filter mesh",
|
||||
"side close-up emphasizing focus in her eyes",
|
||||
"rear shot with blurred soundboard in background",
|
||||
"medium shot with studio monitors visible",
|
||||
"handheld dolly-in for intimate effect"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "one hand holding microphone stand, other hand raised slightly",
|
||||
"action": "singing energetically with emotion",
|
||||
"camera": [
|
||||
"front low angle emphasizing raised hand",
|
||||
"wide shot showing booth environment",
|
||||
"profile shot with dramatic lighting",
|
||||
"close-up on hand gripping mic stand",
|
||||
"rear shot with blurred pop filter frame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "adjusting headphones with one hand while singing",
|
||||
"action": "smiling softly between lyrics",
|
||||
"camera": [
|
||||
"front close-up on headphones adjustment",
|
||||
"side profile smile with blurred mic",
|
||||
"tight close-up on eyes sparkling",
|
||||
"rear dolly shot focusing on headphones",
|
||||
"medium shot with warm studio lights behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "sitting on studio stool in front of mic",
|
||||
"action": "closing eyes and holding lyrics sheet while singing",
|
||||
"camera": [
|
||||
"front shot framing mic and lyric sheet",
|
||||
"close-up on lyric sheet in hand",
|
||||
"side shot capturing relaxed pose",
|
||||
"rear shot with blurred mixing desk",
|
||||
"wide establishing shot of whole studio booth"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"time": "Day",
|
||||
"location": "Minimalistic modern recording studio, all white walls and furniture, microphone with pop filter and sound panels",
|
||||
"outfit": "elegant pure white dress with sheer stockings and studio headphones",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing gracefully in front of white microphone setup",
|
||||
"action": "singing with serene expression, both hands gently on headphones",
|
||||
"camera": [
|
||||
"front medium shot with pure white background",
|
||||
"close-up on serene face framed by white headphones",
|
||||
"side profile with white mic and pop filter",
|
||||
"low angle emphasizing elegance of white dress",
|
||||
"rear over-shoulder shot into white booth"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning slightly toward microphone stand",
|
||||
"action": "singing softly with eyes closed",
|
||||
"camera": [
|
||||
"tight close-up through white pop filter mesh",
|
||||
"profile capturing closed eyes and focus",
|
||||
"rear shot showing clean white acoustic panels",
|
||||
"medium shot with glowing white lighting",
|
||||
"slow dolly-in on her face from side"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "raising one hand gracefully in the air while singing",
|
||||
"action": "expressing emotion with body movement",
|
||||
"camera": [
|
||||
"front low angle emphasizing raised hand",
|
||||
"wide shot of white studio environment",
|
||||
"side profile with flowing dress detail",
|
||||
"close-up on extended hand in soft light",
|
||||
"rear shot capturing silhouette in white glow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "adjusting headphones gently with one hand",
|
||||
"action": "smiling subtly between lyrics",
|
||||
"camera": [
|
||||
"front close-up with headphones in frame",
|
||||
"side profile smile against white wall",
|
||||
"tight close-up on sparkling eyes",
|
||||
"medium shot with microphone blurred in foreground",
|
||||
"over-shoulder capturing white minimalist interior"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "sitting elegantly on modern white stool",
|
||||
"action": "holding lyric sheet in lap while singing softly",
|
||||
"camera": [
|
||||
"front shot framing mic and lyric sheet",
|
||||
"close-up on hands holding paper",
|
||||
"side shot with white studio lights glowing",
|
||||
"rear shot showing full white booth setup",
|
||||
"wide establishing shot of minimal white studio"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"time": "Afternoon",
|
||||
"location": "Spacious dance studio with mirrored walls, wooden floor, and bright ceiling lights",
|
||||
"outfit": "sporty outfit: cropped pastel hoodie with black track pants and white sneakers",
|
||||
"appearance": "hair wet and clinging to face from sweat, skin glowing with perspiration",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing in front of mirror with hands on knees",
|
||||
"action": "breathing heavily, sweat face, wet hair",
|
||||
"camera": [
|
||||
"front medium shot showing sweat on face",
|
||||
"rear shot capturing reflection in mirror",
|
||||
"low angle emphasizing strong posture",
|
||||
"side close-up on sweat dripping",
|
||||
"handheld shaky cam for intensity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning back slightly with arms raised",
|
||||
"action": "stretching arms after intense dancing",
|
||||
"camera": [
|
||||
"front wide shot with arms extended",
|
||||
"side profile with sweat-soaked hair",
|
||||
"low angle highlighting arms and torso",
|
||||
"rear shot with mirrored reflection",
|
||||
"close-up on exhausted but determined face"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "mid-dance move, sliding one foot forward",
|
||||
"action": "serious expression, body low to ground",
|
||||
"camera": [
|
||||
"front wide shot capturing dynamic motion",
|
||||
"low angle emphasizing movement power",
|
||||
"side tracking following slide motion",
|
||||
"rear shot reflecting in mirrors",
|
||||
"close-up on concentrated eyes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "sitting on floor with legs stretched out",
|
||||
"action": "wiping sweat from forehead with towel",
|
||||
"camera": [
|
||||
"close-up on towel wiping sweat",
|
||||
"side profile with hair clinging to cheek",
|
||||
"rear shot showing reflection in mirror",
|
||||
"wide establishing studio shot",
|
||||
"handheld zoom-in on tired smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "crouching low with one hand on floor",
|
||||
"action": "finishing dance move with powerful stance",
|
||||
"camera": [
|
||||
"front low angle emphasizing strength",
|
||||
"side profile showing sweat flying off",
|
||||
"rear shot with doubled mirror reflection",
|
||||
"medium shot focusing on determined eyes",
|
||||
"handheld circular shot for energy"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"time": "Morning",
|
||||
"location": "Park with trees and soft mist",
|
||||
"outfit": "pastel knit sweater with checkered mini skirt and black stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking slowly on misty path",
|
||||
"action": "touching leaves as she passes",
|
||||
"camera": [
|
||||
"wide shot with mist and sunrays",
|
||||
"rear tracking shot through trees",
|
||||
"close-up of hand brushing leaves",
|
||||
"side profile with foggy background",
|
||||
"drone rising above misty path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing still among trees",
|
||||
"action": "stretching arms out to feel the morning air",
|
||||
"camera": [
|
||||
"front wide shot with rays filtering",
|
||||
"over-shoulder capturing mist depth",
|
||||
"low angle emphasizing trees and sky",
|
||||
"medium shot with fog swirling around",
|
||||
"handheld pan upward following arms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting on wooden bench",
|
||||
"action": "exhaling softly and smiling peacefully",
|
||||
"camera": [
|
||||
"side profile with mist behind",
|
||||
"close-up on serene smile",
|
||||
"rear shot framing bench and fog",
|
||||
"slow dolly-in through mist",
|
||||
"wide landscape shot with her small figure"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "kneeling on grass with hands in dew",
|
||||
"action": "looking at water drops sparkling",
|
||||
"camera": [
|
||||
"macro close-up of dew on grass",
|
||||
"low angle framing her hands",
|
||||
"profile shot with blurred trees",
|
||||
"overhead soft focus on her and ground",
|
||||
"slow tilt from grass to her eyes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "walking across a small wooden bridge",
|
||||
"action": "pausing to lean on railing and smile",
|
||||
"camera": [
|
||||
"wide shot of bridge in mist",
|
||||
"rear tracking her walk",
|
||||
"medium shot of leaning pose",
|
||||
"close-up on gentle smile",
|
||||
"drone reveal showing forest below"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"time": "Afternoon",
|
||||
"location": "Flower field under bright blue sky",
|
||||
"outfit": "pastel pink one-piece dress with white lace stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing with arms open wide",
|
||||
"action": "spinning slowly among flowers",
|
||||
"camera": [
|
||||
"wide drone shot circling her spin",
|
||||
"low angle capturing flowers and sky",
|
||||
"tracking shot through flowers toward her",
|
||||
"rear silhouette against sunlit sky",
|
||||
"close-up on smiling face with flowers blurred"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "kneeling among flowers",
|
||||
"action": "gently touching petals with fingers",
|
||||
"camera": [
|
||||
"macro close-up of fingers on petals",
|
||||
"profile shot with blurred blooms",
|
||||
"overhead capturing flower pattern",
|
||||
"low angle with flowers framing face",
|
||||
"slow dolly-in through blossoms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "lying on back in field",
|
||||
"action": "looking up at clouds and laughing",
|
||||
"camera": [
|
||||
"overhead bird’s-eye view",
|
||||
"close-up on laughing face with flowers",
|
||||
"side shot across grass level",
|
||||
"rear shot with blue sky backdrop",
|
||||
"handheld zoom-in with shaky intimacy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "walking barefoot through flowers",
|
||||
"action": "lifting skirt slightly while smiling",
|
||||
"camera": [
|
||||
"low angle on feet in grass",
|
||||
"wide tracking shot from side",
|
||||
"rear dolly-in following footsteps",
|
||||
"medium shot with skirt lift motion",
|
||||
"close-up on glowing smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "sitting cross-legged in flowers",
|
||||
"action": "making a small flower crown",
|
||||
"camera": [
|
||||
"front close-up on crown weaving",
|
||||
"side profile with blurred blooms",
|
||||
"top-down focusing on hands",
|
||||
"rack focus from flowers to her eyes",
|
||||
"wide establishing shot of field"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"time": "Afternoon",
|
||||
"location": "Sunny street with pastel shops and flowers",
|
||||
"outfit": "pastel yellow mini dress with white knee-high socks and sneakers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing in middle of street",
|
||||
"action": "spinning playfully with dress flaring",
|
||||
"camera": [
|
||||
"wide establishing shot of street",
|
||||
"low angle focusing on dress spin",
|
||||
"tracking dolly circling her",
|
||||
"rear shot capturing spin from behind",
|
||||
"slow zoom-in on smiling face"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "walking along pastel shop windows",
|
||||
"action": "running fingers along glass",
|
||||
"camera": [
|
||||
"side tracking shot at hip level",
|
||||
"close-up on hand brushing glass",
|
||||
"reflection shot from window",
|
||||
"rear follow dolly with blurred people",
|
||||
"wide shot capturing full storefront"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning against pastel wall",
|
||||
"action": "making a heart shape with hands",
|
||||
"camera": [
|
||||
"tight close-up on hands forming heart",
|
||||
"fish-eye wide close-up",
|
||||
"side shot at 45°",
|
||||
"POV as if receiving heart",
|
||||
"zoom burst effect from wide to close"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "sitting on curb",
|
||||
"action": "tying shoelaces while smiling up",
|
||||
"camera": [
|
||||
"low angle close-up on hands and laces",
|
||||
"rear over-shoulder capturing face",
|
||||
"front medium shot with pastel background",
|
||||
"wide shot with street perspective",
|
||||
"handheld dolly-in to her smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "holding ice cream",
|
||||
"action": "taking playful bite and laughing",
|
||||
"camera": [
|
||||
"close-up on lips with ice cream",
|
||||
"profile with blurred shops",
|
||||
"rear shot with dripping ice cream",
|
||||
"slow-motion front focus on laugh",
|
||||
"wide shot with passing bicycles"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 7,
|
||||
"time": "Afternoon",
|
||||
"location": "Trendy café with modern pastel interior",
|
||||
"outfit": "white blouse tucked into pleated skirt with sheer white stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting at table with chin on hands",
|
||||
"action": "smiling softly while tilting head",
|
||||
"camera": [
|
||||
"front eye-level close-up",
|
||||
"over-shoulder with coffee cup foreground",
|
||||
"soft focus on eyes with blurred café",
|
||||
"panning shot across table",
|
||||
"low angle from tabletop upward"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing by window",
|
||||
"action": "writing playfully in notebook",
|
||||
"camera": [
|
||||
"profile with sunlight flare",
|
||||
"close-up of pen moving on page",
|
||||
"reflection in window glass",
|
||||
"tracking dolly up from feet",
|
||||
"medium shot with soft bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting sideways on chair",
|
||||
"action": "taking sip of coffee",
|
||||
"camera": [
|
||||
"tight focus on lips with cup",
|
||||
"medium framed by chair back",
|
||||
"dutch angle for playful energy",
|
||||
"slow dolly-in on sip",
|
||||
"wide establishing café interior"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "leaning on counter",
|
||||
"action": "resting chin on hands dreamily",
|
||||
"camera": [
|
||||
"profile with pastel counter lights",
|
||||
"close-up on dreamy eyes",
|
||||
"rear shot capturing café depth",
|
||||
"handheld tilt upward from arms",
|
||||
"medium shot with blurred background"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "standing at café entrance",
|
||||
"action": "waving playfully toward camera",
|
||||
"camera": [
|
||||
"wide shot framing doorway",
|
||||
"rear dolly out into street",
|
||||
"tight close-up on waving hand",
|
||||
"low angle capturing door sign",
|
||||
"tracking shot circling wave"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 8,
|
||||
"time": "Afternoon",
|
||||
"location": "Hilltop path with light mist and mountain view",
|
||||
"outfit": "lavender cardigan with flared pastel skirt and gray tights",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking up misty hill path",
|
||||
"action": "holding skirt slightly while climbing",
|
||||
"camera": [
|
||||
"rear tracking shot on path",
|
||||
"low angle capturing feet and mist",
|
||||
"wide shot with valley below",
|
||||
"side profile with wind blowing hair",
|
||||
"drone reveal rising above hill"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing at lookout",
|
||||
"action": "stretching arms wide into mist",
|
||||
"camera": [
|
||||
"front wide shot with horizon",
|
||||
"rear silhouette against misty valley",
|
||||
"low angle with sky backdrop",
|
||||
"close-up on hands spreading",
|
||||
"slow dolly-in from side"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting on rock",
|
||||
"action": "tying hair with calm expression",
|
||||
"camera": [
|
||||
"medium shot side profile",
|
||||
"close-up on hands tying hair",
|
||||
"rear shot framing valley mist",
|
||||
"handheld zoom to her smile",
|
||||
"wide establishing shot with mountains"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "kneeling on grass",
|
||||
"action": "picking wildflowers gently",
|
||||
"camera": [
|
||||
"macro on hand picking flowers",
|
||||
"low angle with valley in blur",
|
||||
"profile with mist behind",
|
||||
"top-down on her hands",
|
||||
"slow pan across field to her face"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "walking down hill path",
|
||||
"action": "looking back over shoulder smiling",
|
||||
"camera": [
|
||||
"rear tracking dolly with path",
|
||||
"close-up on over-shoulder smile",
|
||||
"wide shot with valley mist",
|
||||
"side tracking with flowing skirt",
|
||||
"drone pull-back revealing whole scene"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 9,
|
||||
"time": "Night",
|
||||
"location": "Balcony overlooking city lights",
|
||||
"outfit": "elegant black mini dress with sheer black stockings and heels",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing at balcony railing",
|
||||
"action": "gazing out over city lights",
|
||||
"camera": [
|
||||
"rear wide shot with city skyline",
|
||||
"profile silhouette against glowing lights",
|
||||
"close-up on hands gripping railing",
|
||||
"low angle capturing her and the skyline",
|
||||
"slow dolly-in from doorway"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning on railing with chin resting",
|
||||
"action": "smiling softly at the horizon",
|
||||
"camera": [
|
||||
"side profile with blurred city bokeh",
|
||||
"tight close-up on soft smile",
|
||||
"rear tracking shot along railing",
|
||||
"medium shot with glowing skyline",
|
||||
"handheld tilt capturing candid mood"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting on balcony chair",
|
||||
"action": "crossing legs elegantly while holding a glass",
|
||||
"camera": [
|
||||
"front eye-level medium shot",
|
||||
"low angle focusing on legs and glass",
|
||||
"profile silhouette against city",
|
||||
"close-up on glass near lips",
|
||||
"wide establishing balcony view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "standing near glass door",
|
||||
"action": "touching window glass gently",
|
||||
"camera": [
|
||||
"rear shot with reflection in glass",
|
||||
"side profile with neon reflection",
|
||||
"close-up of hand on glass surface",
|
||||
"soft focus tracking along her arm",
|
||||
"wide shot framing city lights outside"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "walking back inside",
|
||||
"action": "glancing over shoulder toward city",
|
||||
"camera": [
|
||||
"rear tracking shot into room",
|
||||
"close-up on over-shoulder look",
|
||||
"wide establishing shot of balcony",
|
||||
"low angle capturing dress movement",
|
||||
"slow dolly-in on her eyes"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 10,
|
||||
"time": "Night",
|
||||
"location": "Garden with lanterns and candlelight",
|
||||
"outfit": "flowy white long dress with lace stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking along lantern-lit path",
|
||||
"action": "holding a lantern gently in hand",
|
||||
"camera": [
|
||||
"wide shot with glowing lanterns",
|
||||
"rear tracking with path perspective",
|
||||
"close-up on lantern light in hand",
|
||||
"profile with candle bokeh",
|
||||
"drone shot rising above path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "kneeling by candle arrangement",
|
||||
"action": "lighting one candle softly",
|
||||
"camera": [
|
||||
"macro on candle flame igniting",
|
||||
"low angle capturing her face glow",
|
||||
"rear shot with many candles blurred",
|
||||
"side profile with flickering shadows",
|
||||
"handheld close-up on gentle smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting at small garden table",
|
||||
"action": "resting chin on hands dreamily",
|
||||
"camera": [
|
||||
"front close-up with lantern foreground",
|
||||
"side profile framed by soft lights",
|
||||
"wide shot showing whole garden",
|
||||
"over-shoulder focusing on glowing eyes",
|
||||
"slow dolly-in to serene smile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "standing beneath lantern tree",
|
||||
"action": "raising arms as if embracing lights",
|
||||
"camera": [
|
||||
"low angle capturing lantern canopy",
|
||||
"rear silhouette with glowing tree",
|
||||
"profile with bokeh lights behind",
|
||||
"wide establishing garden lights",
|
||||
"tracking circle shot around her pose"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "walking barefoot on grass",
|
||||
"action": "spinning lightly with dress flowing",
|
||||
"camera": [
|
||||
"rear dolly capturing flowing fabric",
|
||||
"low angle focusing on feet in grass",
|
||||
"wide shot with lanterns in background",
|
||||
"close-up on hair moving in spin",
|
||||
"handheld pan following her spin"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 11,
|
||||
"time": "Night",
|
||||
"location": "Grand medieval-style ballroom lit by hundreds of candles with golden chandeliers and gothic arches",
|
||||
"outfit": "elegant layered gown with multiple flowing fabric layers in soft pastel tones, paired with lace stockings and delicate shoes",
|
||||
"appearance": "hair styled in loose curls with a jeweled tiara, candlelight reflecting on the layered dress",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing gracefully in center of hall with arms slightly lifted",
|
||||
"action": "beginning a slow dance step, gazing downward softly",
|
||||
"camera": [
|
||||
"wide establishing shot of candlelit hall",
|
||||
"low angle emphasizing layered gown",
|
||||
"side profile with candles blurred in background",
|
||||
"rear shot capturing the dress flowing behind",
|
||||
"close-up on soft serene expression"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "spinning lightly with gown flaring out",
|
||||
"action": "smiling gracefully as layers swirl",
|
||||
"camera": [
|
||||
"front wide shot capturing gown layers in motion",
|
||||
"low angle showing candles and fabric layers",
|
||||
"rear shot with chandeliers glowing above",
|
||||
"close-up on swirling gown fabric",
|
||||
"handheld circular dolly around spin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "holding skirt edges delicately with both hands",
|
||||
"action": "stepping forward slowly with elegance",
|
||||
"camera": [
|
||||
"medium shot focusing on skirt layers",
|
||||
"profile capturing her careful step",
|
||||
"low angle with candlelight flicker",
|
||||
"rear shot with her shadow on marble floor",
|
||||
"close-up on hands lifting fabric layers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "pausing mid-dance with one hand extended outward",
|
||||
"action": "gazing toward candlelit balcony dreamily",
|
||||
"camera": [
|
||||
"front shot framing extended hand",
|
||||
"side profile with glowing candles",
|
||||
"rear wide shot capturing full hall depth",
|
||||
"close-up on face with candlelight reflections",
|
||||
"tracking dolly moving slowly toward her"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "ending dance with a graceful curtsy",
|
||||
"action": "bowing slightly with layered gown cascading",
|
||||
"camera": [
|
||||
"wide shot showing curtsy against hall arches",
|
||||
"low angle emphasizing fabric folds",
|
||||
"close-up on gown layers folding gracefully",
|
||||
"rear shot with chandeliers above her",
|
||||
"handheld tilt from gown to her smile"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 12,
|
||||
"time": "Night",
|
||||
"location": "Asian summer festival with hundreds of glowing lanterns floating into the night sky",
|
||||
"outfit": "cute pink summer dress with light fabric and white sandals",
|
||||
"appearance": "hair gently tied back with loose strands, warm glow of lantern light reflecting on her skin",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing among festival crowd holding a lantern",
|
||||
"action": "smiling softly as she prepares to release it",
|
||||
"camera": [
|
||||
"front medium shot with lantern glowing in hands",
|
||||
"close-up on her smile illuminated by warm light",
|
||||
"side profile with lantern crowd blurred",
|
||||
"rear shot with lanterns flying above",
|
||||
"wide establishing shot of festival atmosphere"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "lifting lantern upward with both hands",
|
||||
"action": "watching it float away with hopeful expression",
|
||||
"camera": [
|
||||
"low angle capturing lantern rising above her",
|
||||
"front wide shot with multiple lanterns",
|
||||
"close-up on her face lit by lantern glow",
|
||||
"rear silhouette shot against lantern sky",
|
||||
"handheld tilt following lantern upward"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "walking slowly through festival path",
|
||||
"action": "gazing up at lantern-filled sky",
|
||||
"camera": [
|
||||
"wide shot with festival stalls glowing",
|
||||
"rear tracking shot with lanterns overhead",
|
||||
"profile with lantern light on her cheek",
|
||||
"close-up on eyes reflecting lanterns",
|
||||
"medium shot with soft bokeh background"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "kneeling to help a child with lantern",
|
||||
"action": "smiling warmly while adjusting the lantern",
|
||||
"camera": [
|
||||
"front medium shot of interaction",
|
||||
"close-up on hands fixing lantern",
|
||||
"side profile with glowing lanterns above",
|
||||
"rear shot with child’s lantern rising",
|
||||
"wide establishing shot with crowd and lights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "standing still gazing upward",
|
||||
"action": "holding hands together in small prayer as lanterns rise",
|
||||
"camera": [
|
||||
"low angle with sky full of lanterns",
|
||||
"front shot focusing on gentle prayer",
|
||||
"rear silhouette against glowing night sky",
|
||||
"side profile capturing emotional look",
|
||||
"drone pull-out showing her among crowd"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
src/musicspot_generator/v1/oputstise/song.mp3
Normal file
BIN
src/musicspot_generator/v1/oputstise/song.mp3
Normal file
Binary file not shown.
272
src/musicspot_generator/v1/scenes.json
Normal file
272
src/musicspot_generator/v1/scenes.json
Normal file
@ -0,0 +1,272 @@
|
||||
{
|
||||
"character": {
|
||||
"bodyType": "slim and youthful",
|
||||
"hairStyle": "long wavy hair with pastel blue and purple colors"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"time": "Morning",
|
||||
"location": "Cozy bedroom with pastel bedding and sunlight through curtains",
|
||||
"outfit": "white oversized pajama shirt with thigh-high stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "lying on bed with head resting on hands",
|
||||
"action": "smiling softly at the camera",
|
||||
"camera": [
|
||||
"overhead shot from above capturing sunlight on her hair",
|
||||
"close-up of her face with shallow depth of field",
|
||||
"side angle showing body stretched on bed",
|
||||
"slow zoom-in from doorway",
|
||||
"handheld camera wobble for intimate feeling"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "stretching arms above head while sitting on bed",
|
||||
"action": "yawning cutely with eyes half closed",
|
||||
"camera": [
|
||||
"medium shot from foot of bed",
|
||||
"low angle from floor emphasizing legs",
|
||||
"wide shot with window light flaring",
|
||||
"tracking shot circling around her stretch",
|
||||
"soft focus tilt-shift framing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "kneeling on bed with playful look",
|
||||
"action": "blowing a kiss to the camera",
|
||||
"camera": [
|
||||
"front close-up catching kiss in slow motion",
|
||||
"wide shot with pastel background",
|
||||
"camera tilt from below lips to eyes",
|
||||
"360° pan around her kneeling pose",
|
||||
"handheld push-in as she blows kiss"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"time": "Morning",
|
||||
"location": "Bedroom near window with plants and sunlight",
|
||||
"outfit": "light pastel camisole with short pleated skirt and stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting on window sill, legs slightly crossed",
|
||||
"action": "looking outside then turning to smile",
|
||||
"camera": [
|
||||
"silhouette against sunlight",
|
||||
"side profile with plants blurred in foreground",
|
||||
"close-up of smile turning to camera",
|
||||
"dolly-in from outside window glass",
|
||||
"over-shoulder shot capturing view outside"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "leaning against the wall, hands behind back",
|
||||
"action": "giggling with shy expression",
|
||||
"camera": [
|
||||
"eye-level shot with wall texture visible",
|
||||
"slight high angle to emphasize cuteness",
|
||||
"medium close-up on giggle with tilt",
|
||||
"rack focus between wall décor and her face",
|
||||
"soft handheld sway left to right"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "lying on floor with legs up against the wall",
|
||||
"action": "kicking feet playfully while laughing",
|
||||
"camera": [
|
||||
"top-down view from ceiling",
|
||||
"low angle from foot level",
|
||||
"side shot capturing playful kicks",
|
||||
"slow pan across her body",
|
||||
"handheld camera zoom-in to laughter"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"time": "Afternoon",
|
||||
"location": "Sunny street with pastel shops and flowers",
|
||||
"outfit": "short pastel pink dress with white stockings and sneakers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing with one hand on hip",
|
||||
"action": "spinning gently in place",
|
||||
"camera": [
|
||||
"full body wide shot with pastel shops",
|
||||
"low angle capturing dress swirl",
|
||||
"tracking shot circling spin",
|
||||
"handheld slow zoom-in to face",
|
||||
"rear shot revealing spin from behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "walking with small steps",
|
||||
"action": "waving happily at the camera",
|
||||
"camera": [
|
||||
"tracking dolly shot in front",
|
||||
"overhead drone shot of street",
|
||||
"side follow shot at hip level",
|
||||
"handheld jitter to mimic vlog",
|
||||
"close-up on waving hand with face blurred"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning forward playfully",
|
||||
"action": "making a heart shape with hands",
|
||||
"camera": [
|
||||
"tight close-up on hands forming heart",
|
||||
"fish-eye wide close-up",
|
||||
"side shot at 45°",
|
||||
"POV shot as if receiving heart",
|
||||
"zoom burst effect from wide to close"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"time": "Afternoon",
|
||||
"location": "Trendy café with bright modern interior",
|
||||
"outfit": "white blouse tucked into pleated skirt with stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting at a table with chin on hands",
|
||||
"action": "smiling softly while tilting head",
|
||||
"camera": [
|
||||
"front eye-level close-up",
|
||||
"soft focus on eyes, blurred background",
|
||||
"over-shoulder shot of coffee cup",
|
||||
"panning shot across table to her",
|
||||
"low angle from table surface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing by window with crossed legs",
|
||||
"action": "writing playfully in a small notebook",
|
||||
"camera": [
|
||||
"profile with sunlight flare",
|
||||
"close-up of pen on paper then tilt to face",
|
||||
"tracking shot from feet to head",
|
||||
"reflection in window glass",
|
||||
"medium shot with bokeh lights behind"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "sitting sideways on chair with one leg up",
|
||||
"action": "taking a sip from a cup with cute expression",
|
||||
"camera": [
|
||||
"tight focus on lips touching cup",
|
||||
"medium shot framed by chair back",
|
||||
"slight dutch angle for energy",
|
||||
"slow dolly-in on playful sip",
|
||||
"wide establishing shot of café"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"time": "Night",
|
||||
"location": "Elegant ballroom with chandeliers",
|
||||
"outfit": "sparkly silver mini dress with black stockings and heels",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing tall with one hand on waist",
|
||||
"action": "turning slowly while smiling confidently",
|
||||
"camera": [
|
||||
"wide shot capturing chandelier",
|
||||
"low angle emphasizing elegance",
|
||||
"tracking dolly rotation",
|
||||
"close-up of smile during turn",
|
||||
"rear tracking shot revealing gown shimmer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "sitting gracefully on a velvet chair",
|
||||
"action": "crossing legs elegantly",
|
||||
"camera": [
|
||||
"medium close-up from side",
|
||||
"top-down angle showing chair texture",
|
||||
"front focus on crossed legs",
|
||||
"soft rack focus from chair to her face",
|
||||
"panning shot circling chair"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning on railing with dreamy look",
|
||||
"action": "gazing at the chandelier lights",
|
||||
"camera": [
|
||||
"over-shoulder shot of chandelier view",
|
||||
"profile silhouette with golden backlight",
|
||||
"wide shot capturing ballroom depth",
|
||||
"handheld tilt up from railing to face",
|
||||
"slow dolly-out revealing emptiness of hall"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"time": "Night",
|
||||
"location": "Luxurious bedroom with soft golden lighting",
|
||||
"outfit": "black lace camisole with mini skirt and stockings",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "lying sideways on bed with legs slightly bent",
|
||||
"action": "looking at the camera with sultry eyes",
|
||||
"camera": [
|
||||
"close-up on eyes with blurred background",
|
||||
"tracking shot along legs up to face",
|
||||
"overhead soft focus",
|
||||
"low angle from bed surface",
|
||||
"handheld intimate pan across body"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "sitting at vanity table",
|
||||
"action": "putting on earrings slowly",
|
||||
"camera": [
|
||||
"mirror reflection focus",
|
||||
"close-up on hands adjusting earrings",
|
||||
"profile side shot with warm glow",
|
||||
"over-shoulder shot including vanity lights",
|
||||
"slow push-in from doorway"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "kneeling on bed with arched back",
|
||||
"action": "running hand through hair with sensual expression",
|
||||
"camera": [
|
||||
"rear shot with back arch emphasized",
|
||||
"medium close-up focusing on hair movement",
|
||||
"low angle capturing curves",
|
||||
"soft focus candlelight bokeh",
|
||||
"circling dolly shot for dramatic effect"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
259
src/musicspot_generator/v1/videos.ts
Normal file
259
src/musicspot_generator/v1/videos.ts
Normal file
@ -0,0 +1,259 @@
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
import { logger } from '../../lib/logger';
|
||||
import { callOpenAI } from '../../lib/openai';
|
||||
import { generateVideo } from '../../lib/video-generator';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
type Size = { width: number; height: number };
|
||||
|
||||
interface MusicSpotCharacter {
|
||||
bodyType: string;
|
||||
hairStyle: string;
|
||||
}
|
||||
|
||||
interface MusicSpotCut {
|
||||
cutId: number;
|
||||
pose: string;
|
||||
action: string;
|
||||
camera?: string[]; // list of camera variants per cut
|
||||
}
|
||||
|
||||
interface MusicSpotScene {
|
||||
sceneId: number;
|
||||
time: string;
|
||||
location: string;
|
||||
outfit: string;
|
||||
cuts: MusicSpotCut[];
|
||||
}
|
||||
|
||||
interface MusicSpotConfig {
|
||||
character: MusicSpotCharacter;
|
||||
scenes: MusicSpotScene[];
|
||||
}
|
||||
|
||||
interface Server {
|
||||
baseUrl?: string;
|
||||
outputDir?: string;
|
||||
inputDir?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SIZE: Size = { width: 1280, height: 720 };
|
||||
const FOLDER = process.argv[2] || process.env.MUSICSPOT_FOLDER || 'infinitydance';
|
||||
const FOLDER_SAFE = FOLDER.replace(/[/\\?%*:|"<>]/g, '_');
|
||||
const GENERATED_DIR = path.resolve('generated');
|
||||
|
||||
function loadServers(): Server[] {
|
||||
const servers: Server[] = [
|
||||
{
|
||||
name: 'SERVER1',
|
||||
baseUrl: process.env.SERVER1_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR,
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: 'SERVER2',
|
||||
baseUrl: process.env.SERVER2_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR,
|
||||
},*/
|
||||
]
|
||||
.filter((s) => !!s.baseUrl && !!s.outputDir)
|
||||
.map((s) => ({
|
||||
...s,
|
||||
inputDir: s.outputDir!.replace(/output/i, 'input'),
|
||||
}));
|
||||
|
||||
if (servers.length === 0) {
|
||||
logger.warn('No servers configured. Please set SERVER{N}_COMFY_BASE_URL and SERVER{N}_COMFY_OUTPUT_DIR in .env');
|
||||
} else {
|
||||
for (const s of servers) {
|
||||
logger.info(`Configured ${s.name}: baseUrl=${s.baseUrl}, outputDir=${s.outputDir}, inputDir=${s.inputDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
async function ensureDirs() {
|
||||
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
function buildVideoPromptRequest(
|
||||
character: MusicSpotCharacter,
|
||||
scene: MusicSpotScene,
|
||||
cut: MusicSpotCut,
|
||||
cameraIntent: string
|
||||
): string {
|
||||
return `
|
||||
Return exactly one JSON object and nothing else: { "videoPrompt": "..." }.
|
||||
|
||||
Write "videoPrompt" in 100–140 words. Present tense. Concrete, simple sentences.
|
||||
|
||||
HARD RULES:
|
||||
- One continuous 8-second shot (oner). No edits.
|
||||
- Fixed location and general vantage; maintain spatial continuity.
|
||||
- No zooms, no rack zoom, no smash/push-in, no cuts, no transitions, no "meanwhile".
|
||||
- Camera motion: at most a slight pan/tilt or subtle dolly within 1 meter.
|
||||
- Keep framing consistent (vertical 720x1280). Avoid technical brand names or lens jargon.
|
||||
|
||||
Incorporate the following camera intention: "${cameraIntent}".
|
||||
If it conflicts with HARD RULES (e.g., zoom, push-in, extreme moves), reinterpret it into a subtle, compliant motion (e.g., gentle glide, slight pan/tilt) while preserving the creative intent.
|
||||
|
||||
Describe:
|
||||
1) Main action: ${cut.action}
|
||||
2) Pose/composition: ${cut.pose}
|
||||
3) Scene/time/location/outfit: ${scene.time}; ${scene.location}; outfit: ${scene.outfit}
|
||||
4) Lighting/mood/style coherent with the character: ${character.bodyType}; hair: ${character.hairStyle}
|
||||
|
||||
Prohibited (case-insensitive): cut, cuts, cutting, quick cut, insert, close-up, extreme close-up, zoom, zooming, push-in, pull-out, whip, switch angle, change angle, montage, cross-cut, smash cut, transition, meanwhile, later.
|
||||
|
||||
Only respond with JSON.
|
||||
`.trim();
|
||||
}
|
||||
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function getVideoPromptFromOpenAI(req: string): Promise<string> {
|
||||
const res = await callOpenAI(req);
|
||||
const prompt = res?.videoPrompt || res?.video_prompt || res?.prompt;
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
throw new Error('OpenAI failed to return videoPrompt JSON.');
|
||||
}
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
function pickServer(servers: Server[], idx: number): Server {
|
||||
if (servers.length === 0) {
|
||||
throw new Error('No servers configured.');
|
||||
}
|
||||
return servers[idx % servers.length];
|
||||
}
|
||||
|
||||
async function copyImageToAllServerInputs(servers: Server[], localGeneratedImagePath: string): Promise<string> {
|
||||
const fileName = path.basename(localGeneratedImagePath);
|
||||
for (const s of servers) {
|
||||
if (!s.inputDir) continue;
|
||||
const dest = path.join(s.inputDir, fileName);
|
||||
try {
|
||||
await fs.copyFile(localGeneratedImagePath, dest);
|
||||
logger.debug(`Copied ${fileName} to ${s.name} input: ${dest}`);
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to copy ${fileName} to ${s.name} input: ${err}`);
|
||||
}
|
||||
}
|
||||
return fileName; // return the name used for Comfy workflows
|
||||
}
|
||||
|
||||
async function fileExists(p: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(p);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await ensureDirs();
|
||||
|
||||
// Load scenes.json
|
||||
const configRaw = await fs.readFile(path.resolve(`src/musicspot_generator/${FOLDER}/scenes.json`), 'utf-8');
|
||||
const cfg: MusicSpotConfig = JSON.parse(configRaw);
|
||||
|
||||
const servers = loadServers();
|
||||
if (servers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate videos only, based on images already present in ./generated
|
||||
let videoTaskIndex = 0;
|
||||
|
||||
for (const scene of cfg.scenes) {
|
||||
logger.info(`=== Scene ${scene.sceneId}: Video generation start ===`);
|
||||
for (const cut of scene.cuts) {
|
||||
const cameraVariants =
|
||||
Array.isArray(cut.camera) && cut.camera.length > 0
|
||||
? cut.camera
|
||||
: ['eye-level medium shot', 'slight left 30°', 'slight right 30°', 'slight high angle', 'slight low angle'];
|
||||
|
||||
for (let camIdx = 0; camIdx < cameraVariants.length; camIdx++) {
|
||||
const cameraIntent = cameraVariants[camIdx];
|
||||
const variantIndex = camIdx + 1;
|
||||
|
||||
const imgFileName = `${FOLDER_SAFE}_musicspot_s${scene.sceneId}_c${cut.cutId}_v${variantIndex}.png`;
|
||||
const imgPath = path.join(GENERATED_DIR, imgFileName);
|
||||
|
||||
// Only proceed if image exists
|
||||
const hasImage = await fileExists(imgPath);
|
||||
if (!hasImage) {
|
||||
logger.warn(`Skipping video: source image not found: ${imgPath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const videoFileName = imgFileName.replace(/\.png$/i, '.mp4');
|
||||
const videoOutPath = path.join(GENERATED_DIR, videoFileName);
|
||||
|
||||
// Skip if video already
|
||||
const hasVideo = await fileExists(videoOutPath);
|
||||
if (hasVideo) {
|
||||
logger.info(`Video already exists, skipping: ${videoOutPath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1) Generate video prompt for this camera
|
||||
logger.info(
|
||||
`Scene ${scene.sceneId} - Cut ${cut.cutId} - Cam${variantIndex}: generating video prompt from image ${imgFileName}...`
|
||||
);
|
||||
const vidPromptReq = buildVideoPromptRequest(cfg.character, scene, cut, cameraIntent);
|
||||
|
||||
let videoPrompt: string;
|
||||
try {
|
||||
videoPrompt = await getVideoPromptFromOpenAI(vidPromptReq);
|
||||
} catch (err) {
|
||||
logger.error(`OpenAI video prompt failed for ${imgFileName}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2) Copy the base image to every server's input folder
|
||||
const imageFileNameForComfy = await copyImageToAllServerInputs(servers, imgPath);
|
||||
|
||||
// 3) Generate video on a chosen server (round-robin)
|
||||
const serverForVideo = pickServer(servers, videoTaskIndex++);
|
||||
logger.info(`Generating video (${videoFileName}) on ${serverForVideo.name} using ${imageFileNameForComfy}...`);
|
||||
|
||||
try {
|
||||
const videoPath = await generateVideo(
|
||||
videoPrompt,
|
||||
imageFileNameForComfy,
|
||||
videoFileName,
|
||||
serverForVideo.baseUrl!,
|
||||
serverForVideo.outputDir!,
|
||||
DEFAULT_SIZE,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
await sleep(10000); // wait a bit for file system to settle
|
||||
logger.info(`Video generated: ${videoPath}`);
|
||||
} catch (err) {
|
||||
logger.error(`Video generation failed (${videoFileName}) on ${serverForVideo.name}: ${err}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info(`=== Scene ${scene.sceneId}: Video generation complete ===`);
|
||||
}
|
||||
|
||||
logger.info('Video generation for all scenes completed.');
|
||||
} catch (err) {
|
||||
logger.error('Fatal error in music spot video generator:', err);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
logger.error('Unhandled error:', err);
|
||||
});
|
||||
BIN
src/musicspot_generator/v1/zagreb/face.png
Normal file
BIN
src/musicspot_generator/v1/zagreb/face.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
834
src/musicspot_generator/v1/zagreb/scenes.json
Normal file
834
src/musicspot_generator/v1/zagreb/scenes.json
Normal file
@ -0,0 +1,834 @@
|
||||
{
|
||||
"character": {
|
||||
"bodyType": "average",
|
||||
"hairStyle": "long blonde hair tied in a man bun, white skin, blue eyes, beard"
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"sceneId": 1,
|
||||
"season": "Autumn",
|
||||
"time": "Evening",
|
||||
"location": "Zagreb skyline viewpoint with light fog and warm city lights",
|
||||
"outfit": "dark gray adidas joggers with white side stripes, black heavyweight hoodie (hood down), light quilted autumn jacket in charcoal, white adidas sneakers slightly scuffed, black knit beanie",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing at viewpoint railing",
|
||||
"action": "looking over city while exhaling misty breath",
|
||||
"camera": [
|
||||
"fullbody shot with skyline and fog glow",
|
||||
"closeup on eyes and misty breath",
|
||||
"back shot framed by city lights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "hands in pockets",
|
||||
"action": "nodding head slowly to beat",
|
||||
"camera": [
|
||||
"fullbody shot silhouetted against skyline",
|
||||
"closeup on subtle head nod and beard",
|
||||
"side shot with drifting fog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "feet near railing edge",
|
||||
"action": "dancing: tight heel-toe shuffle forward and back, ankles loose, arms swinging low in relaxed groove",
|
||||
"camera": [
|
||||
"fullbody shot wide skyline backdrop",
|
||||
"closeup on footwork over wet stone",
|
||||
"side shot tracking along railing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "one arm lifted",
|
||||
"action": "dancing: step-touch left/right with rolling shoulders and head bobs on the snare",
|
||||
"camera": [
|
||||
"fullbody shot low angle, lights behind",
|
||||
"closeup on rolling shoulders and hoodie fabric",
|
||||
"back shot into glowing fog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "leaning against railing",
|
||||
"action": "staring straight into lens with confident half-smile",
|
||||
"camera": [
|
||||
"fullbody shot framed by rail",
|
||||
"closeup on confident stare",
|
||||
"side shot with fog drift"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 2,
|
||||
"season": "Autumn",
|
||||
"time": "Day",
|
||||
"location": "Inside Zagreb blue tram, sunlight streaks through windows",
|
||||
"outfit": "mid-blue jeans, white cotton t-shirt under light gray zip hoodie, navy bomber jacket, clean white adidas sneakers, simple black wristwatch",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting by window",
|
||||
"action": "writing lyrics in notebook as city blurs past",
|
||||
"camera": [
|
||||
"fullbody shot seated by window",
|
||||
"closeup on pen and notebook",
|
||||
"side shot with city motion streaks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing near door holding rail",
|
||||
"action": "dancing: rail-hold groove with shoulder ticks and toe taps in sync with tram sway",
|
||||
"camera": [
|
||||
"fullbody shot vertical down tram aisle",
|
||||
"closeup on toe taps on rubber floor",
|
||||
"side shot from opposite pole"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning on glass",
|
||||
"action": "fogging window with breath then drawing a small heart",
|
||||
"camera": [
|
||||
"fullbody shot in window bay",
|
||||
"closeup on fingertip tracing heart",
|
||||
"side shot with sunlight flare"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "feet apart, both hands on strap",
|
||||
"action": "dancing: micro two-step in place with chest pops on backbeat",
|
||||
"camera": [
|
||||
"fullbody shot in aisle",
|
||||
"closeup on chest pops through hoodie",
|
||||
"back shot down toward exit door"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "stepping off tram",
|
||||
"action": "placing foot on wet pavement and glancing up",
|
||||
"camera": [
|
||||
"fullbody shot exiting with tram behind",
|
||||
"closeup on sneaker hitting puddle",
|
||||
"side shot tracking walk away"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 3,
|
||||
"season": "Autumn",
|
||||
"time": "Morning",
|
||||
"location": "Dolac market with red umbrellas, crisp air",
|
||||
"outfit": "black adidas joggers, cream knit t-shirt under a denim trucker jacket, white adidas sneakers with gray socks, fingerless knit gloves",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking through market",
|
||||
"action": "nodding to vendors and smiling",
|
||||
"camera": [
|
||||
"fullbody shot weaving among umbrellas",
|
||||
"closeup on smile and beard",
|
||||
"side shot with shoppers blurred"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "open space between stalls",
|
||||
"action": "dancing: pivot-spin on heel, one arm slicing air, stopping on beat",
|
||||
"camera": [
|
||||
"fullbody shot centered under umbrellas",
|
||||
"closeup on pivoting sneaker",
|
||||
"back shot with umbrellas radiating"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "holding an apple",
|
||||
"action": "taking a bite and chuckling",
|
||||
"camera": [
|
||||
"fullbody shot framed by produce colors",
|
||||
"closeup on bite and beard",
|
||||
"side shot with vendor in bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "near stall edge",
|
||||
"action": "dancing: side-step bounce with finger snaps and quick shoulder check",
|
||||
"camera": [
|
||||
"fullbody shot on cobblestone",
|
||||
"closeup on finger snaps",
|
||||
"side shot past crates of apples"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "sitting on bench",
|
||||
"action": "exhaling a long misty breath up to sky",
|
||||
"camera": [
|
||||
"fullbody shot bench among umbrellas",
|
||||
"closeup on breath plume",
|
||||
"back shot to morning light"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 4,
|
||||
"season": "Autumn",
|
||||
"time": "Afternoon",
|
||||
"location": "Graffiti alley glowing with neon tubes and hanging fog",
|
||||
"outfit": "charcoal adidas joggers, navy heavyweight hoodie layered under a black denim jacket, white adidas sneakers worn at toes, charcoal beanie, silver chain",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "line with two friends",
|
||||
"action": "dancing: synchronized stomp-stomp-slide combo with shoulder hits (together)",
|
||||
"camera": [
|
||||
"fullbody shot of trio in wide alley",
|
||||
"closeup on synchronized sneakers",
|
||||
"side shot panning across the line"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "center of small circle",
|
||||
"action": "dancing: knee spin to floor to knee up while friends clap and hype (together focus on him)",
|
||||
"camera": [
|
||||
"fullbody shot near ground level",
|
||||
"closeup on balancing palm and sleeve",
|
||||
"back shot showing friends clapping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning on wall",
|
||||
"action": "rapping directly to camera, neon flicker behind",
|
||||
"camera": [
|
||||
"fullbody shot against graffiti panel",
|
||||
"closeup on lips and breath in cold air",
|
||||
"side shot with neon reflections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "shoulder to shoulder with friends",
|
||||
"action": "dancing: side-step shuffle with hand waves and head whips (together)",
|
||||
"camera": [
|
||||
"fullbody shot three-wide groove",
|
||||
"closeup on hand waves across frame",
|
||||
"back shot down glowing alley"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "arms stretched open",
|
||||
"action": "looking up as fog lifts around lights",
|
||||
"camera": [
|
||||
"fullbody shot silhouette in neon haze",
|
||||
"closeup on eyes lit by tubes",
|
||||
"side shot past a painted mural"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 5,
|
||||
"season": "Autumn",
|
||||
"time": "Evening",
|
||||
"location": "Sava riverbank at golden hour with low mist",
|
||||
"outfit": "mid-wash jeans, black long-sleeve tee under olive lightweight parka, white adidas sneakers with darker laces, gray knit scarf",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking riverside",
|
||||
"action": "dancing: loose arm swing with heel peels and forward glide",
|
||||
"camera": [
|
||||
"fullbody shot along river path",
|
||||
"closeup on heel peel on damp gravel",
|
||||
"side shot with river reflections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "hands in parka pockets",
|
||||
"action": "gazing at sun reflecting on water",
|
||||
"camera": [
|
||||
"fullbody shot silhouette at bank",
|
||||
"closeup on eyes catching gold",
|
||||
"back shot toward low sun"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "standing by railing",
|
||||
"action": "tapping rhythm on rail with knuckles",
|
||||
"camera": [
|
||||
"fullbody shot framed by rail lines",
|
||||
"closeup on tapping knuckles",
|
||||
"side shot with mist ribboning"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "open space at water edge",
|
||||
"action": "dancing: slide-to-cross step with chest pop accent and arm sweep",
|
||||
"camera": [
|
||||
"fullbody shot river behind",
|
||||
"closeup on chest pop under tee",
|
||||
"side shot tracking along water"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "head tilted back",
|
||||
"action": "breathing out slowly, eyes closed",
|
||||
"camera": [
|
||||
"fullbody shot with fading sun",
|
||||
"closeup on breath plume dispersing",
|
||||
"back shot to amber sky"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 6,
|
||||
"season": "Autumn",
|
||||
"time": "Night",
|
||||
"location": "Ban Jelačić Square with neon ads and light fog",
|
||||
"outfit": "black adidas joggers, gray t-shirt, slate bomber jacket, white adidas sneakers, fingerless gloves",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "group line facing camera",
|
||||
"action": "dancing: bounce-bounce-step pattern with knee lifts in unison (together)",
|
||||
"camera": [
|
||||
"fullbody shot of group centered in square",
|
||||
"closeup on synchronized knees",
|
||||
"side shot with neon bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "front of dance circle",
|
||||
"action": "dancing: spin in, arms open, stop on beat with chest hit (together feature)",
|
||||
"camera": [
|
||||
"fullbody shot in circle opening",
|
||||
"closeup on arm extension and jacket fold",
|
||||
"back shot toward statue and lights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "friends behind clapping",
|
||||
"action": "rapping at lens with fog swirling",
|
||||
"camera": [
|
||||
"fullbody shot square tiles reflecting",
|
||||
"closeup on lips and beard",
|
||||
"side shot past cheering friends"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "two friends flanking",
|
||||
"action": "dancing: traveling shuffle diagonally with toe digs and head tilts (together)",
|
||||
"camera": [
|
||||
"fullbody shot three-across traveling",
|
||||
"closeup on toe digs kicking sparks of water",
|
||||
"back shot crossing square"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "hands on hips",
|
||||
"action": "smiling up at neon glow",
|
||||
"camera": [
|
||||
"fullbody shot slight low angle",
|
||||
"closeup on smiling eyes",
|
||||
"side shot with tram passing blur"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 7,
|
||||
"season": "Autumn",
|
||||
"time": "Day",
|
||||
"location": "Corner café with fogged windows and warm Edison bulbs",
|
||||
"outfit": "dark jeans, soft oatmeal t-shirt, forest-green hoodie under tan canvas jacket, white adidas sneakers, wool cap",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "seated with two friends at table",
|
||||
"action": "dancing: table-top beat — finger drumming while shoulders groove (together)",
|
||||
"camera": [
|
||||
"fullbody shot across small table",
|
||||
"closeup on finger rhythms on wood",
|
||||
"side shot with fogged window"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing by chair facing friend",
|
||||
"action": "dancing: mirrored mini two-step and clap on two (together)",
|
||||
"camera": [
|
||||
"fullbody shot of paired groove",
|
||||
"closeup on clapping hands",
|
||||
"back shot toward bar lights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "holding coffee cup",
|
||||
"action": "blowing steam off cup and smirking",
|
||||
"camera": [
|
||||
"fullbody shot seated relaxed",
|
||||
"closeup on steam curling",
|
||||
"side shot with bulbs in bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "friends around hyping",
|
||||
"action": "dancing: quick spin ending in finger point to camera (together energy)",
|
||||
"camera": [
|
||||
"fullbody shot between tables",
|
||||
"closeup on finger point and grin",
|
||||
"back shot past other patrons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "leaning back in chair",
|
||||
"action": "exhaling lightly, calm confidence",
|
||||
"camera": [
|
||||
"fullbody shot reclined posture",
|
||||
"closeup on relaxed eyes",
|
||||
"side shot across window condensation"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 8,
|
||||
"season": "Autumn",
|
||||
"time": "Evening",
|
||||
"location": "Old Zagreb apartment balcony with laundry lines and city fog",
|
||||
"outfit": "black adidas joggers, slate long-sleeve t-shirt under navy quilted vest, white adidas sneakers, knit scarf",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "leaning on rail under warm bulb",
|
||||
"action": "writing lyric line in notebook",
|
||||
"camera": [
|
||||
"fullbody shot balcony edge",
|
||||
"closeup on pen and paper",
|
||||
"side shot past swaying laundry"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "hands lifted",
|
||||
"action": "dancing: shoulder rolls with slow side travel, wrists loose",
|
||||
"camera": [
|
||||
"fullbody shot city behind",
|
||||
"closeup on rolling shoulders",
|
||||
"back shot toward foggy rooftops"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "center balcony tile",
|
||||
"action": "dancing: foot slide-cross with quick head nod accents",
|
||||
"camera": [
|
||||
"fullbody shot top-down slight",
|
||||
"closeup on sliding sneakers on tiles",
|
||||
"side shot along rail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "headphones on",
|
||||
"action": "nodding in time, eyes closed",
|
||||
"camera": [
|
||||
"fullbody shot under balcony lamp",
|
||||
"closeup on serene face and beard",
|
||||
"back shot to dim streetlights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "sitting on chair",
|
||||
"action": "long breath into cold night air",
|
||||
"camera": [
|
||||
"fullbody shot with chair legs angled",
|
||||
"closeup on breath plume",
|
||||
"side shot from doorway"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 9,
|
||||
"season": "Autumn",
|
||||
"time": "Day",
|
||||
"location": "Neighborhood street football court, leaves on ground",
|
||||
"outfit": "navy tracksuit top, black adidas joggers, white adidas sneakers with turf dust, simple beanie",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "triangle with friends",
|
||||
"action": "passing football quickly between feet (together)",
|
||||
"camera": [
|
||||
"fullbody shot wide half-court",
|
||||
"closeup on ball taps and passes",
|
||||
"side shot through metal fence"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "center circle",
|
||||
"action": "dancing: soccer-shuffle — toe taps on ball with hip sway (together)",
|
||||
"camera": [
|
||||
"fullbody shot center circle",
|
||||
"closeup on rapid toe taps",
|
||||
"back shot with friends cheering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "near goalpost",
|
||||
"action": "dancing: step-over fake into spin and pose (solo flair)",
|
||||
"camera": [
|
||||
"fullbody shot near net",
|
||||
"closeup on foot feint over ball",
|
||||
"side shot across goal mesh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "leaning on post",
|
||||
"action": "chuckling at camera, breath visible",
|
||||
"camera": [
|
||||
"fullbody shot framed by net",
|
||||
"closeup on smile and breath",
|
||||
"back shot to autumn trees"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "group line on sideline",
|
||||
"action": "dancing: circle footwork — alternating shuffles in and out (together)",
|
||||
"camera": [
|
||||
"fullbody shot line routine",
|
||||
"closeup on synchronized steps",
|
||||
"side shot along chalk line"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 10,
|
||||
"season": "Autumn",
|
||||
"time": "Night",
|
||||
"location": "Rainy cobblestone street with neon reflections",
|
||||
"outfit": "black jeans, charcoal hoodie with hood up, water-resistant black shell jacket, white adidas sneakers wet with rain",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "mid-street",
|
||||
"action": "kicking puddle to splash arcs of neon water",
|
||||
"camera": [
|
||||
"fullbody shot centered on reflections",
|
||||
"closeup on splash around sneaker",
|
||||
"back shot with neon signs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "feet planted wide",
|
||||
"action": "dancing: chest pulse on beat with slow head roll, rain dripping off brim",
|
||||
"camera": [
|
||||
"fullbody shot silhouette in rain",
|
||||
"closeup on chest pulse through hoodie",
|
||||
"side shot with water streaks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "arms open",
|
||||
"action": "letting rain hit face, eyes closed",
|
||||
"camera": [
|
||||
"fullbody shot T-pose slight",
|
||||
"closeup on raindrops on beard",
|
||||
"back shot with street glow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "pivot foot ready",
|
||||
"action": "dancing: 360° rain spin with heel skid and jacket flare",
|
||||
"camera": [
|
||||
"fullbody shot tracking spin",
|
||||
"closeup on heel skid and spray",
|
||||
"side shot following arc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "hood low",
|
||||
"action": "staring into lens, breath steaming",
|
||||
"camera": [
|
||||
"fullbody shot still in rain",
|
||||
"closeup on intense eyes",
|
||||
"back shot with wet cobbles"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 11,
|
||||
"season": "Autumn",
|
||||
"time": "Morning",
|
||||
"location": "Zagreb Cathedral steps in pale fog",
|
||||
"outfit": "dark jeans, black crew tee, gray wool overcoat, white adidas sneakers, knit gloves",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting mid-steps",
|
||||
"action": "writing lyrics steadily",
|
||||
"camera": [
|
||||
"fullbody shot wide steps and spires",
|
||||
"closeup on pen strokes",
|
||||
"side shot with drifting fog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing arms open",
|
||||
"action": "exhaling long breath to sky",
|
||||
"camera": [
|
||||
"fullbody shot facing façade",
|
||||
"closeup on breath plume",
|
||||
"back shot to gothic towers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "cleared area on steps",
|
||||
"action": "dancing: step-tap pattern up two steps, back down, snap on beat",
|
||||
"camera": [
|
||||
"fullbody shot across steps",
|
||||
"closeup on step taps",
|
||||
"side shot along handrail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "headphones on",
|
||||
"action": "slow nod timing to kick and snare",
|
||||
"camera": [
|
||||
"fullbody shot centered on landing",
|
||||
"closeup on nod and beard",
|
||||
"back shot to open square"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "hands in coat pockets",
|
||||
"action": "looking up the tower silently",
|
||||
"camera": [
|
||||
"fullbody shot low angle",
|
||||
"closeup on upward gaze",
|
||||
"side shot with stone texture"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 12,
|
||||
"season": "Autumn",
|
||||
"time": "Night",
|
||||
"location": "Lantern-lit garden path with candle clusters and light ground fog",
|
||||
"outfit": "black adidas joggers, charcoal long-sleeve tee, midnight blue bomber, white adidas sneakers catching candle glints",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "walking along lantern path",
|
||||
"action": "lifting a lantern and holding it forward",
|
||||
"camera": [
|
||||
"fullbody shot through lantern aisle",
|
||||
"closeup on lantern glow on face",
|
||||
"back shot with lantern trail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "small clearing",
|
||||
"action": "dancing: lantern in left hand, slow side-glide with soft wrist circles",
|
||||
"camera": [
|
||||
"fullbody shot framed by candles",
|
||||
"closeup on circling wrist and flame",
|
||||
"side shot across floating fog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "at small garden table",
|
||||
"action": "resting chin on hands, dreamy stare",
|
||||
"camera": [
|
||||
"fullbody shot seated with lantern foreground",
|
||||
"closeup on gentle eyes",
|
||||
"back shot to candle clusters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "beneath hanging lights",
|
||||
"action": "dancing: slow turn with arm rise, ending in still pose under lights",
|
||||
"camera": [
|
||||
"fullbody shot low angle to lights",
|
||||
"closeup on raised palm",
|
||||
"side shot passing candle bokeh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "bare path",
|
||||
"action": "spinning lightly as jacket hem flows",
|
||||
"camera": [
|
||||
"fullbody shot tracking spin",
|
||||
"closeup on jacket swirl",
|
||||
"back shot retreating down path"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 13,
|
||||
"season": "Autumn",
|
||||
"time": "Evening",
|
||||
"location": "Warm recording studio with wooden panels, microphone on stand with pop filter, soft amber lamps",
|
||||
"outfit": "charcoal adidas joggers, black heavyweight t-shirt, dark zip hoodie open at chest, studio headphones, white adidas sneakers",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "standing at mic, one hand on headphones",
|
||||
"action": "singing through pop filter with eyes closed",
|
||||
"camera": [
|
||||
"fullbody shot booth and panels",
|
||||
"closeup on lips behind pop filter fabric",
|
||||
"side shot across mic arm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "one hand gripping mic stand",
|
||||
"action": "dancing: subtle knee bounce and torso sway while holding pitch",
|
||||
"camera": [
|
||||
"fullbody shot between panels",
|
||||
"closeup on torso sway and hoodie folds",
|
||||
"back shot from behind pop filter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "leaning slightly toward mic",
|
||||
"action": "soft smile between lines, breath visible",
|
||||
"camera": [
|
||||
"fullbody shot centered on stand",
|
||||
"closeup on smile and beard texture",
|
||||
"side shot with amber lamp flare"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "adjusting headphones",
|
||||
"action": "dancing: micro step-touch in place with shoulder ticks as chorus hits",
|
||||
"camera": [
|
||||
"fullbody shot framed by acoustic panels",
|
||||
"closeup on headphone cup and hand",
|
||||
"back shot over shoulder into booth glass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "stool behind mic",
|
||||
"action": "holding lyric sheet steady, one line delivered",
|
||||
"camera": [
|
||||
"fullbody shot seated by stand",
|
||||
"closeup on lyric sheet print",
|
||||
"side shot past pop filter ring"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sceneId": 14,
|
||||
"season": "Autumn",
|
||||
"time": "Day",
|
||||
"location": "Minimalist white studio booth, diffused panels, microphone with pop filter",
|
||||
"outfit": "light gray adidas joggers, crisp white t-shirt, soft white zip hoodie, clean white adidas sneakers, over-ear studio headphones",
|
||||
"cuts": [
|
||||
{
|
||||
"cutId": 1,
|
||||
"pose": "sitting on white stool at mic",
|
||||
"action": "singing gently into pop filter with steady breath",
|
||||
"camera": [
|
||||
"fullbody shot bright white booth",
|
||||
"closeup on mouth behind pop fabric",
|
||||
"side shot along mic arm and cable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 2,
|
||||
"pose": "standing, lyric sheet in left hand",
|
||||
"action": "dancing: soft sway with sheet hand marking the beat while delivering a phrase",
|
||||
"camera": [
|
||||
"fullbody shot against white wall",
|
||||
"closeup on sheet hand pulsing beat",
|
||||
"back shot to frosted panel glow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 3,
|
||||
"pose": "head slightly tilted",
|
||||
"action": "smiling at the take, exhale visible in cool booth",
|
||||
"camera": [
|
||||
"fullbody shot centered in booth",
|
||||
"closeup on gentle smile",
|
||||
"side shot with panel edge parallax"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 4,
|
||||
"pose": "hands lightly on headphones",
|
||||
"action": "dancing: tiny step-rock left-right, shoulders ticking to metronome",
|
||||
"camera": [
|
||||
"fullbody shot with mic foreground",
|
||||
"closeup on headphone cushions and fingers",
|
||||
"back shot over shoulder to pop filter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cutId": 5,
|
||||
"pose": "one hand on mic stand",
|
||||
"action": "holding final note clean through pop filter",
|
||||
"camera": [
|
||||
"fullbody shot with stand and cable",
|
||||
"closeup on pop filter mesh catching light",
|
||||
"side shot from booth door"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
src/musicspot_generator/v1/zagreb/song.mp3
Normal file
BIN
src/musicspot_generator/v1/zagreb/song.mp3
Normal file
Binary file not shown.
Reference in New Issue
Block a user