feat(render+templates): Remotion engine, 16 branded templates (incl. 3D), seconds pricing, coming-soon
Render engine - Add Remotion (code-based) as a 2nd render engine alongside After Effects. node-agent dispatches on Job.Engine; RunRemotion maps bindings -> --props, renders native then ffmpeg-scales to the quality tier (aspect-preserving). - content.projects.render_engine + render_remotion_comp (migration 32); render-svc claim resolves engine and routes (skips .aep for Remotion). - Admin TemplatesAdmin gains an engine picker + Remotion composition id field. Template pack (services/remotion) - 16 branded, Persian (Vazirmatn), color- and text-editable templates, each in 3 aspects (16:9 / 1:1 / 9:16): LogoMotion, Opener, InstaPromo, YouTubeIntro, Slideshow, HappyBirthday, SalePromo, QuoteCard, EventInvite, Countdown, GlitterReveal (editable logo image), NowruzGreeting (animated characters), and 4 cinematic 3D templates via @remotion/three (Hero3D, Nowruz3D, Birthday3D, Promo3D) with reflections + bloom/DOF/vignette. - scripts/seed_remotion_templates.py seeds containers/projects/scenes/colors. Pricing - Rewrite /pricing to the seconds-based model (charge = length x resolution), data-driven from /v1/plans, Toman, broker checkout. Coming-soon - Persian experimental-build overlay on all pages (launch date + countdown). Fixes - middleware matcher bypasses all static asset paths; catalog mapping passes cover image + preview video so real thumbnails render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* Registry of FlatRender branded templates. Each entry is rendered into the
|
||||
* three supported aspects (16:9 / 1:1 / 9:16) by Root.tsx, producing composition
|
||||
* ids like "LogoMotion-16x9". Every template uses Persian text presets + the
|
||||
* shared colour props so the studio can offer one consistent edit experience.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { AnyZodObject } from "zod";
|
||||
import { BRAND } from "./lib/branding";
|
||||
|
||||
import { LogoMotion, logoMotionSchema } from "./compositions/LogoMotion";
|
||||
import { Opener, openerSchema } from "./compositions/Opener";
|
||||
import { InstaPromo, instaPromoSchema } from "./compositions/InstaPromo";
|
||||
import { YouTubeIntro, youTubeIntroSchema } from "./compositions/YouTubeIntro";
|
||||
import { Slideshow, slideshowSchema } from "./compositions/Slideshow";
|
||||
import { HappyBirthday, happyBirthdaySchema } from "./compositions/HappyBirthday";
|
||||
import { SalePromo, salePromoSchema } from "./compositions/SalePromo";
|
||||
import { QuoteCard, quoteCardSchema } from "./compositions/QuoteCard";
|
||||
import { EventInvite, eventInviteSchema } from "./compositions/EventInvite";
|
||||
import { Countdown, countdownSchema } from "./compositions/Countdown";
|
||||
import { GlitterReveal, glitterRevealSchema } from "./compositions/GlitterReveal";
|
||||
import { NowruzGreeting, nowruzGreetingSchema } from "./compositions/NowruzGreeting";
|
||||
import { Hero3D, hero3DSchema } from "./compositions/Hero3D";
|
||||
import { Nowruz3D, nowruz3DSchema } from "./compositions/Nowruz3D";
|
||||
import { Birthday3D, birthday3DSchema } from "./compositions/Birthday3D";
|
||||
import { Promo3D, promo3DSchema } from "./compositions/Promo3D";
|
||||
|
||||
export interface TemplateDef {
|
||||
/** Base id; the registered composition ids are `${id}-${aspect}`. */
|
||||
id: string;
|
||||
/** Persian display name (used when seeding the site catalog). */
|
||||
name: string;
|
||||
/** Short Persian description for the catalog. */
|
||||
description: string;
|
||||
component: React.FC<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
schema: AnyZodObject;
|
||||
durationSec: number;
|
||||
defaultProps: Record<string, unknown>;
|
||||
}
|
||||
|
||||
const c = (accent: string, secondary: string, bg: string) => ({
|
||||
accentColor: accent,
|
||||
secondaryColor: secondary,
|
||||
backgroundColor: bg,
|
||||
textColor: BRAND.white,
|
||||
});
|
||||
|
||||
export const TEMPLATES: TemplateDef[] = [
|
||||
{
|
||||
id: "LogoMotion",
|
||||
name: "موشن لوگو",
|
||||
description: "نمایش حرفهای لوگو و نام برند با درخشش و حرکت",
|
||||
component: LogoMotion,
|
||||
schema: logoMotionSchema,
|
||||
durationSec: 5,
|
||||
defaultProps: { brandText: "فلترندر", tagline: "موشن، ساده و حرفهای", ...c(BRAND.blue, BRAND.purple, "#04060f") },
|
||||
},
|
||||
{
|
||||
id: "Opener",
|
||||
name: "تیتراژ آغازین",
|
||||
description: "شروع سینمایی برای ویدیو با عنوان و زیرعنوان",
|
||||
component: Opener,
|
||||
schema: openerSchema,
|
||||
durationSec: 5,
|
||||
defaultProps: { kicker: "تقدیم میکند", title: "یک شروع تازه", subtitle: "داستان شما از همینجا آغاز میشود", ...c(BRAND.cyan, "#6366f1", "#0a0a12") },
|
||||
},
|
||||
{
|
||||
id: "InstaPromo",
|
||||
name: "تبلیغ پیج اینستاگرام",
|
||||
description: "معرفی و تبلیغ صفحهٔ اینستاگرام با دعوت به فالو",
|
||||
component: InstaPromo,
|
||||
schema: instaPromoSchema,
|
||||
durationSec: 5,
|
||||
defaultProps: { handle: "@flatrender", headline: "پیج ما را دنبال کنید", subtext: "هر روز محتوای تازه و الهامبخش", cta: "فالو کنید", ...c(BRAND.pink, BRAND.amber, "#140a12") },
|
||||
},
|
||||
{
|
||||
id: "YouTubeIntro",
|
||||
name: "اینترو کانال یوتیوب",
|
||||
description: "اینترو حرفهای کانال یوتیوب با دکمهٔ سابسکرایب",
|
||||
component: YouTubeIntro,
|
||||
schema: youTubeIntroSchema,
|
||||
durationSec: 5,
|
||||
defaultProps: { channelName: "کانال فلترندر", subtitle: "آموزش، ترفند و انگیزه", cta: "سابسکرایب کنید", ...c("#ff4d4d", BRAND.purple, "#0c0810") },
|
||||
},
|
||||
{
|
||||
id: "Slideshow",
|
||||
name: "اسلایدشو",
|
||||
description: "نمایش پشتسرهم چند پیام یا ویژگی بهصورت اسلاید",
|
||||
component: Slideshow,
|
||||
schema: slideshowSchema,
|
||||
durationSec: 9,
|
||||
defaultProps: { title: "چرا فلترندر؟", slide1: "ساخت ویدیو در چند دقیقه", slide2: "بدون نیاز به دانش فنی", slide3: "خروجی با کیفیت حرفهای", ...c(BRAND.green, "#3b82f6", "#060b0a") },
|
||||
},
|
||||
{
|
||||
id: "HappyBirthday",
|
||||
name: "تولدت مبارک",
|
||||
description: "کارت تبریک تولد با کاغذرنگی و نام شخص",
|
||||
component: HappyBirthday,
|
||||
schema: happyBirthdaySchema,
|
||||
durationSec: 6,
|
||||
defaultProps: { greeting: "تولدت مبارک", name: "سارا", message: "بهترینها را برایت آرزومندیم 🎉", ...c(BRAND.pink, "#fde047", "#140a18") },
|
||||
},
|
||||
{
|
||||
id: "SalePromo",
|
||||
name: "فروش ویژه",
|
||||
description: "بنر تبلیغاتی فروش و تخفیف با دعوت به خرید",
|
||||
component: SalePromo,
|
||||
schema: salePromoSchema,
|
||||
durationSec: 5,
|
||||
defaultProps: { badge: "۵۰٪ تخفیف", headline: "فروش ویژهٔ پایان فصل", subtext: "فقط تا پایان همین هفته", cta: "همین حالا خرید کنید", ...c(BRAND.amber, BRAND.pink, "#120a08") },
|
||||
},
|
||||
{
|
||||
id: "QuoteCard",
|
||||
name: "کارت نقلقول",
|
||||
description: "نمایش جملهٔ انگیزشی یا نقلقول با نام گوینده",
|
||||
component: QuoteCard,
|
||||
schema: quoteCardSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: { quote: "موفقیت، مجموع تلاشهای کوچکِ هر روز است.", author: "فلترندر", ...c(BRAND.cyan, "#6366f1", "#0a0a12") },
|
||||
},
|
||||
{
|
||||
id: "EventInvite",
|
||||
name: "دعوتنامهٔ رویداد",
|
||||
description: "دعوتنامهٔ شیک برای رویداد با تاریخ و مکان",
|
||||
component: EventInvite,
|
||||
schema: eventInviteSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: { kicker: "دعوتنامه", eventTitle: "همایش سالانهٔ نوآوری", date: "۱۵ مهر ۱۴۰۳", location: "تهران، سالن همایشها", cta: "ثبتنام کنید", ...c(BRAND.purple, BRAND.blue, "#0a0814") },
|
||||
},
|
||||
{
|
||||
id: "Countdown",
|
||||
name: "شمارش معکوس",
|
||||
description: "شمارش معکوس هیجانانگیز برای شروع یک رویداد",
|
||||
component: Countdown,
|
||||
schema: countdownSchema,
|
||||
durationSec: 8,
|
||||
defaultProps: { title: "شروع رویداد تا", startNumber: 5, goText: "شروع!", subtitle: "آمادهاید؟", ...c(BRAND.blue, BRAND.cyan, "#04060f") },
|
||||
},
|
||||
{
|
||||
id: "GlitterReveal",
|
||||
name: "نمایش لوگو با غبار درخشان",
|
||||
description: "نمایش جادویی لوگو با ذرات درخشان؛ لوگو و متن قابل ویرایش",
|
||||
component: GlitterReveal,
|
||||
schema: glitterRevealSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: { brandText: "فلترندر", tagline: "موشن، ساده و حرفهای", logoUrl: "", ...c(BRAND.blue, BRAND.purple, "#05040e") },
|
||||
},
|
||||
{
|
||||
id: "NowruzGreeting",
|
||||
name: "تبریک نوروز",
|
||||
description: "صحنهٔ بهاری نوروز با شخصیتهای متحرک؛ حاجیفیروز، ماهی قرمز و سبزه",
|
||||
component: NowruzGreeting,
|
||||
schema: nowruzGreetingSchema,
|
||||
durationSec: 7.5,
|
||||
defaultProps: {
|
||||
greeting: "نوروز مبارک",
|
||||
subtitle: "سال نو پیروز و شادمان",
|
||||
message: "۱۴۰۶",
|
||||
accentColor: "#f5b942",
|
||||
secondaryColor: "#e23b3b",
|
||||
backgroundColor: "#1fb6b0",
|
||||
textColor: "#fdf6e3",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Hero3D",
|
||||
name: "نمایش سهبعدی برند",
|
||||
description: "نمایش حرفهای و سهبعدی لوگو و برند با نورپردازی و جلوههای واقعی",
|
||||
component: Hero3D,
|
||||
schema: hero3DSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: { brandText: "فلترندر", tagline: "موشن، ساده و حرفهای", ...c(BRAND.blue, BRAND.purple, "#04060f") },
|
||||
},
|
||||
{
|
||||
id: "Nowruz3D",
|
||||
name: "تبریک نوروز سهبعدی",
|
||||
description: "صحنهٔ سهبعدی نوروز با حاجیفیروز، سفرهٔ هفتسین و نورپردازی سینمایی",
|
||||
component: Nowruz3D,
|
||||
schema: nowruz3DSchema,
|
||||
durationSec: 7,
|
||||
defaultProps: {
|
||||
greeting: "نوروز مبارک",
|
||||
subtitle: "سال نو پیروز و شادمان",
|
||||
message: "۱۴۰۶",
|
||||
accentColor: "#f5c542",
|
||||
secondaryColor: "#e23b3b",
|
||||
backgroundColor: "#1a1228",
|
||||
textColor: "#fdf6e3",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Birthday3D",
|
||||
name: "تولد سهبعدی",
|
||||
description: "صحنهٔ سهبعدی تولد با کیک و شمعهای روشن، بادکنک و کاغذرنگی",
|
||||
component: Birthday3D,
|
||||
schema: birthday3DSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: {
|
||||
greeting: "تولدت مبارک",
|
||||
name: "سارا",
|
||||
message: "بهترینها را برایت آرزومندیم 🎉",
|
||||
accentColor: "#fb7185",
|
||||
secondaryColor: "#a855f7",
|
||||
backgroundColor: "#1a1226",
|
||||
textColor: "#fdf6e3",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Promo3D",
|
||||
name: "فروش ویژه سهبعدی",
|
||||
description: "تبلیغ سهبعدی فروش و تخفیف با جعبههای هدیه و نورپردازی سینمایی",
|
||||
component: Promo3D,
|
||||
schema: promo3DSchema,
|
||||
durationSec: 6,
|
||||
defaultProps: {
|
||||
badge: "۵۰٪ تخفیف",
|
||||
headline: "فروش ویژهٔ پایان فصل",
|
||||
subtext: "فقط تا پایان همین هفته",
|
||||
cta: "همین حالا خرید کنید",
|
||||
accentColor: "#f59e0b",
|
||||
secondaryColor: "#fb7185",
|
||||
backgroundColor: "#140e1f",
|
||||
textColor: "#ffffff",
|
||||
},
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user