diff --git a/public/template-media/LogoMotion3D-16x9.mp4 b/public/template-media/LogoMotion3D-16x9.mp4 new file mode 100644 index 0000000..db52167 Binary files /dev/null and b/public/template-media/LogoMotion3D-16x9.mp4 differ diff --git a/public/template-media/LogoMotion3D-16x9.png b/public/template-media/LogoMotion3D-16x9.png new file mode 100644 index 0000000..55062b3 Binary files /dev/null and b/public/template-media/LogoMotion3D-16x9.png differ diff --git a/public/template-media/LogoMotion3D-1x1.mp4 b/public/template-media/LogoMotion3D-1x1.mp4 new file mode 100644 index 0000000..d57ae26 Binary files /dev/null and b/public/template-media/LogoMotion3D-1x1.mp4 differ diff --git a/public/template-media/LogoMotion3D-1x1.png b/public/template-media/LogoMotion3D-1x1.png new file mode 100644 index 0000000..f97aa68 Binary files /dev/null and b/public/template-media/LogoMotion3D-1x1.png differ diff --git a/public/template-media/LogoMotion3D-9x16.mp4 b/public/template-media/LogoMotion3D-9x16.mp4 new file mode 100644 index 0000000..e82b967 Binary files /dev/null and b/public/template-media/LogoMotion3D-9x16.mp4 differ diff --git a/public/template-media/LogoMotion3D-9x16.png b/public/template-media/LogoMotion3D-9x16.png new file mode 100644 index 0000000..ebe8349 Binary files /dev/null and b/public/template-media/LogoMotion3D-9x16.png differ diff --git a/public/template-media/LogoMotion3D.mp4 b/public/template-media/LogoMotion3D.mp4 new file mode 100644 index 0000000..db52167 Binary files /dev/null and b/public/template-media/LogoMotion3D.mp4 differ diff --git a/scripts/seed_remotion_templates.py b/scripts/seed_remotion_templates.py index d527db6..3de22e7 100644 --- a/scripts/seed_remotion_templates.py +++ b/scripts/seed_remotion_templates.py @@ -78,6 +78,8 @@ T = [ [("appName","نام اپلیکیشن","اپلیکیشن شما"),("tagline","شعار","تجربه‌ای روان، سریع و زیبا"),("cta","دکمه","همین حالا دانلود کنید")],("#3b82f6","#8b5cf6","#f4f5f7")), ("CharacterStory","fr-character-story","داستان شخصیتی (۱۳ صحنه)","روایت داستان شما در سیزده صحنهٔ متحرک با شخصیت؛ تصویرسازی مدرن و مینیمال، صحنه‌ها کاملاً قابل ویرایش و انعطاف‌پذیر",39, CS_TEXTS,("#cf8a76","#6f9d96","#ece4d6")), + ("LogoMotion3D","fr-logo-motion-3d","موشن لوگو سه‌بعدی","نمایش سینمایی و سه‌بعدی لوگو با کارت فلزی، پرتوهای نور، درخشش و افکت لنز؛ لوگو و متن قابل ویرایش",5, + [("brandText","نام برند","برند شما"),("tagline","شعار","شعار شما اینجا")],("#38bdf8","#818cf8","#0a0e1a")), ] # Optional Media (image) content elements per template — these surface in the @@ -85,17 +87,19 @@ T = [ MEDIA = { "GlitterReveal": [("logoUrl", "لوگو (تصویر دلخواه)")], "AppShowcase3D": [("screenUrl", "تصویر اپلیکیشن (اسکرین‌شات)")], + "LogoMotion3D": [("logoUrl", "لوگو (تصویر)")], } # Per-template text colour (default white for dark backgrounds; dark for light studios). TEXTCOLORS = { "AppShowcase3D": "#0f172a", "CharacterStory": "#2b3a55", + "LogoMotion3D": "#f8fafc", } # Templates that ship a distinct preview video PER aspect (so the detail page shows # the matching render, not the 16:9 cropped). Others reuse the single 16:9 preview. -PERASPECT_VIDEO = {"AppShowcase3D", "CharacterStory"} +PERASPECT_VIDEO = {"AppShowcase3D", "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. diff --git a/services/remotion/src/Root.tsx b/services/remotion/src/Root.tsx index d1203c9..66eabac 100644 --- a/services/remotion/src/Root.tsx +++ b/services/remotion/src/Root.tsx @@ -5,6 +5,7 @@ import { Three3DTest } from "./compositions/Three3DTest"; import { AssetSheet } from "./compositions/AssetSheet"; import { StoryScenes, STORY_SCENES_DURATION } from "./compositions/StoryScenes"; import { FlexStory, flexStorySchema, flexStoryDefaults, calcFlexStoryMetadata } from "./compositions/FlexStory"; +import { LogoMotion3D, logoMotion3DSchema, logoMotion3DDefaults } from "./compositions/LogoMotion3D"; import { CHARACTER_JOURNEY } from "./scenes/presets"; import { IlluminatedCircles, @@ -107,6 +108,21 @@ export const RemotionRoot: React.FC = () => { }} /> + {/* Tech/3D logo motion — quality-preview composition */} + {ASPECTS.map((a) => ( + + ))} + {/* 3D feasibility test */} (renders any SVG/PNG/data-URI). Static camera keeps the +// flat logo aligned to the card. +export const logoMotion3DSchema = z.object({ + logoUrl: z.string(), // uploaded logo (SVG/PNG/data-URI); "" → branded placeholder mark + brandText: z.string(), + tagline: z.string(), + ...colorSchema, +}); +type Props = z.infer; + +export const logoMotion3DDefaults: Props = { + logoUrl: "", + brandText: "فلت‌رندر", + tagline: "موشن، ساده و حرفه‌ای", + accentColor: "#38bdf8", + secondaryColor: "#818cf8", + backgroundColor: "#0a0e1a", + textColor: "#f8fafc", +}; + +const resolveSrc = (u: string) => (/^https?:\/\//.test(u) || u.startsWith("data:") ? u : staticFile(u)); + +const Rays: React.FC<{ frame: number; color: string; op: number }> = ({ frame, color, op }) => { + const n = 16; + const pulse = 1 + Math.sin(frame / 11) * 0.08; + return ( + + {Array.from({ length: n }).map((_, i) => ( + + + + + ))} + + ); +}; + +const Flare: React.FC<{ core: number; streak: number; accent: string }> = ({ core, streak, accent }) => ( + + + + + + +); + +const Card: React.FC<{ scale: number; accent: string }> = ({ scale, accent }) => ( + + + + + + +); + +export const LogoMotion3D: React.FC = (props) => { + const frame = useCurrentFrame(); + const { fps, width, height } = useVideoConfig(); + const L = useLayout(); + const accent = props.accentColor; + + const popIn = spring({ frame: frame - 6, fps, config: { damping: 11, stiffness: 130 } }); + const scale = interpolate(popIn, [0, 1], [0.2, 1]); + const raysOp = interpolate(frame, [4, 24], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); + const core = interpolate(frame, [8, 20, 40], [0, 1, 0.32], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); + const streak = interpolate(frame, [10, 22, 44], [0, 0.9, 0.18], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); + const brandOp = interpolate(frame, [30, 48], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); + const brandY = interpolate(popIn, [0, 1], [L.vmin(28), 0]); + const tagOp = interpolate(frame, [46, 64], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); + + // The 3D card (1.7 units) projects to ≈43% of the frame height — match the HTML + // logo to it so it sits exactly on the card. + const cardPx = height * 0.43; + + return ( + + + + + + + + + + + + + + {Array.from({ length: 14 }).map((_, i) => { + const x = (rand(i) - 0.5) * 9; + const y = (rand(i + 3) - 0.5) * 5 + Math.sin((frame + i * 20) / 36) * 0.2; + const z = -1 - rand(i + 6) * 1.6; + return ; + })} + + + + + + + {/* Logo on the card (centered, scales in with the card). Any format renders. */} + +
+ {props.logoUrl ? ( + + ) : ( +
+ )} +
+ + + {/* Brand + tagline below the card */} + +
+ {props.brandText} +
+
+ {props.tagline} +
+
+ + + + ); +};