fix: correct scene duration calculation and initial visibility

- outPoint is the duration, not absolute end time
- First scene starts with opacity:1 (visible immediately)
- Other scenes use tl.set for instant opacity changes
- Scene_04: 0.88s duration (was incorrectly 5s)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-03-24 22:13:04 -07:00
co-authored by Claude Opus 4.6
parent 61a18d294f
commit 4d816709eb
2 changed files with 29 additions and 27 deletions
@@ -319,26 +319,29 @@ def generate_html(data: dict) -> str:
scene_name = layer.get("name", "")
scene_comp = comp_by_name.get(scene_name)
scene_start = layer.get("inPoint", 0)
scene_dur = layer.get("outPoint", 0)
if scene_dur <= scene_start:
scene_dur = scene_start + 5
scene_duration = layer.get("outPoint", 0)
if scene_duration <= 0:
scene_duration = 5
scene_end = scene_start + scene_duration
scene_id = f"scene-{comp_idx}"
comp_idx += 1
initial_opacity = 1 if scene_start < 0.01 else 0
all_html.append(
f' <!-- ═══ {scene_name} ({scene_start:.1f}-{scene_dur:.1f}s) ═══ -->'
f' <!-- ═══ {scene_name} ({scene_start:.1f}-{scene_end:.1f}s) ═══ -->'
)
all_html.append(
f' <div id="{scene_id}" data-start="{round(scene_start, 4)}" '
f'data-duration="{round(scene_dur - scene_start, 4)}" data-track-index="{layer_idx}" '
f'data-duration="{round(scene_duration, 4)}" data-track-index="{layer_idx}" '
f'style="position:absolute;top:0;left:0;width:{root_w}px;height:{root_h}px;'
f'overflow:hidden;opacity:0;">'
f'overflow:hidden;opacity:{initial_opacity};">'
)
# Scene fade in/out
all_gsap.append(f' /* {scene_name} */')
all_gsap.append(f' tl.to("#{scene_id}", {{ opacity: 1, duration: 0.01 }}, {round(scene_start, 4)});')
all_gsap.append(f' /* {scene_name} ({scene_start:.1f}-{scene_end:.1f}s) */')
if initial_opacity == 0:
all_gsap.append(f' tl.set("#{scene_id}", {{ opacity: 1 }}, {round(scene_start, 4)});')
if scene_comp:
# Process scene layers
@@ -378,7 +381,7 @@ def generate_html(data: dict) -> str:
all_gsap.append(line)
# Scene fade out
fade_out_t = round(scene_dur - 0.3, 4)
fade_out_t = round(scene_end - 0.3, 4)
all_gsap.append(f' tl.to("#{scene_id}", {{ opacity: 0, duration: 0.3 }}, {fade_out_t});')
all_gsap.append("")
+17 -18
View File
@@ -22,8 +22,8 @@
<div id="root" data-composition-id="render"
data-width="1920" data-height="1080" data-duration="26.69">
<div id="c999-l0" data-start="0.0" data-duration="22.7895" data-track-index="0" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;background:#111111"></div>
<!-- ═══ Scene_04 (15.4-20.4s) ═══ -->
<div id="scene-0" data-start="15.4488" data-duration="5.0" data-track-index="1" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<!-- ═══ Scene_04 (15.4-16.3s) ═══ -->
<div id="scene-0" data-start="15.4488" data-duration="0.8842" data-track-index="1" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<div id="c1-l0" data-start="3.5369" data-duration="0.8842" data-track-index="0" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:0.5;transform:scale(-1.0,-1.0);border:2px solid #ffffff;background:transparent"></div>
<div id="c1-l1" data-start="3.5369" data-duration="0.8842" data-track-index="1" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:0.5;border:2px solid #ffffff;background:transparent"></div>
<div id="c1-l2" data-start="0.0" data-duration="0.8842" data-track-index="2" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;transform:scale(1.0,0.5);background:#111111"></div>
@@ -56,8 +56,8 @@
<div id="c1-l29" data-start="0.0" data-duration="1.0677" data-track-index="29" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;background:rgba(30,30,30,0.8)"><span style="font-family:monospace;font-size:14px;color:#555;position:absolute;bottom:8px;right:8px;">Photo/Video_08</span></div>
</div>
<!-- ═══ Scene_03 (8.6-13.6s) ═══ -->
<div id="scene-1" data-start="8.642" data-duration="5.0" data-track-index="2" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<!-- ═══ Scene_03 (8.6-12.8s) ═══ -->
<div id="scene-1" data-start="8.642" data-duration="4.1291" data-track-index="2" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<div id="c2-l0" data-start="0.0" data-duration="0.8967" data-track-index="0" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;transform:scale(1.0,0.5);background:#111111"></div>
<div id="c2-l1" data-start="5.372" data-duration="1.635" data-track-index="1" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:0.2;display:flex;align-items:center;justify-content:center"><span style="font-family:'Montserrat',sans-serif;font-weight:900;font-size:27px;color:#ffffff;text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;">dynamic</span></div>
<div id="c2-l2" data-start="0.0" data-duration="0.8967" data-track-index="2" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;transform:scale(1.0,0.5);background:#111111"></div>
@@ -83,8 +83,8 @@
<div id="c2-l22" data-start="0.0" data-duration="2.636" data-track-index="22" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;background:rgba(30,30,30,0.8)"><span style="font-family:monospace;font-size:14px;color:#555;position:absolute;bottom:8px;right:8px;">Photo/Video_05</span></div>
</div>
<!-- ═══ Scene_02 (5.9-10.9s) ═══ -->
<div id="scene-2" data-start="5.8725" data-duration="5.0" data-track-index="3" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<!-- ═══ Scene_02 (5.9-9.0s) ═══ -->
<div id="scene-2" data-start="5.8725" data-duration="3.1365" data-track-index="3" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<div id="c3-l0" data-start="0.0" data-duration="3.1365" data-track-index="0" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;background:rgba(30,30,30,0.8)"><span style="font-family:monospace;font-size:14px;color:#555;position:absolute;bottom:8px;right:8px;">Photo/Video_04</span></div>
<div id="c3-l1" data-start="0.9343" data-duration="1.2679" data-track-index="1" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:114px;transform-origin:0px 0px;opacity:1;display:flex;align-items:center;justify-content:center"><span style="font-family:'Montserrat',sans-serif;font-weight:900;font-size:36px;color:#ffffff;text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;">easy to use</span></div>
<div id="c3-l2" data-start="0.9343" data-duration="1.2679" data-track-index="2" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:114px;transform-origin:0px 0px;opacity:0.2;transform:scale(4.0,4.0);display:flex;align-items:center;justify-content:center"><span style="font-family:'Montserrat',sans-serif;font-weight:900;font-size:36px;color:#ffffff;text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;">easy to use</span></div>
@@ -96,7 +96,7 @@
</div>
<!-- ═══ Scene_01 (0.0-6.6s) ═══ -->
<div id="scene-3" data-start="0.0" data-duration="6.5732" data-track-index="4" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:0;">
<div id="scene-3" data-start="0.0" data-duration="6.5732" data-track-index="4" style="position:absolute;top:0;left:0;width:1920px;height:1080px;overflow:hidden;opacity:1;">
<div id="c4-l0" data-start="3.5369" data-duration="2.7027" data-track-index="0" style="position:absolute;left:0.0px;top:0.0px;width:1338px;height:133px;transform-origin:0px 0px;opacity:1;display:flex;align-items:center;justify-content:center"><span style="font-family:'Montserrat',sans-serif;font-weight:900;font-size:36px;color:#ffffff;text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;">clean design</span></div>
<div id="c4-l1" data-start="4.1041" data-duration="2.1355" data-track-index="1" style="position:absolute;left:-0.5px;top:0.0px;width:1920px;height:1080px;transform-origin:0.5px 0.0px;opacity:1;border:5px solid #ffcb00;background:transparent"></div>
<div id="c4-l2" data-start="3.6703" data-duration="0.5005" data-track-index="2" style="position:absolute;left:0.0px;top:0.0px;width:1920px;height:1080px;transform-origin:0px 0px;opacity:1;background:#ff3333"></div>
@@ -122,8 +122,8 @@
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
/* Scene_04 */
tl.to("#scene-0", { opacity: 1, duration: 0.01 }, 15.4488);
/* Scene_04 (15.4-16.3s) */
tl.set("#scene-0", { opacity: 1 }, 15.4488);
tl.set("#c1-l3", { scale: 1.0 }, 15.4488);
tl.to("#c1-l3", { scale: 0.76, duration: 2.636, ease: "power2.inOut" }, 15.4488);
tl.set("#c1-l5", { scale: 1.0 }, 15.4488);
@@ -140,10 +140,10 @@
tl.set("#c1-l22", { scale: 1.0 }, 15.7491);
tl.to("#c1-l22", { scale: 1.2, duration: 0.1001, ease: "none" }, 15.7491);
tl.to("#c1-l22", { scale: 0.9, duration: 0.367, ease: "none" }, 15.8492);
tl.to("#scene-0", { opacity: 0, duration: 0.3 }, 20.1488);
tl.to("#scene-0", { opacity: 0, duration: 0.3 }, 16.033);
/* Scene_03 */
tl.to("#scene-1", { opacity: 1, duration: 0.01 }, 8.642);
/* Scene_03 (8.6-12.8s) */
tl.set("#scene-1", { opacity: 1 }, 8.642);
tl.set("#c2-l14", { scale: 1.0 }, 8.8088);
tl.to("#c2-l14", { scale: 1.2, duration: 0.1669, ease: "none" }, 8.8088);
tl.to("#c2-l14", { scale: 1.0, duration: 0.1668, ease: "none" }, 8.9757);
@@ -172,10 +172,10 @@
tl.to("#c2-l22", { scale: 1.0, duration: 0.6673, ease: "power2.inOut" }, 8.642);
tl.set("#c2-l22", { opacity: 0.0 }, 8.642);
tl.to("#c2-l22", { opacity: 1.0, duration: 0.3337, ease: "power2.inOut" }, 8.642);
tl.to("#scene-1", { opacity: 0, duration: 0.3 }, 13.342);
tl.to("#scene-1", { opacity: 0, duration: 0.3 }, 12.4711);
/* Scene_02 */
tl.to("#scene-2", { opacity: 1, duration: 0.01 }, 5.8725);
/* Scene_02 (5.9-9.0s) */
tl.set("#scene-2", { opacity: 1 }, 5.8725);
tl.set("#c3-l0", { scale: 1.0 }, 8.3083);
tl.to("#c3-l0", { scale: 1.2, duration: 0.6673, ease: "power2.inOut" }, 8.3083);
tl.set("#c3-l1", { scale: 0.8 }, 5.8725);
@@ -185,10 +185,9 @@
tl.to("#c3-l1", { scale: 1.15, duration: 1.1011, ease: "power2.inOut" }, 6.9402);
tl.set("#c3-l5", { scale: 1.0 }, 8.3083);
tl.to("#c3-l5", { scale: 1.2, duration: 0.6673, ease: "power2.inOut" }, 8.3083);
tl.to("#scene-2", { opacity: 0, duration: 0.3 }, 10.5725);
tl.to("#scene-2", { opacity: 0, duration: 0.3 }, 8.709);
/* Scene_01 */
tl.to("#scene-3", { opacity: 1, duration: 0.01 }, 0.0);
/* Scene_01 (0.0-6.6s) */
tl.set("#c4-l0", { scale: 0.0 }, 0.0);
tl.to("#c4-l0", { scale: 1.0, duration: 0.6673, ease: "power2.inOut" }, 0.0);
tl.to("#c4-l0", { scale: 1.0, duration: 0.0334, ease: "power2.inOut" }, 0.6673);