From 7f26c406c7e683cf8ddf067c626433b97aa6422d Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Mon, 21 Sep 2026 16:21:35 -0700 Subject: [PATCH] Match scene length to narration and write fuller narration lines --- app.py | 9 +++++++-- static/index.html | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 0ff8e89..1a62af6 100644 --- a/app.py +++ b/app.py @@ -79,6 +79,7 @@ GLOBAL_DEFAULTS = { "aspect_ratio": "9:16", "target_seconds": 60, "clip_seconds": 8, + "scene_timing": "narration", "error_cooldown_minutes": 5, "work_hours_enabled": False, "work_days": "mon,tue,wed,thu,fri,sat,sun", @@ -998,7 +999,7 @@ Every character is a cartoon: a cartoon animal, a cartoon creature, or a simple The Short has exactly {n} scenes of {clip} seconds each. Each scene has: "visual": a detailed, self-contained shot description of one still image (setting, action, mood, lighting). Name the characters but do not re-describe their appearance, that comes from "characters". Never mention on-screen text or words. -"narration": one spoken line of at most {words} words. +"narration": one spoken line of {max(4, words - 5)} to {words} words, so it fills most of the scene. Scene 1 must hook the viewer in the first 2 seconds. The final scene must deliver a payoff. @@ -1494,7 +1495,11 @@ def media_duration(path): def render_scene(s, image, audio, out, aspect): w, h = (1080, 1920) if aspect == "9:16" else (1920, 1080) - dur = max(float(s["clip_seconds"]), media_duration(audio) + 0.6) + spoken = media_duration(audio) + if s.get("scene_timing", "narration") == "fixed": + dur = max(float(s["clip_seconds"]), spoken + 0.6) + else: + dur = max(2.5, spoken + 0.8) frames = int(dur * 30) vf = ( f"[0:v]scale={w * 2}:{h * 2}:force_original_aspect_ratio=increase,crop={w * 2}:{h * 2}," diff --git a/static/index.html b/static/index.html index 650f4c2..a92e08d 100644 --- a/static/index.html +++ b/static/index.html @@ -326,7 +326,8 @@ const FIELDS=[ ["ollama_timeout","Ollama timeout (seconds)","select:120|300|600|900","Max wait per Ollama request before retrying","g"], ["aspect_ratio","Aspect ratio","select:9:16|16:9","","g"], ["target_seconds","Target length (seconds)","select:30|45|60|90|120|180","Split into scenes of the length below","g"], -["clip_seconds","Seconds per scene","select:5|6|8|10|12","8 gives 7 scenes in a 60 second Short","g"], +["clip_seconds","Seconds per scene","select:5|6|8|10|12","Sets how many scenes the story has and how long each narration line is. 8 gives 7 scenes","g"], +["scene_timing","Scene timing","select:narration=Match the narration|fixed=Fixed length per scene","Match the narration moves to the next scene shortly after the voice finishes","g"], ["error_cooldown_minutes","Wait after error (minutes)","select:1|5|10|15|30|60","","g"] ]; const DAYS=[["mon","Mon"],["tue","Tue"],["wed","Wed"],["thu","Thu"],["fri","Fri"],["sat","Sat"],["sun","Sun"]];