624 lines
16 KiB
TypeScript
624 lines
16 KiB
TypeScript
|
|
/** A layer definition without an `id` — fresh ids are assigned when the template is applied. */
|
|||
|
|
export interface SceneTemplateLayer {
|
|||
|
|
type: "text" | "image" | "video" | "shape" | "draw";
|
|||
|
|
name?: string;
|
|||
|
|
visible?: boolean;
|
|||
|
|
x: number;
|
|||
|
|
y: number;
|
|||
|
|
width: number;
|
|||
|
|
height: number;
|
|||
|
|
rotation: number;
|
|||
|
|
opacity: number;
|
|||
|
|
zIndex: number;
|
|||
|
|
props: Record<string, unknown>;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const SCENE_BROWSER_CATEGORIES = [
|
|||
|
|
{ id: "all", label: "All Scenes" },
|
|||
|
|
{ id: "characters", label: "Characters" },
|
|||
|
|
{ id: "business", label: "Business" },
|
|||
|
|
{ id: "technology", label: "Technology" },
|
|||
|
|
{ id: "nature", label: "Nature" },
|
|||
|
|
{ id: "abstract", label: "Abstract" },
|
|||
|
|
{ id: "sports", label: "Sports" },
|
|||
|
|
{ id: "food", label: "Food" },
|
|||
|
|
] as const;
|
|||
|
|
|
|||
|
|
export type SceneBrowserCategoryId =
|
|||
|
|
(typeof SCENE_BROWSER_CATEGORIES)[number]["id"];
|
|||
|
|
|
|||
|
|
export type SceneBrowserContentCategory = Exclude<
|
|||
|
|
SceneBrowserCategoryId,
|
|||
|
|
"all"
|
|||
|
|
>;
|
|||
|
|
|
|||
|
|
export type SceneBrowserMediaFilter = "all" | "video" | "photo";
|
|||
|
|
|
|||
|
|
export interface BrowserSceneItem {
|
|||
|
|
id: string;
|
|||
|
|
name: string;
|
|||
|
|
category: SceneBrowserContentCategory;
|
|||
|
|
mediaType: "video" | "photo";
|
|||
|
|
characterCount: number;
|
|||
|
|
durationLabel: string;
|
|||
|
|
gradientFrom: string;
|
|||
|
|
gradientTo: string;
|
|||
|
|
/** Pre-built layers that populate the scene when selected. */
|
|||
|
|
templateLayers: SceneTemplateLayer[];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Layout helpers — canvas is 1280 × 720
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
/** Two-column layout: solid colour left, image placeholder right. */
|
|||
|
|
function splitLayout(
|
|||
|
|
bg: string,
|
|||
|
|
titleColor = "#FFFFFF",
|
|||
|
|
subtitleColor = "#94a3b8"
|
|||
|
|
): SceneTemplateLayer[] {
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
type: "shape",
|
|||
|
|
x: 0,
|
|||
|
|
y: 0,
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 0,
|
|||
|
|
props: { shape: "rect", fill: bg, stroke: bg, strokeWidth: 0, cornerRadius: 0 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "image",
|
|||
|
|
x: 660,
|
|||
|
|
y: 60,
|
|||
|
|
width: 540,
|
|||
|
|
height: 600,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 1,
|
|||
|
|
props: { src: "", cornerRadius: 12 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 230,
|
|||
|
|
width: 530,
|
|||
|
|
height: 120,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 2,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Main Title",
|
|||
|
|
fontSize: 60,
|
|||
|
|
fill: titleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "left",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 380,
|
|||
|
|
width: 530,
|
|||
|
|
height: 80,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 3,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Subtitle Here",
|
|||
|
|
fontSize: 36,
|
|||
|
|
fill: subtitleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "left",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** Centred title + subtitle, no image placeholder. */
|
|||
|
|
function centeredLayout(
|
|||
|
|
bg: string,
|
|||
|
|
titleColor = "#FFFFFF",
|
|||
|
|
subtitleColor = "#94a3b8"
|
|||
|
|
): SceneTemplateLayer[] {
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
type: "shape",
|
|||
|
|
x: 0,
|
|||
|
|
y: 0,
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 0,
|
|||
|
|
props: { shape: "rect", fill: bg, stroke: bg, strokeWidth: 0, cornerRadius: 0 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 265,
|
|||
|
|
width: 1120,
|
|||
|
|
height: 135,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 1,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Main Title",
|
|||
|
|
fontSize: 72,
|
|||
|
|
fill: titleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "center",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 430,
|
|||
|
|
width: 1120,
|
|||
|
|
height: 80,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 2,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Subtitle Here",
|
|||
|
|
fontSize: 40,
|
|||
|
|
fill: subtitleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "center",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** Full-bleed image background with a dark overlay + centred text on top. */
|
|||
|
|
function overlayLayout(
|
|||
|
|
bg: string,
|
|||
|
|
titleColor = "#FFFFFF",
|
|||
|
|
subtitleColor = "#e2e8f0"
|
|||
|
|
): SceneTemplateLayer[] {
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
type: "shape",
|
|||
|
|
x: 0,
|
|||
|
|
y: 0,
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 0,
|
|||
|
|
props: { shape: "rect", fill: bg, stroke: bg, strokeWidth: 0, cornerRadius: 0 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "image",
|
|||
|
|
x: 0,
|
|||
|
|
y: 0,
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 1,
|
|||
|
|
props: { src: "", cornerRadius: 0 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "shape",
|
|||
|
|
x: 0,
|
|||
|
|
y: 0,
|
|||
|
|
width: 1280,
|
|||
|
|
height: 720,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 0.55,
|
|||
|
|
zIndex: 2,
|
|||
|
|
props: { shape: "rect", fill: "#000000", stroke: "#000000", strokeWidth: 0, cornerRadius: 0 },
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 265,
|
|||
|
|
width: 1120,
|
|||
|
|
height: 135,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 3,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Main Title",
|
|||
|
|
fontSize: 72,
|
|||
|
|
fill: titleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "center",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
type: "text",
|
|||
|
|
x: 80,
|
|||
|
|
y: 430,
|
|||
|
|
width: 1120,
|
|||
|
|
height: 80,
|
|||
|
|
rotation: 0,
|
|||
|
|
opacity: 1,
|
|||
|
|
zIndex: 4,
|
|||
|
|
props: {
|
|||
|
|
text: "Your Subtitle Here",
|
|||
|
|
fontSize: 40,
|
|||
|
|
fill: subtitleColor,
|
|||
|
|
fontFamily: "Inter, sans-serif",
|
|||
|
|
align: "center",
|
|||
|
|
letterSpacing: 0,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
animation: "none",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
// Scene catalog
|
|||
|
|
// ---------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
export const BROWSER_SCENES: BrowserSceneItem[] = [
|
|||
|
|
// ── Characters ────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "man-waving",
|
|||
|
|
name: "Man waving hello",
|
|||
|
|
category: "characters",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-sky-200",
|
|||
|
|
gradientTo: "to-blue-300",
|
|||
|
|
templateLayers: splitLayout("#0c1a3d"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "woman-presenting",
|
|||
|
|
name: "Woman presenting",
|
|||
|
|
category: "characters",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-violet-200",
|
|||
|
|
gradientTo: "to-purple-300",
|
|||
|
|
templateLayers: splitLayout("#1a0a2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "friendly-greeting",
|
|||
|
|
name: "Friendly office greeting",
|
|||
|
|
category: "characters",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 2,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-rose-200",
|
|||
|
|
gradientTo: "to-pink-300",
|
|||
|
|
templateLayers: splitLayout("#2d0a14"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "customer-support",
|
|||
|
|
name: "Customer support agent",
|
|||
|
|
category: "characters",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-cyan-200",
|
|||
|
|
gradientTo: "to-teal-300",
|
|||
|
|
templateLayers: splitLayout("#071a1a"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Business ──────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "team-meeting",
|
|||
|
|
name: "Team meeting",
|
|||
|
|
category: "business",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 4,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-blue-200",
|
|||
|
|
gradientTo: "to-indigo-300",
|
|||
|
|
templateLayers: splitLayout("#0a1a3d"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "handshake-deal",
|
|||
|
|
name: "Handshake closing deal",
|
|||
|
|
category: "business",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 2,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-slate-200",
|
|||
|
|
gradientTo: "to-gray-300",
|
|||
|
|
templateLayers: splitLayout("#0f172a"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "startup-pitch",
|
|||
|
|
name: "Startup pitch deck",
|
|||
|
|
category: "business",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-indigo-200",
|
|||
|
|
gradientTo: "to-violet-300",
|
|||
|
|
templateLayers: centeredLayout("#0f0f2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "office-collaboration",
|
|||
|
|
name: "Office collaboration",
|
|||
|
|
category: "business",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 3,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-blue-200",
|
|||
|
|
gradientTo: "to-sky-300",
|
|||
|
|
templateLayers: splitLayout("#0a1428"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Technology ────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "city-skyline",
|
|||
|
|
name: "City skyline",
|
|||
|
|
category: "technology",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-indigo-200",
|
|||
|
|
gradientTo: "to-blue-400",
|
|||
|
|
templateLayers: overlayLayout("#0a0f2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "tech-network",
|
|||
|
|
name: "Tech network",
|
|||
|
|
category: "technology",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-cyan-200",
|
|||
|
|
gradientTo: "to-indigo-300",
|
|||
|
|
templateLayers: centeredLayout("#071a1a"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "coding-desk",
|
|||
|
|
name: "Developer at desk",
|
|||
|
|
category: "technology",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-emerald-200",
|
|||
|
|
gradientTo: "to-teal-300",
|
|||
|
|
templateLayers: splitLayout("#071c14"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "data-visualization",
|
|||
|
|
name: "Data visualization",
|
|||
|
|
category: "technology",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-violet-200",
|
|||
|
|
gradientTo: "to-fuchsia-300",
|
|||
|
|
templateLayers: centeredLayout("#1a0a2e"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Nature ────────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "forest-path",
|
|||
|
|
name: "Forest morning path",
|
|||
|
|
category: "nature",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-green-200",
|
|||
|
|
gradientTo: "to-emerald-300",
|
|||
|
|
templateLayers: overlayLayout("#071c0f"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "ocean-sunset",
|
|||
|
|
name: "Ocean sunset",
|
|||
|
|
category: "nature",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-amber-200",
|
|||
|
|
gradientTo: "to-orange-300",
|
|||
|
|
templateLayers: overlayLayout("#1c0f07"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "mountain-aerial",
|
|||
|
|
name: "Mountain aerial",
|
|||
|
|
category: "nature",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-sky-200",
|
|||
|
|
gradientTo: "to-blue-300",
|
|||
|
|
templateLayers: overlayLayout("#0c1a2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "wildlife-meadow",
|
|||
|
|
name: "Wildlife meadow",
|
|||
|
|
category: "nature",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-lime-200",
|
|||
|
|
gradientTo: "to-green-300",
|
|||
|
|
templateLayers: overlayLayout("#0a1c07"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Abstract ──────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "abstract-waves",
|
|||
|
|
name: "Abstract waves",
|
|||
|
|
category: "abstract",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-fuchsia-200",
|
|||
|
|
gradientTo: "to-purple-300",
|
|||
|
|
templateLayers: centeredLayout("#1a0a2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "gradient-flow",
|
|||
|
|
name: "Gradient flow",
|
|||
|
|
category: "abstract",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-pink-200",
|
|||
|
|
gradientTo: "to-rose-300",
|
|||
|
|
templateLayers: centeredLayout("#1c0a14"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "geometric-shapes",
|
|||
|
|
name: "Geometric shapes",
|
|||
|
|
category: "abstract",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-indigo-200",
|
|||
|
|
gradientTo: "to-violet-300",
|
|||
|
|
templateLayers: centeredLayout("#0f0a2e"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "particle-burst",
|
|||
|
|
name: "Particle burst",
|
|||
|
|
category: "abstract",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-blue-200",
|
|||
|
|
gradientTo: "to-cyan-300",
|
|||
|
|
templateLayers: centeredLayout("#071628"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Sports ────────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "sports-celebration",
|
|||
|
|
name: "Sports celebration",
|
|||
|
|
category: "sports",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 3,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-orange-200",
|
|||
|
|
gradientTo: "to-red-300",
|
|||
|
|
templateLayers: splitLayout("#1c0f07"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "soccer-goal",
|
|||
|
|
name: "Soccer goal moment",
|
|||
|
|
category: "sports",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 2,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-green-200",
|
|||
|
|
gradientTo: "to-lime-300",
|
|||
|
|
templateLayers: splitLayout("#0a1c07"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "gym-workout",
|
|||
|
|
name: "Gym workout",
|
|||
|
|
category: "sports",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-amber-200",
|
|||
|
|
gradientTo: "to-yellow-300",
|
|||
|
|
templateLayers: splitLayout("#1c1007"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "running-track",
|
|||
|
|
name: "Running on track",
|
|||
|
|
category: "sports",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-sky-200",
|
|||
|
|
gradientTo: "to-indigo-300",
|
|||
|
|
templateLayers: splitLayout("#0a1428"),
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// ── Food ──────────────────────────────────────────────────────────────────
|
|||
|
|
{
|
|||
|
|
id: "food-preparation",
|
|||
|
|
name: "Food preparation",
|
|||
|
|
category: "food",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 1,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-amber-200",
|
|||
|
|
gradientTo: "to-orange-300",
|
|||
|
|
templateLayers: splitLayout("#1c0f07"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "restaurant-plating",
|
|||
|
|
name: "Restaurant plating",
|
|||
|
|
category: "food",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-rose-200",
|
|||
|
|
gradientTo: "to-red-300",
|
|||
|
|
templateLayers: overlayLayout("#1c0a0f"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "coffee-pour",
|
|||
|
|
name: "Coffee pour slow-mo",
|
|||
|
|
category: "food",
|
|||
|
|
mediaType: "video",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-yellow-200",
|
|||
|
|
gradientTo: "to-amber-300",
|
|||
|
|
templateLayers: overlayLayout("#0f0a07"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "fresh-ingredients",
|
|||
|
|
name: "Fresh ingredients",
|
|||
|
|
category: "food",
|
|||
|
|
mediaType: "photo",
|
|||
|
|
characterCount: 0,
|
|||
|
|
durationLabel: "3-10 sec.",
|
|||
|
|
gradientFrom: "from-lime-200",
|
|||
|
|
gradientTo: "to-green-300",
|
|||
|
|
templateLayers: overlayLayout("#0a1c07"),
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
export function filterBrowserScenes(
|
|||
|
|
scenes: BrowserSceneItem[],
|
|||
|
|
options: {
|
|||
|
|
categoryId: SceneBrowserCategoryId;
|
|||
|
|
mediaFilter: SceneBrowserMediaFilter;
|
|||
|
|
search: string;
|
|||
|
|
}
|
|||
|
|
): BrowserSceneItem[] {
|
|||
|
|
const query = options.search.trim().toLowerCase();
|
|||
|
|
|
|||
|
|
return scenes.filter((scene) => {
|
|||
|
|
if (options.categoryId !== "all" && scene.category !== options.categoryId) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
if (
|
|||
|
|
options.mediaFilter !== "all" &&
|
|||
|
|
scene.mediaType !== options.mediaFilter
|
|||
|
|
) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
if (query && !scene.name.toLowerCase().includes(query)) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
});
|
|||
|
|
}
|