Files
flatrender/scripts/seed_remotion_templates.py
T
soroush.asadi 1795bc855b
CI/CD / CI · Web (tsc) (push) Successful in 1m19s
CI/CD / Deploy · full stack (push) Failing after 12s
feat(remotion): premium 3D app-showcase template (AppShowcase3D)
- New @remotion/three template: titanium flagship phone (thin rim, glossy black
  glass, rounded-corner screen via ShapeGeometry, dynamic island, side buttons),
  light keynote studio (contact shadow + env reflections + DOF + soft bloom),
  film grain + entrance light-sweep. All 3 aspects re-flowed.
- Editable screenUrl (user app screenshot textured onto the screen via TextureLoader
  + delayRender), appName/tagline/cta, 4 colours (dark text on light bg).
- Add pick(wide,square,tall) helper to lib/aspect.ts (Tier-0 from the R&D).
- Seed: AppShowcase3D + per-template text colour; built with the flat-artist skill.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 21:28:49 +03:30

121 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# Generates SQL to seed the 10 branded Remotion templates into content.* so they
# appear on the site. Each template -> 1 container + 3 aspect projects, each with
# a scene, Persian text content-elements (bindable -> Remotion props) and shared
# colours (bindable -> colour props) + a per-scene colour-swatch SVG.
#
# Usage: python scripts/seed_remotion_templates.py | docker exec -i fr2-postgres psql -U postgres -d flatrender
import uuid
# Assets are served from the Next app's public/ folder (relative URLs), so this
# works regardless of MinIO/object-store availability.
MINIO = ""
NS = uuid.UUID("11111111-2222-3333-4444-555555555555")
def uid(s): return str(uuid.uuid5(NS, s))
def q(s): return "'" + str(s).replace("'", "''") + "'"
ASPECTS = [("16x9", 1920, 1080, "16:9"), ("1x1", 1080, 1080, "1:1"), ("9x16", 1080, 1920, "9:16")]
CTITLES = {"accentColor": "رنگ اصلی", "secondaryColor": "رنگ دوم", "backgroundColor": "پس‌زمینه", "textColor": "رنگ متن"}
# id, slug, name(fa), desc(fa), dur, [(textKey,title,value)], (accent,secondary,bg)
T = [
("LogoMotion","fr-logo-motion","موشن لوگو","نمایش حرفه‌ای لوگو و نام برند با درخشش و حرکت",5,
[("brandText","متن لوگو","فلت‌رندر"),("tagline","شعار","موشن، ساده و حرفه‌ای")],("#3ba7ff","#a855f7","#04060f")),
("Opener","fr-opener","تیتراژ آغازین","شروع سینمایی برای ویدیو با عنوان و زیرعنوان",5,
[("kicker","پیش‌متن","تقدیم می‌کند"),("title","عنوان","یک شروع تازه"),("subtitle","زیرعنوان","داستان شما از همین‌جا آغاز می‌شود")],("#22d3ee","#6366f1","#0a0a12")),
("InstaPromo","fr-insta-promo","تبلیغ پیج اینستاگرام","معرفی و تبلیغ صفحهٔ اینستاگرام با دعوت به فالو",5,
[("handle","آیدی پیج","@flatrender"),("headline","عنوان","پیج ما را دنبال کنید"),("subtext","توضیح","هر روز محتوای تازه و الهام‌بخش"),("cta","دکمه","فالو کنید")],("#fb7185","#f59e0b","#140a12")),
("YouTubeIntro","fr-youtube-intro","اینترو کانال یوتیوب","اینترو حرفه‌ای کانال یوتیوب با دکمهٔ سابسکرایب",5,
[("channelName","نام کانال","کانال فلت‌رندر"),("subtitle","زیرعنوان","آموزش، ترفند و انگیزه"),("cta","دکمه","سابسکرایب کنید")],("#ff4d4d","#a855f7","#0c0810")),
("Slideshow","fr-slideshow","اسلایدشو","نمایش پشت‌سرهم چند پیام یا ویژگی به‌صورت اسلاید",9,
[("title","عنوان","چرا فلت‌رندر؟"),("slide1","اسلاید ۱","ساخت ویدیو در چند دقیقه"),("slide2","اسلاید ۲","بدون نیاز به دانش فنی"),("slide3","اسلاید ۳","خروجی با کیفیت حرفه‌ای")],("#34d399","#3b82f6","#060b0a")),
("HappyBirthday","fr-happy-birthday","تولدت مبارک","کارت تبریک تولد با کاغذرنگی و نام شخص",6,
[("greeting","تبریک","تولدت مبارک"),("name","نام","سارا"),("message","پیام","بهترین‌ها را برایت آرزومندیم 🎉")],("#fb7185","#fde047","#140a18")),
("SalePromo","fr-sale-promo","فروش ویژه","بنر تبلیغاتی فروش و تخفیف با دعوت به خرید",5,
[("badge","نشان تخفیف","۵۰٪ تخفیف"),("headline","عنوان","فروش ویژهٔ پایان فصل"),("subtext","توضیح","فقط تا پایان همین هفته"),("cta","دکمه","همین حالا خرید کنید")],("#f59e0b","#fb7185","#120a08")),
("QuoteCard","fr-quote-card","کارت نقل‌قول","نمایش جملهٔ انگیزشی یا نقل‌قول با نام گوینده",6,
[("quote","نقل‌قول","موفقیت، مجموع تلاش‌های کوچکِ هر روز است."),("author","گوینده","فلت‌رندر")],("#22d3ee","#6366f1","#0a0a12")),
("EventInvite","fr-event-invite","دعوت‌نامهٔ رویداد","دعوت‌نامهٔ شیک برای رویداد با تاریخ و مکان",6,
[("kicker","پیش‌متن","دعوت‌نامه"),("eventTitle","عنوان رویداد","همایش سالانهٔ نوآوری"),("date","تاریخ","۱۵ مهر ۱۴۰۳"),("location","مکان","تهران، سالن همایش‌ها"),("cta","دکمه","ثبت‌نام کنید")],("#a855f7","#3ba7ff","#0a0814")),
("Countdown","fr-countdown","شمارش معکوس","شمارش معکوس هیجان‌انگیز برای شروع یک رویداد",8,
[("title","عنوان","شروع رویداد تا"),("startNumber","عدد شروع","5"),("goText","متن پایان","شروع!"),("subtitle","زیرعنوان","آماده‌اید؟")],("#3ba7ff","#22d3ee","#04060f")),
("GlitterReveal","fr-glitter-reveal","نمایش لوگو با غبار درخشان","نمایش جادویی لوگو با ذرات درخشان؛ لوگو و متن قابل ویرایش",6,
[("brandText","نام برند","فلت‌رندر"),("tagline","شعار","موشن، ساده و حرفه‌ای")],("#3ba7ff","#a855f7","#05040e")),
("NowruzGreeting","fr-nowruz","تبریک نوروز","صحنهٔ بهاری نوروز با شخصیت‌های متحرک؛ حاجی‌فیروز، ماهی قرمز و سبزه",8,
[("greeting","متن تبریک","نوروز مبارک"),("subtitle","زیرعنوان","سال نو پیروز و شادمان"),("message","پیام / سال","۱۴۰۶")],("#f5b942","#e23b3b","#1fb6b0")),
("Hero3D","fr-hero-3d","نمایش سه‌بعدی برند","نمایش حرفه‌ای و سه‌بعدی لوگو و برند با نورپردازی و جلوه‌های واقعی",6,
[("brandText","نام برند","فلت‌رندر"),("tagline","شعار","موشن، ساده و حرفه‌ای")],("#3ba7ff","#a855f7","#04060f")),
("Nowruz3D","fr-nowruz-3d","تبریک نوروز سه‌بعدی","صحنهٔ سه‌بعدی نوروز با حاجی‌فیروز، سفرهٔ هفت‌سین و نورپردازی سینمایی",7,
[("greeting","متن تبریک","نوروز مبارک"),("subtitle","زیرعنوان","سال نو پیروز و شادمان"),("message","پیام / سال","۱۴۰۶")],("#f5c542","#e23b3b","#1a1228")),
("Birthday3D","fr-birthday-3d","تولد سه‌بعدی","صحنهٔ سه‌بعدی تولد با کیک و شمع‌های روشن، بادکنک و کاغذرنگی",6,
[("greeting","تبریک","تولدت مبارک"),("name","نام","سارا"),("message","پیام","بهترین‌ها را برایت آرزومندیم 🎉")],("#fb7185","#a855f7","#1a1226")),
("Promo3D","fr-promo-3d","فروش ویژه سه‌بعدی","تبلیغ سه‌بعدی فروش و تخفیف با جعبه‌های هدیه و نورپردازی سینمایی",6,
[("badge","نشان تخفیف","۵۰٪ تخفیف"),("headline","عنوان","فروش ویژهٔ پایان فصل"),("subtext","توضیح","فقط تا پایان همین هفته"),("cta","دکمه","همین حالا خرید کنید")],("#f59e0b","#fb7185","#140e1f")),
("AppShowcase3D","fr-app-showcase","معرفی اپلیکیشن سه‌بعدی","نمایش سه‌بعدی و حرفه‌ای اپلیکیشن روی گوشی پرچم‌دار با نورپردازی استودیویی",6,
[("appName","نام اپلیکیشن","اپلیکیشن شما"),("tagline","شعار","تجربه‌ای روان، سریع و زیبا"),("cta","دکمه","همین حالا دانلود کنید")],("#3b82f6","#8b5cf6","#f4f5f7")),
]
# Optional Media (image) content elements per template — these surface in the
# studio as upload/replace fields. key = the Remotion prop the image binds to.
MEDIA = {
"GlitterReveal": [("logoUrl", "لوگو (تصویر دلخواه)")],
"AppShowcase3D": [("screenUrl", "تصویر اپلیکیشن (اسکرین‌شات)")],
}
# Per-template text colour (default white for dark backgrounds; dark for light studios).
TEXTCOLORS = {
"AppShowcase3D": "#0f172a",
}
def swatch_svg(colors):
rects = "".join(f'<rect x="{i*50}" y="0" width="50" height="40" fill="{c}"/>' for i, c in enumerate(colors))
return f'<svg xmlns="http://www.w3.org/2000/svg" width="200" height="40">{rects}</svg>'
def icon_svg(hex):
return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="{hex}"/></svg>'
out = []
out.append("BEGIN;")
slugs = ",".join(q(t[1]) for t in T)
out.append(f"DELETE FROM content.project_containers WHERE slug IN ({slugs});")
for idx, (tid, slug, name, desc, dur, texts, (accent, sec, bg)) in enumerate(T):
cid = uid("c-" + tid)
thumb16 = f"{MINIO}/template-media/{tid}-16x9.png"
preview = f"{MINIO}/template-media/{tid}.mp4"
txt = TEXTCOLORS.get(tid, "#ffffff")
colors = [("accentColor", accent), ("secondaryColor", sec), ("backgroundColor", bg), ("textColor", txt)]
out.append(
"INSERT INTO content.project_containers (id,tenant_id,slug,name,description,image,demo,full_demo,mini_demo,"
"is_published,is_premium,is_mockup,primary_mode,sort) VALUES ("
f"{q(cid)},NULL,{q(slug)},{q(name)},{q(desc)},{q(thumb16)},{q(preview)},{q(preview)},{q(preview)},"
f"TRUE,FALSE,FALSE,'FLEXIBLE',{idx});")
for (asp, w, h, aspstr) in ASPECTS:
pid = uid(f"p-{tid}-{asp}")
sid = uid(f"s-{tid}-{asp}")
thumb = f"{MINIO}/template-media/{tid}-{asp}.png"
out.append(
"INSERT INTO content.projects (id,container_id,name,image,full_demo,original_width,original_height,aspect,"
"project_duration_sec,free_fps,choose_mode,resolution,render_engine,render_remotion_comp,is_published,sort) VALUES ("
f"{q(pid)},{q(cid)},{q(aspstr)},{q(thumb)},{q(preview)},{w},{h},{q(aspstr)},"
f"{dur},30,'FLEXIBLE','FullHD','Remotion',{q(tid+'-'+asp)},TRUE,0);")
out.append(
"INSERT INTO content.scenes (id,project_id,key,title,scene_color_svg,default_duration_sec,sort) VALUES ("
f"{q(sid)},{q(pid)},'c1','صحنه ۱',{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 ("
f"{q(uid(f'ce-{tid}-{asp}-{k}'))},{q(sid)},{q(k)},{q(title)},'Text',{q(val)},{pos},1);")
for mpos, (k, title) in enumerate(MEDIA.get(tid, [])):
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(sid)},{q(k)},{q(title)},'Media','',{len(texts)+mpos},0);")
for si, (k, hexv) in enumerate(colors):
out.append(
"INSERT INTO content.shared_colors (id,project_id,element_key,title,icon,attr_value,default_color,sort) VALUES ("
f"{q(uid(f'sc-{tid}-{asp}-{k}'))},{q(pid)},{q(k)},{q(CTITLES[k])},{q(icon_svg(hexv))},'fill',{q(hexv)},{si});")
out.append("COMMIT;")
out.append("SELECT count(*) AS containers FROM content.project_containers WHERE slug LIKE 'fr-%';")
print("\n".join(out))