Testimonial reel
Square reel of customer quotes, one card per testimonial, pushed in one after another.
TestimonialReel, defaults
Installation
npx shadcn add https://www.reelcn.dev/r/testimonial-reel.jsonFiles land in src/reelcn/ with the items it builds on. Dependencies: zod.
Register the composition
<Composition
id="TestimonialReel"
component={TestimonialReel}
schema={testimonialReelSchema}
defaultProps={testimonialReelDefaults}
calculateMetadata={testimonialReelMetadata}
width={1080}
height={1080}
fps={30}
durationInFrames={1}
/>Render
npx remotion render TestimonialReel # 16:9
npx remotion render TestimonialReel --width=1080 --height=1920 # 9:16Props
PropTypeDescription
testimonials*{ quote: string; name: string; role: string; avatar?: string; }[]
theme"daylight" | "midnight" | "mono" | "ledger" | "afterglow" | "chromewave" | "neon" | "paper" | "sunset"Theme preset. Inherits the surrounding `ThemeProvider` when omitted.
brand{ accent?: string; logo?: string; font?: string; }
sfxbooleanPlays a soft whoosh as each scene starts.
musicstringBackground music file, looped under everything at 25% volume.
Built from
Use
- Social proof for a landing page or an ad
- Collecting launch-day reactions into one clip
Avoid
- One quote on its own. Use
quote-card
Make it with an agent
With the reelcn agent skill installed, ask for the video in plain words, such as "make a launch video for Relay with reelcn". The skill picks a template, sets its props, reviews a contact sheet and renders.
Guides
Components take their colors from a theme, their timing from motion props and their layout from the canvas.
Source
registry/items/testimonial-reel.tsx
/**
* @title Testimonial Reel
* @category templates
* @description Square reel of customer quotes, one card per testimonial, pushed in one after another.
* @duration data-driven
* @use Social proof for a landing page or an ad
* @use Collecting launch-day reactions into one clip
* @avoid One quote on its own. Use `quote-card`
* @tags testimonials, quotes, social proof, template
* @example
* <Composition
* id="TestimonialReel"
* component={TestimonialReel}
* schema={testimonialReelSchema}
* defaultProps={testimonialReelDefaults}
* calculateMetadata={testimonialReelMetadata}
* width={1080}
* height={1080}
* fps={30}
* durationInFrames={1}
* />
*/
import { z } from "zod";
import type { Scene, Story } from "./story";
import { Storyboard, templateMetadata, templateSchema, templateStory } from "./storyboard";
export const testimonialReelSchema = templateSchema.extend({
testimonials: z
.array(
z.object({
quote: z.string(),
name: z.string(),
role: z.string(),
/** Avatar image. Initials are drawn when omitted. */
avatar: z.string().optional(),
}),
)
.min(1),
});
export type TestimonialReelProps = z.infer<typeof testimonialReelSchema>;
export const testimonialReelDefaults: TestimonialReelProps = {
testimonials: [
{
quote: "We cut our launch video from two weeks to one afternoon.",
name: "Maya Chen",
role: "Head of product, Northwind",
},
{ quote: "Our changelog finally gets watched instead of skipped.", name: "Tomás Rivera", role: "Founder, Pace" },
{
quote: "The whole team edits the JSON. Nobody waits on a video editor.",
name: "Priya Nair",
role: "Design lead, Relay",
},
],
};
export function testimonialReelStory(props: TestimonialReelProps): Story {
return templateStory(
props,
props.testimonials.map(
(t): Scene => ({ type: "quote", quote: t.quote, name: t.name, role: t.role, avatar: t.avatar }),
),
"card-push",
);
}
export function TestimonialReel(props: TestimonialReelProps) {
return <Storyboard story={testimonialReelStory(props)} />;
}
export const testimonialReelMetadata = templateMetadata(testimonialReelStory);