Templates
Templates
Product Launch
Launch video for a product: name and tagline, feature cards, screenshots in a browser window, and a call to action.
Install
Usage
<Composition
id="ProductLaunch"
component={ProductLaunch}
schema={productLaunchSchema}
defaultProps={productLaunchDefaults}
calculateMetadata={productLaunchMetadata}
width={1920}
height={1080}
fps={30}
durationInFrames={1}
/>Props
| Name | Type | Default | Description |
|---|---|---|---|
name | string | — | |
tagline | string | — | |
features | { title: string; body?: string; }[] | — | |
screenshots | string[] | — | Screenshot or screen-recording URLs, one browser scene each. A placeholder screen stands in when empty. |
cta | string | — | |
theme? | "midnight" | "daylight" | "paper" | "neon" | "mono" | "sunset" | — | Theme preset. Inherits the surrounding `ThemeProvider` when omitted. |
brand? | { accent?: string; logo?: string; font?: string; } | — | |
sfx? | boolean | — | Plays a soft whoosh as each scene starts. |
music? | string | — | Background music file, looped under everything at 25% volume. |
url? | string | — |
Use
- Announcing a new product or a major version
- A hero video for a landing page
Avoid
- One feature in a vertical short — use
feature-short
Dependencies
zod
Source
registry/items/product-launch.tsx
/**
* @title Product Launch
* @category templates
* @description Launch video for a product: name and tagline, feature cards, screenshots in a browser window, and a call to action.
* @duration data-driven
* @use Announcing a new product or a major version
* @use A hero video for a landing page
* @avoid One feature in a vertical short — use `feature-short`
* @tags launch, product, saas, announcement, template
* @example
* <Composition
* id="ProductLaunch"
* component={ProductLaunch}
* schema={productLaunchSchema}
* defaultProps={productLaunchDefaults}
* calculateMetadata={productLaunchMetadata}
* width={1920}
* height={1080}
* fps={30}
* durationInFrames={1}
* />
*/
import { z } from "zod";
import type { Scene, Story } from "./story";
import { chunk, Storyboard, templateMetadata, templateSchema, templateStory } from "./storyboard";
export const productLaunchSchema = templateSchema.extend({
name: z.string(),
tagline: z.string(),
features: z.array(z.object({ title: z.string(), body: z.string().optional() })),
/** Screenshot or screen-recording URLs, one browser scene each. A placeholder screen stands in when empty. */
screenshots: z.array(z.string()),
cta: z.string(),
url: z.string().optional(),
});
export type ProductLaunchProps = z.infer<typeof productLaunchSchema>;
export const productLaunchDefaults: ProductLaunchProps = {
name: "Relay",
tagline: "Release notes your users actually read",
features: [
{ title: "Write once", body: "Draft in Markdown and publish everywhere." },
{ title: "Ship on merge", body: "Every merged pull request becomes a line." },
{ title: "See who read it", body: "Opens and clicks for every release." },
],
screenshots: [],
cta: "Start free today",
url: "relay.example.com",
};
export function productLaunchStory(props: ProductLaunchProps): Story {
const { name, tagline, features, screenshots, cta, url } = props;
const logo: Scene[] = props.brand?.logo ? [{ type: "logo", text: name }] : [];
const screens: (string | undefined)[] = screenshots.length > 0 ? screenshots : [undefined];
return templateStory(props, [
...logo,
{ type: "title", kicker: "Introducing", title: name, subtitle: tagline, background: "gradient-mesh" },
...chunk(features, 3).map(
(group): Scene => ({
type: "bullets",
items: group.map((feature) => ({ text: feature.title, detail: feature.body })),
}),
),
...screens.map((src): Scene => ({ type: "device", device: "browser", src, url })),
{ type: "cta", title: cta, url, background: "spotlight" },
]);
}
export function ProductLaunch(props: ProductLaunchProps) {
return <Storyboard story={productLaunchStory(props)} />;
}
export const productLaunchMetadata = templateMetadata(productLaunchStory);