{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"format":{"type":"string","const":"shortdrama.script.v1"},"drama":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"logline":{"description":"One sentence: protagonist + situation + structural conflict + stakes","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"format":{"type":"string","enum":["series","short_film","drama_ads","film_trailer","music_video"]},"genre":{"description":"The kind of story: a sub-genre key from get_catalog(\"genres\") (best: it carries the brief the story is written to), a genre key (leaves the kind open), a custom: preset, or the creator's own genre name with genre_description","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"genre_description":{"description":"For a genre of the creator's own: what it is (the brief the story is written to). Ignored for catalog genres","anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"subgenres":{"maxItems":5,"type":"array","items":{"type":"string","maxLength":80},"description":"Extra genre tags; genre alone decides the brief"},"tropes":{"maxItems":6,"type":"array","items":{"type":"string","maxLength":80},"description":"Keys from get_catalog(\"tropes\") or free text"},"language":{"type":"string","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$","description":"Dialogue language"},"target_audience":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"content_rating":{"anyOf":[{"type":"string","enum":["all_ages","7_plus","13_plus","16_plus"],"description":"Who the drama is for, by age, from get_catalog(\"content_ratings\"): the ceiling the story is written to and every image and video is generated within. Pick it from the genre and the audience: 16_plus (TV-14) is the vertical-drama standard for romance, revenge and thriller; 13_plus for teen and sweet stories; 7_plus or all_ages for children and family"},{"type":"null"}]},"aspect_ratio":{"type":"string","enum":["9:16","16:9","1:1","4:5"]},"episode_target_count":{"anyOf":[{"type":"integer","minimum":1,"maximum":200},{"type":"null"}]},"episode_target_seconds":{"anyOf":[{"type":"integer","minimum":15,"maximum":1800},{"type":"null"}]},"visual_style":{"anyOf":[{"anyOf":[{"type":"string","minLength":1,"maxLength":80,"description":"A key from get_catalog(\"visual_styles\"), official or custom:"},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"prompt_fragment":{"type":"string","minLength":1,"maxLength":1000,"description":"Added to every image/video prompt: lighting, lens, palette, texture"},"negative_fragment":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"required":["name","prompt_fragment"],"description":"A one-off style; save it with save_custom_preset to reuse it"}]},{"type":"null"}]},"default_models":{"type":"object","properties":{"image":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"video":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"music":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"video_resolution":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}]}},"description":"Models generation uses for this drama (ids from list_models) and the video resolution"}}},"bible":{"type":"object","properties":{"premise":{"anyOf":[{"type":"string","maxLength":3000},{"type":"null"}]},"structural_conflict":{"description":"Why the premise produces conflict in every scene by itself","anyOf":[{"type":"string","maxLength":1500},{"type":"null"}]},"theme":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"tone_refs":{"description":"The feel, with 2–3 reference titles","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"world":{"anyOf":[{"type":"string","maxLength":3000},{"type":"null"}]},"central_question":{"description":"The dramatic question of the whole season","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"engine_of_satisfaction":{"description":"Which injustice is planted and which payoff is promised","anyOf":[{"type":"string","maxLength":1500},{"type":"null"}]},"season_arc":{"anyOf":[{"maxItems":12,"type":"array","items":{"type":"object","properties":{"phase":{"type":"string","minLength":1,"maxLength":80},"episodes":{"type":"string","maxLength":20,"description":"e.g. \"1-10\""},"beats":{"type":"string","maxLength":2000}},"required":["phase","episodes","beats"]}},{"type":"null"}]},"irony_ledger":{"description":"What the audience knows that characters do not, and the episodes where each side learns it","anyOf":[{"maxItems":30,"type":"array","items":{"type":"object","properties":{"secret":{"type":"string","minLength":1,"maxLength":500},"audience_learns":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"characters_learn":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]}},"required":["secret"]}},{"type":"null"}]},"production_notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"relationships":{"description":"Who each character is to the others, and where loyalty is fragile","anyOf":[{"type":"string","maxLength":3000},{"type":"null"}]}}},"characters":{"maxItems":60,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"age":{"description":"e.g. \"28\", \"early 30s\"","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"gender":{"description":"e.g. \"female\", \"male\"","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"role":{"type":"string","enum":["protagonist","antagonist","love_interest","supporting","extra"]},"logline":{"description":"Who they are + the core conflict they carry","anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"story":{"description":"What drives them, one short labelled line each: Want (outer goal), Need (inner truth they must learn), Wound (past event), Flaw (the lie they believe), Stakes (what they lose), Contradiction, Empathy lever (how the audience is made to care at first sight), Arc (start → end)","anyOf":[{"type":"string","maxLength":3000},{"type":"null"}]},"voice_style":{"description":"How they speak","anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"appearance":{"description":"Canonical physical description reused for every image, 40–90 words, in this order: age and ethnicity or region; face (shape, eyes, brows, nose, lips, skin tone); hair (length, colour, texture, usual style); build and height; one or two distinctive marks that survive any shot (a mole, a scar, a grey streak, glasses). The body only: clothing goes in looks, mood and story elsewhere. Set it once: changing it later outdates every portrait and shot of the character","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"voice_key":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"looks":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"name":{"description":"e.g. \"office\", \"wedding dress\"; required for a new look","type":"string","minLength":1,"maxLength":80},"description":{"description":"What they wear and how they are styled in this look: outfit, colours, hair, makeup, accessories. Clothing lives here, never in appearance; scenes pick a look by name, and the same look keeps the same portrait","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"is_default":{"type":"boolean"}}}}},"required":["name"]}},"locations":{"default":[],"maxItems":100,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"description":"What it looks like: architecture, dressing, light","anyOf":[{"type":"string","maxLength":1500},{"type":"null"}]},"interior":{"type":"boolean"},"time_variants":{"maxItems":6,"type":"array","items":{"type":"string","maxLength":40},"description":"e.g. [\"day\", \"night\"]"}},"required":["name"]}},"props":{"default":[],"maxItems":100,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"significance":{"description":"Why it matters to the story","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"required":["name"]}},"episodes":{"default":[],"maxItems":200,"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":1,"maximum":500},"title":{"anyOf":[{"type":"string","maxLength":150},{"type":"null"}]},"summary":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"goal":{"description":"What conflict moves forward and which emotion is targeted","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"hook":{"description":"What grabs attention in the first 3 seconds","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"cliffhanger":{"description":"The question the episode ends on","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"connect_back":{"description":"How it pays off or escalates the previous episode's cliffhanger","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"beat_skeleton":{"maxItems":12,"type":"array","items":{"type":"object","properties":{"beat":{"type":"string","enum":["hook","friction","spike","button","other"]},"at_seconds":{"type":"number","minimum":0,"maximum":600}},"required":["beat","at_seconds"]}},"target_seconds":{"anyOf":[{"type":"integer","minimum":10,"maximum":1800},{"type":"null"}]},"overrides":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Episode-level overrides: visual_style, mood, models"},"is_paywall_gate":{"type":"boolean","description":"The last free episode; it carries the strongest cliffhanger"},"music_prompt":{"description":"Direction for the episode score, any language: genre and sound, instruments, mood, tempo/BPM, key, era. generate_music scores it scene by scene (cold open, tension, climax, cliffhanger sting); empty: a brief from the genre and visual style","anyOf":[{"type":"string","maxLength":1500},{"type":"null"}]},"music_volume":{"description":"The music's level in the render, 0–1 (null: the default, 0.5)","anyOf":[{"type":"number","minimum":0,"maximum":1},{"type":"null"}]},"music_cues":{"description":"The score's level per section, by scene id: 0 silent, 1 whisper, 2 soft, 3 build, 4 full; a scene left out gets its automatic level (get_episode_music shows them)","anyOf":[{"type":"object","propertyNames":{"type":"string","maxLength":64},"additionalProperties":{"type":"integer","minimum":0,"maximum":4}},{"type":"null"}]},"scenes":{"description":"When present, replaces the episode script","maxItems":40,"type":"array","items":{"type":"object","properties":{"beat":{"type":"string","enum":["hook","friction","spike","button","other"],"description":"hook (0–15s, grab within 3s) · friction · spike · button (last 5–10s, cut on the question)"},"heading":{"description":"INT./EXT. LOCATION — TIME","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"action":{"type":"string","minLength":1,"maxLength":2500,"description":"What we see: action, micro-expressions, reactions. Written for close-ups."},"camera":{"anyOf":[{"type":"object","properties":{"shot_size":{"description":"get_catalog(\"shot_sizes\"), e.g. \"mcu\"","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"angle":{"description":"get_catalog(\"camera_angles\")","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"move":{"description":"get_catalog(\"camera_moves\")","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"lens":{"description":"get_catalog(\"lenses\")","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"shots":{"description":"Cuts inside the scene, for models that render multi-shot clips","anyOf":[{"maxItems":6,"type":"array","items":{"type":"object","properties":{"shot_size":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"angle":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"move":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"description":{"type":"string","minLength":1,"maxLength":400},"seconds":{"anyOf":[{"type":"number","minimum":0.5,"maximum":30},{"type":"null"}]}},"required":["description"]}},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}]}}},{"type":"null"}]},"mood":{"description":"get_catalog(\"moods\") or free text","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"duration_seconds":{"description":"Seconds, 6–15: one scene is one clip. A moment that needs longer becomes two scenes.","anyOf":[{"type":"number","minimum":6,"maximum":15},{"type":"null"}]},"location":{"anyOf":[{"type":"string","minLength":1,"maxLength":120,"description":"An id, or the exact name"},{"type":"null"}]},"time_of_day":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"characters":{"maxItems":8,"type":"array","items":{"type":"object","properties":{"character":{"type":"string","minLength":1,"maxLength":120,"description":"An id, or the exact name"},"look":{"description":"A look id or name; omitted = the character's default look","anyOf":[{"type":"string","minLength":1,"maxLength":120,"description":"An id, or the exact name"},{"type":"null"}]},"role_in_scene":{"anyOf":[{"type":"string","maxLength":150},{"type":"null"}]},"position_hint":{"description":"Where they are in frame","anyOf":[{"type":"string","maxLength":150},{"type":"null"}]}},"required":["character"]}},"props":{"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":120,"description":"An id, or the exact name"}},"dialogue":{"maxItems":40,"type":"array","items":{"type":"object","properties":{"character":{"anyOf":[{"type":"string","minLength":1,"maxLength":120,"description":"An id, or the exact name"},{"type":"null"}],"description":"Who speaks; null for narration / voice-over"},"text":{"type":"string","minLength":1,"maxLength":600},"delivery":{"description":"How it is said: \"whispering, voice breaking\"","anyOf":[{"type":"string","maxLength":150},{"type":"null"}]},"lang":{"anyOf":[{"type":"string","pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$"},{"type":"null"}]}},"required":["character","text"]}},"continuity":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Continuity with the scene before when both play in the same place. match_previous (default true): the video takes a still of the previous clip as a reference for set, light and wardrobe, and cuts to a new camera setup. Set { match_previous: false } when time passes in the same place."},"director_notes":{"anyOf":[{"type":"string","maxLength":1500},{"type":"null"}]},"overrides":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"prompt_override":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Per-model prompt text, for experts; replaces the compiled prompt"},"key_visual":{"description":"How the key visual is made: direct (the default: no key visual, the video gets the portraits, plate and props and a free camera), frame (one opening keyframe), storyboard (a comic page of 4–6 panels the video plays as cuts), storyboard_3x3 (7–9 panels). Leave it out: every scene starts as direct, and a script written by an agent is always saved as direct. Set frame or a storyboard only with update_scene when the user asks for it on that scene.","anyOf":[{"type":"string","enum":["frame","storyboard","storyboard_3x3","direct"]},{"type":"null"}]}},"required":["action"]}}},"required":["number"],"additionalProperties":false}}},"required":["format"],"$id":"https://api.shortdrama.studio/v2/schemas/shortdrama.script.v1.json","title":"shortdrama.script.v1","description":"A whole short drama as one portable document: drama settings, story bible, characters (with looks), locations, props and episodes with their scene scripts. References between parts are by exact name. Read by import_script, written by export_script. Docs: https://shortdrama.studio/shortdrama-script-format"}