feat(seed): per-scene loop video + thumbnail for every scene
Each scene now carries both a still (content.scenes.image) AND a short ~1.5s LOOP
video (content.scenes.demo), so the studio scene cards show a looping preview, not
a static swatch.
- LOOP_SCENES = {CharacterStory, LogoMotion3D}: their scenes get a dedicated
per-scene loop ({tid}-{asp}-c{n}-loop.mp4 / {tid}-{asp}-loop.mp4); other
templates fall back to their full preview MP4.
- Renders 42 loops: LogoMotion3D ×3 (frames 30–74) + CharacterStory 13 scenes ×3
aspects (frames (n-1)*90+20 … +64), each a 45-frame / 1.5s clip mid-scene.
- Seed sets image + snapshot_url + demo per scene; verified all 42 serve 200 and
the DB wires each scene to its own still + loop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,10 @@ TEXTCOLORS = {
|
||||
# the matching render, not the 16:9 cropped). Others reuse the single 16:9 preview.
|
||||
PERASPECT_VIDEO = {"AppShowcase3D", "CharacterStory", "LogoMotion3D"}
|
||||
|
||||
# Templates that ship a short ~1.5s LOOP video PER SCENE (scene.demo), so the studio
|
||||
# scene cards play a looping preview. Others fall back to the full preview MP4.
|
||||
LOOP_SCENES = {"CharacterStory", "LogoMotion3D"}
|
||||
|
||||
# Templates whose content is split across MANY scenes (key c1..cN), one editable
|
||||
# scene card per beat. value = scene count; texts are assigned 2-per-scene in order.
|
||||
MULTISCENE = {"CharacterStory": len(CS_BEATS)}
|
||||
@@ -143,18 +147,20 @@ for idx, (tid, slug, name, desc, dur, texts, (accent, sec, bg)) in enumerate(T):
|
||||
# one editable scene card per beat; 2 text fields (title+caption) each.
|
||||
for sc in range(1, nscenes + 1):
|
||||
skid = uid(f"s-{tid}-{asp}-{sc}")
|
||||
scimg = f"{MINIO}/template-media/{tid}-{asp}-c{sc}.png" # per-scene rendered still
|
||||
scimg = f"{MINIO}/template-media/{tid}-{asp}-c{sc}.png" # per-scene still
|
||||
scdemo = f"{MINIO}/template-media/{tid}-{asp}-c{sc}-loop.mp4" if tid in LOOP_SCENES else pvideo
|
||||
out.append(
|
||||
"INSERT INTO content.scenes (id,project_id,key,title,image,snapshot_url,scene_color_svg,default_duration_sec,sort) VALUES ("
|
||||
f"{q(skid)},{q(pid)},{q('c'+str(sc))},{q('صحنه '+str(sc))},{q(scimg)},{q(scimg)},{q(swatch_svg([accent,sec,bg,txt]))},{SCENE_SECONDS},{sc-1});")
|
||||
"INSERT INTO content.scenes (id,project_id,key,title,image,snapshot_url,demo,scene_color_svg,default_duration_sec,sort) VALUES ("
|
||||
f"{q(skid)},{q(pid)},{q('c'+str(sc))},{q('صحنه '+str(sc))},{q(scimg)},{q(scimg)},{q(scdemo)},{q(swatch_svg([accent,sec,bg,txt]))},{SCENE_SECONDS},{sc-1});")
|
||||
for pos, (k, title, val) in enumerate(texts[(sc - 1) * 2: sc * 2]):
|
||||
out.append(
|
||||
"INSERT INTO content.scene_content_elements (id,scene_id,key,title,type,default_value,position_in_container,direction_layer_value) VALUES ("
|
||||
f"{q(uid(f'ce-{tid}-{asp}-{k}'))},{q(skid)},{q(k)},{q(title)},'Text',{q(val)},{pos},1);")
|
||||
else:
|
||||
scdemo = f"{MINIO}/template-media/{tid}-{asp}-loop.mp4" if tid in LOOP_SCENES else pvideo
|
||||
out.append(
|
||||
"INSERT INTO content.scenes (id,project_id,key,title,image,snapshot_url,scene_color_svg,default_duration_sec,sort) VALUES ("
|
||||
f"{q(sid)},{q(pid)},'c1','صحنه ۱',{q(thumb)},{q(thumb)},{q(swatch_svg([accent,sec,bg,txt]))},{dur},0);")
|
||||
"INSERT INTO content.scenes (id,project_id,key,title,image,snapshot_url,demo,scene_color_svg,default_duration_sec,sort) VALUES ("
|
||||
f"{q(sid)},{q(pid)},'c1','صحنه ۱',{q(thumb)},{q(thumb)},{q(scdemo)},{q(swatch_svg([accent,sec,bg,txt]))},{dur},0);")
|
||||
for pos, (k, title, val) in enumerate(texts):
|
||||
out.append(
|
||||
"INSERT INTO content.scene_content_elements (id,scene_id,key,title,type,default_value,position_in_container,direction_layer_value) VALUES ("
|
||||
|
||||
Reference in New Issue
Block a user