
Create Remotion Geist
- 431 installs
- 22 repo stars
- Updated January 29, 2026
- vercel-labs/skill-remotion-geist
Create Remotion videos using the Geist design system aesthetic.
About
Create Remotion videos using the Geist design system aesthetic. Use when asked to create videos, animations, or motion graphics that should follow Vercel's visual style - dark theme, spring animations, Geist typography, and the Geist color palette. Create Remotion videos styled with Vercel's Geist design system - dark backgrounds, spring animations, Geist fonts, and the 10-step color scale.
- # Create Remotion Geist Video
- Create Remotion videos styled with Vercel's Geist design system - dark backgrounds, spring animations, Geist fonts, and
- Creating any Remotion video that should look like Vercel
- Building motion graphics with Geist's dark theme aesthetic
- Making animated content using Geist typography and colors
Create Remotion Geist by the numbers
- 431 all-time installs (skills.sh)
- +6 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #798 of 1,881 Marketing & SEO skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 27, 2026 (Skillselion catalog sync)
create-remotion-geist capabilities & compatibility
- Capabilities
- # create remotion geist video · create remotion videos styled with vercel's geis · creating any remotion video that should look lik · building motion graphics with geist's dark theme
- Use cases
- documentation
What create-remotion-geist says it does
Create Remotion videos using the Geist design system aesthetic. Use when asked to create videos, animations, or motion graphics that should follow Vercel's visual style - dark theme, spring animations
npx skills add https://github.com/vercel-labs/skill-remotion-geist --skill create-remotion-geistAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 431 |
|---|---|
| repo stars | ★ 22 |
| Security audit | 3 / 3 scanners passed |
| Last updated | January 29, 2026 |
| Repository | vercel-labs/skill-remotion-geist ↗ |
How do I apply create-remotion-geist using the workflow in its SKILL.md?
Create Remotion videos using the Geist design system aesthetic. Use when asked to create videos, animations, or motion graphics that should follow Vercel's visual style - dark theme, spri...
Who is it for?
Developers following the create-remotion-geist skill for the tasks it documents.
Skip if: Tasks outside the create-remotion-geist scope described in SKILL.md.
When should I use this skill?
User mentions create-remotion-geist or related triggers from the skill description.
What you get
Working create-remotion-geist setup aligned with the documented patterns and constraints.
- Remotion Geist project scaffold
- CodeBlock component
- Rendered MP4 video
By the numbers
- Includes 8 reference guides in the references directory
- Documents a Geist 10-step dark color scale for Remotion scenes
- Lists 11 supported prism highlight languages
Files
Create Remotion Geist Video
Create Remotion videos styled with Vercel's Geist design system - dark backgrounds, spring animations, Geist fonts, and the 10-step color scale.
When to Use
- Creating any Remotion video that should look like Vercel
- Building motion graphics with Geist's dark theme aesthetic
- Making animated content using Geist typography and colors
- Producing videos that need the polished Vercel visual style
Critical Rules
1. NEVER use emojis - Use proper Geist icons from @geist-ui/icons package 2. Use official brand assets - Download from official sources, don't hand-craft SVGs 3. Entry point must be .tsx - Use src/index.tsx with registerRoot(), not .ts 4. Use prism-react-renderer for code - Do NOT use regex-based syntax highlighting
Quick Start
1. Scaffold the project:
mkdir -p src/{scenes,components,utils} out
npm init -y
npm install remotion @remotion/cli @remotion/tailwind react react-dom
npm install -D tailwindcss typescript @types/react
npm install @geist-ui/icons # For proper icons2. Create core files (see references/project-setup.md for templates):
remotion.config.ts- Enable Tailwindtailwind.config.js- Geist colors and fontssrc/styles.css- Font loading from CDNsrc/index.tsx- Root composition withregisterRoot()src/Root.tsx- Composition definitionssrc/utils/animations.ts- Spring animations
3. Build scenes following the pattern in references/scene-patterns.md
4. Render:
npx remotion studio # Preview at localhost:3000
npx remotion render MyComp out/video.mp4Geist Design Tokens (Quick Reference)
Colors (Dark Theme)
| Token | CSS Variable | Value | Usage |
|---|---|---|---|
| background-100 | --ds-background-100 | #0a0a0a | Primary background |
| background-200 | --ds-background-200 | #171717 | Secondary/elevated |
| gray-400 | --ds-gray-400 | #737373 | Default borders |
| green-700 | --ds-green-700 | #46A758 | Success |
| red-700 | --ds-red-700 | #E5484D | Error |
| amber-700 | --ds-amber-700 | #FFB224 | Warning |
| blue-700 | --ds-blue-700 | #0070F3 | Info/accent |
Typography Classes
- Headings:
text-heading-{72|64|56|48|40|32|24|20|16|14}(semibold, tight tracking) - Labels:
text-label-{20|18|16|14|13|12}[-mono](normal weight) - Copy:
text-copy-{24|20|18|16|14|13}[-mono](normal weight)
Spacing (4px base)
space-2: 8px |space-4: 16px |space-6: 24px |space-8: 32px
Animation Utilities
Use spring-based animations for Geist's smooth aesthetic:
import { spring, interpolate } from 'remotion';
// Fade in with delay
export function fadeIn(frame: number, fps: number, delay = 0, duration = 0.4) {
const delayFrames = delay * fps;
const durationFrames = duration * fps;
return interpolate(frame, [delayFrames, delayFrames + durationFrames], [0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
}
// Spring scale
export function springIn(frame: number, fps: number, delay = 0) {
return spring({ frame: frame - delay * fps, fps, config: { damping: 200 } });
}Scene Structure Pattern
export function MyScene() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const titleOpacity = fadeIn(frame, fps, 0, 0.4);
const titleScale = springIn(frame, fps, 0);
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center">
<h2 style={{ opacity: titleOpacity, transform: `scale(${titleScale})` }}>
Title
</h2>
</AbsoluteFill>
);
}Key Principles
1. NEVER use emojis - Import icons from @geist-ui/icons (e.g., import { Code, Folder, Check } from '@geist-ui/icons') 2. Success = Green - Geist uses green for success states (--ds-green-700) 3. Borders = gray-400 - Default border color (--ds-gray-400) 4. Inputs use bg-100 - Primary background, not secondary 5. Spring animations - Smooth, damped motion (damping: 200) 6. Tight letter-spacing - Headings have negative tracking 7. Use official brand assets - Download logos from official sources (see references/geist-icons.md)
References
references/project-setup.md- Complete file templatesreferences/geist-icons.md- Icons and brand assets (MUST READ)references/code-blocks.md- Syntax-highlighted code blocks (use prism-react-renderer)references/geist-colors.md- Full 10-step color scalereferences/geist-typography.md- All typography classes with specsreferences/geist-components.md- Component props and patternsreferences/scene-patterns.md- Scene templates for common contentreferences/storyboard-template.md- Planning video structure
Font Loading (jsDelivr CDN)
@font-face {
font-family: 'Geist';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-sans/Geist-Regular.woff2') format('woff2');
font-weight: 400;
}
/* Add Medium (500), SemiBold (600), Bold (700) weights */Code Blocks for Remotion Videos
IMPORTANT: Do NOT use regex-based syntax highlighting - it breaks easily. Use prism-react-renderer instead.
Installation
npm install prism-react-rendererCodeBlock Component
// src/components/CodeBlock.tsx
import { useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
import { Highlight, themes } from 'prism-react-renderer';
type CodeBlockProps = {
code: string;
language?: string;
delay?: number;
animate?: boolean;
highlightLines?: number[];
fontSize?: number;
};
export function CodeBlock({
code,
language = 'typescript',
delay = 0,
animate = true,
highlightLines = [],
fontSize = 16,
}: CodeBlockProps) {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Fade in animation
const opacity = interpolate(
frame,
[delay * fps, (delay + 0.3) * fps],
[0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
// Typewriter effect - reveal characters over time
const charsToShow = animate
? Math.floor(
interpolate(
frame,
[(delay + 0.2) * fps, (delay + 0.2) * fps + code.length * 0.5],
[0, code.length],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
)
)
: code.length;
const displayCode = code.slice(0, charsToShow);
return (
<div
className="bg-background-200 border border-gray-400 rounded-lg overflow-hidden"
style={{ opacity }}
>
<Highlight theme={geistDarkTheme} code={displayCode} language={language}>
{({ style, tokens, getLineProps, getTokenProps }) => (
<pre
style={{
...style,
margin: 0,
padding: 24,
fontSize,
lineHeight: 1.6,
fontFamily: "'Geist Mono', monospace",
backgroundColor: 'transparent',
}}
>
{tokens.map((line, i) => {
const isHighlighted = highlightLines.includes(i + 1);
return (
<div
key={i}
{...getLineProps({ line })}
style={{
display: 'flex',
backgroundColor: isHighlighted ? 'rgba(0, 112, 243, 0.15)' : 'transparent',
margin: isHighlighted ? '0 -24px' : 0,
padding: isHighlighted ? '0 24px' : 0,
}}
>
<span
style={{
color: '#525252',
marginRight: 24,
minWidth: 24,
textAlign: 'right',
userSelect: 'none',
}}
>
{i + 1}
</span>
<span>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token })} />
))}
</span>
</div>
);
})}
</pre>
)}
</Highlight>
</div>
);
}
// Geist-inspired dark theme for prism-react-renderer
const geistDarkTheme = {
plain: {
color: '#ededed',
backgroundColor: '#171717',
},
styles: [
{
types: ['comment', 'prolog', 'doctype', 'cdata'],
style: { color: '#525252', fontStyle: 'italic' as const },
},
{
types: ['punctuation'],
style: { color: '#737373' },
},
{
types: ['property', 'tag', 'boolean', 'number', 'constant', 'symbol'],
style: { color: '#0070F3' },
},
{
types: ['selector', 'attr-name', 'string', 'char', 'builtin', 'inserted'],
style: { color: '#46A758' },
},
{
types: ['operator', 'entity', 'url', 'variable'],
style: { color: '#ededed' },
},
{
types: ['atrule', 'attr-value', 'keyword'],
style: { color: '#FF6B8A' }, // Pink for keywords
},
{
types: ['function', 'class-name'],
style: { color: '#FFB224' }, // Amber for functions
},
{
types: ['regex', 'important'],
style: { color: '#FFB224' },
},
],
};Usage
import { CodeBlock } from '../components/CodeBlock';
// Basic usage
<CodeBlock code={myCode} />
// With options
<CodeBlock
code={`export async function myWorkflow() {
"use workflow";
const result = await doSomething();
return result;
}`}
language="typescript"
delay={0.3}
animate={true}
highlightLines={[2]} // Highlight line 2
fontSize={18}
/>Supported Languages
Common languages: typescript, javascript, jsx, tsx, json, bash, css, html, python, go, rust
Theme Colors (Geist-aligned)
| Token Type | Color | Hex |
|---|---|---|
| Plain text | Gray 100 | #ededed |
| Comments | Gray 500 | #525252 |
| Punctuation | Gray 400 | #737373 |
| Strings | Green 700 | #46A758 |
| Numbers/Constants | Blue 700 | #0070F3 |
| Keywords | Pink | #FF6B8A |
| Functions | Amber 700 | #FFB224 |
Line Highlighting
Use highlightLines prop to draw attention to specific lines:
// Highlight the directive on line 2
<CodeBlock
code={workflowCode}
highlightLines={[2]}
/>
// Highlight multiple lines
<CodeBlock
code={errorHandlingCode}
highlightLines={[5, 6, 7]}
/>Typewriter Animation
The animate prop enables a typewriter effect that reveals code character by character. Set to false for instant display:
// With typewriter (default)
<CodeBlock code={myCode} animate={true} />
// Instant display
<CodeBlock code={myCode} animate={false} />Alternative: Static Code (No Library)
If you want to avoid the dependency, use a simpler approach without syntax highlighting:
export function SimpleCodeBlock({ code, highlightLines = [] }: { code: string; highlightLines?: number[] }) {
const lines = code.split('\n');
return (
<div className="bg-background-200 border border-gray-400 rounded-lg p-6">
<pre className="font-mono text-sm" style={{ fontFamily: "'Geist Mono', monospace" }}>
{lines.map((line, i) => (
<div
key={i}
className={highlightLines.includes(i + 1) ? 'bg-blue-700/15 -mx-6 px-6' : ''}
>
<span className="text-gray-500 mr-4 inline-block w-6 text-right">{i + 1}</span>
<span className="text-gray-100">{line}</span>
</div>
))}
</pre>
</div>
);
}This won't have syntax highlighting but avoids the regex issues.
Geist Color System
10-step scale from 100 (lightest) to 1000 (darkest). Uses CSS variables --ds-{color}-{step}.
IMPORTANT: Success = Green, NOT Blue. Blue is for info/accent.
Gray Scale
| Step | Light Theme | Dark Theme | Usage |
|---|---|---|---|
| 100 | #F2F2F2 | #1A1A1A | Subtle backgrounds |
| 200 | #EBEBEB | #1F1F1F | Secondary backgrounds |
| 300 | #E6E6E6 | #292929 | Borders (subtle) |
| 400 | #EBEBEB | #737373 | Default borders |
| 500 | #C9C9C9 | #525252 | Borders (hover) |
| 600 | #A8A8A8 | #404040 | Borders (active) |
| 700 | #8F8F8F | #262626 | Muted text |
| 800 | #7D7D7D | #171717 | Secondary text |
| 900 | #666666 | #A1A1A1 | Primary text (light) |
| 1000 | #171717 | #EDEDED | Primary text |
Background Colors
| Token | Light | Dark | Usage |
|---|---|---|---|
| background-100 | #FFFFFF | #0A0A0A | Primary surface |
| background-200 | #FAFAFA | #000000 | Elevated surfaces |
Semantic Colors
| Type | CSS Variable | Value | Usage |
|---|---|---|---|
| success | --ds-green-700 | #46A758 | Success states |
| error | --ds-red-700 | #E5484D | Error states, destructive |
| warning | --ds-amber-700 | #FFB224 | Caution, attention |
| info | --ds-blue-700 | #0070F3 | Informational, accent |
| secondary | --ds-gray-400 | #737373 | Neutral, muted |
| violet | --ds-violet-700 | #8B5CF6 | Accent, special |
| cyan | --ds-cyan-700 | #06B6D4 | Accent, special |
Brand Colors
--geist-success: #46A758; /* Green */
--geist-error: #E5484D; /* Red */
--geist-warning: #FFB224; /* Amber */
--geist-info: #0070F3; /* Blue */
--geist-cyan: #06B6D4;
--geist-violet: #8B5CF6;Blue Scale (Success/Info)
| Step | Value |
|---|---|
| 100 | #F0F7FF |
| 200 | #EBF5FF |
| 300 | #E0F0FF |
| 400 | #CCE4FF |
| 500 | #99CAFF |
| 600 | #52A8FF |
| 700 | #0070F3 |
| 800 | #005FCC |
| 900 | #0062D6 |
| 1000 | #002040 |
Red Scale (Error)
| Step | Value |
|---|---|
| 100 | #FFF0F0 |
| 700 | #E5484D |
| 1000 | #3B1219 |
Amber Scale (Warning)
| Step | Value |
|---|---|
| 100 | #FFF7E6 |
| 700 | #FFB224 |
| 1000 | #4D2900 |
Green Scale
| Step | Value |
|---|---|
| 100 | #EEFBEE |
| 700 | #46A758 |
| 1000 | #1B2D1D |
Usage Patterns
Component States
- Default bg:
{color}-100or{color}-200 - Hover bg:
{color}-200or{color}-300 - Default border:
{color}-400 - Hover border:
{color}-500 - Active border:
{color}-600 - High contrast bg:
{color}-700or{color}-800 - Secondary text:
{color}-900 - Primary text:
{color}-1000
Tailwind Config
colors: {
background: { 100: '#0a0a0a', 200: '#171717' },
gray: {
100: '#ededed', 200: '#d4d4d4', 300: '#a3a3a3',
400: '#737373', 500: '#525252', 600: '#404040',
700: '#262626', 800: '#171717', 900: '#0a0a0a', 1000: '#000000'
},
blue: { 500: '#3b82f6', 600: '#2563eb', 700: '#0070F3' },
red: { 500: '#ef4444', 700: '#E5484D' },
amber: { 500: '#f59e0b', 700: '#FFB224' },
green: { 500: '#22c55e', 700: '#46A758' },
violet: { 500: '#8b5cf6' },
cyan: { 500: '#06b6d4' },
}Geist Components Reference
Key props and patterns for representing Geist components in Remotion videos.
IMPORTANT: Never use emoji characters. Use icons from @geist-ui/icons package.
Button
type: 'default' | 'secondary' | 'tertiary' | 'error' | 'warning' | 'alert' | 'cyan'
size: 'tiny' | 'small' | 'medium' | 'large'
shape: 'square' | 'circle' | 'rounded'
variant: 'shadow' | 'invert' | 'unstyled'Visual representation:
// Primary button
<div className="px-4 py-2 rounded-md bg-white text-black font-medium text-sm">
Confirm
</div>
// Secondary button
<div className="px-4 py-2 rounded-md border border-gray-400 text-gray-300 text-sm">
Cancel
</div>Modal
Structure:
Modal.Modal → Modal.Body → Modal.Header → Modal.Title
→ Content
→ Modal.ActionsVisual representation:
import { X } from '@geist-ui/icons';
<div className="bg-background-100 border border-gray-400 rounded-lg shadow-2xl" style={{ width: 400 }}>
{/* Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-400">
<span className="text-white font-semibold text-xl">Modal Title</span>
<X size={20} color="#737373" />
</div>
{/* Content */}
<div className="px-6 py-6 text-gray-400">Content goes here...</div>
{/* Actions */}
<div className="flex justify-end gap-3 px-6 py-4 border-t border-gray-400">
<button className="px-4 py-2 rounded-md border border-gray-400 text-gray-300">Cancel</button>
<button className="px-4 py-2 rounded-md bg-white text-black font-medium">Confirm</button>
</div>
</div>Note
type: 'error' | 'warning' | 'success' | 'secondary' | 'default'
fill: boolean // fills background
size: 'xSmall' | 'small' | 'mediumSmall' | 'large'Icons: success=CheckCircle (green), error=XCircle (red), warning=AlertTriangle (amber)
Visual representation:
import { AlertTriangle, CheckCircle } from '@geist-ui/icons';
// Warning note
<div className="flex items-center gap-4 px-6 py-4 rounded-lg"
style={{ backgroundColor: '#FFB22415', border: '1px solid #FFB22440' }}>
<AlertTriangle size={20} color="#FFB224" />
<span className="text-amber-700">Warning message</span>
</div>
// Success note (uses GREEN)
<div className="flex items-center gap-4 px-6 py-4 rounded-lg"
style={{ backgroundColor: '#46A75815', border: '1px solid #46A75840' }}>
<CheckCircle size={20} color="#46A758" />
<span className="text-green-700">Success message</span>
</div>Badge
variant: 'gray' | 'blue' | 'red' | 'amber' | 'green' | 'purple' | 'pink' | 'teal'
// Add -subtle suffix for light backgrounds
size: 'lg' | 'md' | 'sm'Visual representation:
<div className="px-3 py-1 rounded-full bg-violet-500/20 border border-violet-500/40 text-violet-400 text-sm font-medium">
Badge
</div>Input
<div>
<label className="text-gray-400 text-sm mb-2 block">Email</label>
<div className="bg-background-100 border border-gray-400 rounded-md px-4 py-3 text-white">
user@vercel.com
</div>
</div>Checkbox
import { Check } from '@geist-ui/icons';
// Checked
<div className="flex items-center gap-3">
<div className="w-5 h-5 rounded border-2 border-green-700 bg-green-700 flex items-center justify-center">
<Check size={12} color="white" />
</div>
<span className="text-white">Remember me</span>
</div>
// Unchecked
<div className="w-5 h-5 rounded border-2 border-gray-400" />Radio
// Selected
<div className="w-5 h-5 rounded-full border-2 border-blue-500 flex items-center justify-center">
<div className="w-2.5 h-2.5 rounded-full bg-blue-500" />
</div>
// Unselected
<div className="w-5 h-5 rounded-full border-2 border-gray-400" />Toggle/Switch
<div className="w-12 h-6 rounded-full bg-blue-500 flex items-center px-1">
<div className="w-4 h-4 rounded-full bg-white" style={{ marginLeft: 'auto' }} />
</div>Select
import { ChevronDown } from '@geist-ui/icons';
<div className="bg-background-100 border border-gray-400 rounded-md px-4 py-3 text-gray-400 flex justify-between items-center">
<span>Select option...</span>
<ChevronDown size={16} color="#737373" />
</div>Table
<div className="border border-gray-400 rounded-lg overflow-hidden">
<table className="w-full">
<thead>
<tr className="bg-background-200">
<th className="px-4 py-3 text-left text-gray-400 text-sm font-medium border-b border-gray-400">Column</th>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-3 text-white text-sm">data</td>
</tr>
</tbody>
</table>
</div>Tabs
<div className="flex gap-1 bg-background-200 rounded-lg p-1">
<div className="px-4 py-2 rounded-md bg-white text-black font-medium text-sm">Tab 1</div>
<div className="px-4 py-2 rounded-md text-gray-400 text-sm">Tab 2</div>
<div className="px-4 py-2 rounded-md text-gray-400 text-sm">Tab 3</div>
</div>Toast
import { CheckCircle } from '@geist-ui/icons';
<div className="flex items-center gap-3 px-5 py-3 rounded-lg bg-background-200 border border-gray-400 shadow-lg">
<CheckCircle size={18} color="#46A758" /> {/* Success = green */}
<span className="text-white text-sm">Operation completed</span>
</div>StatusDot
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-700" /> {/* Success = green */}
<span className="text-gray-300 text-sm">Online</span>
</div>Spinner
<div className="w-5 h-5 border-2 border-gray-600 border-t-blue-500 rounded-full" />Geist Icons & Brand Assets
CRITICAL: NEVER use emojis in Remotion videos. Always use proper Geist icons or official brand assets.
Icon Package
Install the @geist-ui/icons package for proper Geist icons:
npm install @geist-ui/iconsUsage
import { Code, Folder, Check, ArrowRight, Settings, Globe } from '@geist-ui/icons';
// Basic usage
<Code />
// With customization
<Check size={24} color="#46A758" />
<Folder size={32} color="white" />Common Icons
| Instead of Emoji | Use Icon |
|---|---|
| 📁 | <Folder /> |
| 📄 | <File /> |
| ✓ or ✅ | <Check /> or <CheckCircle /> |
| ⚠ or ⚠️ | <AlertTriangle /> |
| ❌ | <X /> or <XCircle /> |
| ⬇️ | <ArrowDown /> or <Download /> |
| ⬆️ | <ArrowUp /> or <Upload /> |
| ➡️ | <ArrowRight /> |
| 🔒 | <Lock /> |
| 🌐 | <Globe /> |
| ⚙️ | <Settings /> |
| 💻 | <Monitor /> or <Code /> |
| 📱 | <Smartphone /> |
| 🔍 | <Search /> |
| 📊 | <BarChart /> |
Icon Props
interface IconProps {
size?: number; // Default: 24
color?: string; // Default: 'currentColor'
strokeWidth?: number; // Default: 1.5
}Official Brand Assets
Download official logos from Vercel's brand page. Do not hand-craft SVGs.
Download URLs
| Brand | Download |
|---|---|
| Vercel | https://assets.vercel.com/raw/upload/front/press/vercel-assets.zip |
| Next.js | https://assets.vercel.com/raw/upload/front/press/nextjs-assets.zip |
| Turbo | https://assets.vercel.com/raw/upload/front/press/turbo-assets.zip |
| v0 | https://assets.vercel.com/raw/upload/v1762563059/front/press/v0-assets.zip |
| AI SDK | https://assets.vercel.com/raw/upload/v1763470459/front/press/ai-sdk-assets.zip |
Vercel Logo Component
After downloading assets, create a component from the official SVG:
// src/components/VercelLogo.tsx
type VercelLogoProps = { size?: number; color?: string };
export function VercelLogo({ size = 80, color = 'white' }: VercelLogoProps) {
return (
<svg width={size} height={size * 0.87} viewBox="0 0 76 65" fill="none">
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" fill={color} />
</svg>
);
}Next.js Logo Component
// src/components/NextJSLogo.tsx
type NextJSLogoProps = { size?: number; color?: string };
export function NextJSLogo({ size = 80, color = 'white' }: NextJSLogoProps) {
return (
<svg width={size} height={size} viewBox="0 0 180 180" fill="none">
<mask id="mask0" style={{ maskType: 'alpha' }} maskUnits="userSpaceOnUse" x="0" y="0" width="180" height="180">
<circle cx="90" cy="90" r="90" fill="black" />
</mask>
<g mask="url(#mask0)">
<circle cx="90" cy="90" r="90" fill={color === 'white' ? 'black' : color} stroke={color} strokeWidth="6" />
<path
d="M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z"
fill="url(#paint0_linear)"
/>
<rect x="115" y="54" width="12" height="72" fill="url(#paint1_linear)" />
</g>
<defs>
<linearGradient id="paint0_linear" x1="109" y1="116.5" x2="144.5" y2="160.5" gradientUnits="userSpaceOnUse">
<stop stopColor={color} />
<stop offset="1" stopColor={color} stopOpacity="0" />
</linearGradient>
<linearGradient id="paint1_linear" x1="121" y1="54" x2="120.799" y2="106.875" gradientUnits="userSpaceOnUse">
<stop stopColor={color} />
<stop offset="1" stopColor={color} stopOpacity="0" />
</linearGradient>
</defs>
</svg>
);
}Geist Icons Browser
Browse all 600+ official icons at: https://vercel.com/geist/icons
You can right-click any icon to copy its SVG.
Alternative: Copy SVGs Directly
If you need icons not in @geist-ui/icons, visit https://vercel.com/geist/icons and right-click to copy the SVG, then create a React component:
// Example: Custom icon from Geist
export function CustomIcon({ size = 24, color = 'currentColor' }: { size?: number; color?: string }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5">
{/* Paste SVG path here */}
</svg>
);
}Icon Categories Available
From vercel.com/geist/icons:
- Navigation: Arrows, chevrons, menu, sidebar
- Actions: Check, X, plus, minus, edit, delete
- Files: Folder, file, document, code
- Communication: Bell, envelope, message, chat
- Media: Play, pause, volume, camera
- Data: Chart, graph, database, table
- Status: Loading, spinner, check-circle, alert
- Devices: Monitor, smartphone, tablet, server
- Social: GitHub, Twitter/X, Discord, LinkedIn
- Brand: Vercel, Next.js, Turbo, v0, and 40+ tech logos
Geist Typography
All typography uses Geist Sans (sans) or Geist Mono (mono). Classes set font-size, line-height, letter-spacing, and font-weight.
Heading Classes
| Class | Size | Line Height | Letter Spacing | Weight |
|---|---|---|---|---|
| text-heading-72 | 72px | 72px | -4.32px | 600 (semibold) |
| text-heading-64 | 64px | 64px | -3.84px | 600 |
| text-heading-56 | 56px | 56px | -3.36px | 600 |
| text-heading-48 | 48px | 56px | -2.88px | 600 |
| text-heading-40 | 40px | 48px | -2.4px | 600 |
| text-heading-32 | 32px | 40px | -1.28px | 600 |
| text-heading-24 | 24px | 32px | -0.96px | 600 |
| text-heading-20 | 20px | 26px | -0.4px | 600 |
| text-heading-16 | 16px | 24px | -0.32px | 600 |
| text-heading-14 | 14px | 20px | -0.28px | 600 |
Usage:
- 72: Marketing heroes
- 48-64: Marketing subheadings
- 32: Dashboard page headings
- 24: Section headings
- 16-20: Card/modal titles
- 14: Small headings
Label Classes
| Class | Font | Size | Line Height | Weight |
|---|---|---|---|---|
| text-label-20 | sans | 20px | 32px | 400 |
| text-label-18 | sans | 18px | 20px | 400 |
| text-label-16 | sans | 16px | 20px | 400 |
| text-label-14 | sans | 14px | 20px | 400 |
| text-label-14-mono | mono | 14px | 20px | 400 |
| text-label-13 | sans | 13px | 16px | 400 |
| text-label-13-mono | mono | 13px | 20px | 400 |
| text-label-12 | sans | 12px | 16px | 400 |
| text-label-12-mono | mono | 12px | 16px | 400 |
Usage:
- 20: Marketing labels
- 16: Form labels, titles
- 14: Most common (menus, buttons)
- 13: Secondary info, tabular data
- 12: Tertiary (timestamps, badges)
- mono variants: Code, technical data
Copy Classes
| Class | Font | Size | Line Height | Weight |
|---|---|---|---|---|
| text-copy-24 | sans | 24px | 36px | 400 |
| text-copy-20 | sans | 20px | 36px | 400 |
| text-copy-18 | sans | 18px | 28px | 400 |
| text-copy-16 | sans | 16px | 24px | 400 |
| text-copy-14 | sans | 14px | 20px | 400 |
| text-copy-14-mono | mono | 14px | 20px | 400 |
| text-copy-13 | sans | 13px | 18px | 400 |
| text-copy-13-mono | mono | 13px | 18px | 400 |
Usage:
- 24: Marketing hero paragraphs
- 20: Marketing body text
- 18: Quotes, featured text
- 16: Modal body, spacious views
- 14: Most common body text
- 13: Compact views, descriptions
- mono variants: Inline code
Button Classes
| Class | Size | Line Height | Weight |
|---|---|---|---|
| text-button-16 | 16px | 20px | 500 (medium) |
| text-button-14 | 14px | 20px | 500 |
| text-button-12 | 12px | 16px | 500 |
Font Families
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'Geist Mono', 'SF Mono', Monaco, 'Consolas', monospace;CSS Implementation
.text-heading-32 {
font-family: var(--font-sans);
font-size: 32px;
font-weight: 600;
line-height: 40px;
letter-spacing: -1.28px;
}
.text-label-14 {
font-family: var(--font-sans);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.text-copy-14-mono {
font-family: var(--font-mono);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}Remotion Implementation
// For headings - use semibold + tight tracking
<h2 style={{
fontSize: 48,
fontWeight: 600,
lineHeight: '56px',
letterSpacing: '-2.88px',
fontFamily: 'Geist, sans-serif',
}}>
Heading Text
</h2>
// For labels - normal weight
<span style={{
fontSize: 14,
fontWeight: 400,
lineHeight: '20px',
fontFamily: 'Geist, sans-serif',
}}>
Label Text
</span>
// For mono text
<code style={{
fontSize: 13,
fontWeight: 400,
lineHeight: '18px',
fontFamily: 'Geist Mono, monospace',
}}>
code text
</code>Project Setup
Complete file templates for a Geist Remotion video project.
package.json
{
"name": "geist-video",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "remotion studio",
"build": "remotion render MainVideo out/video.mp4",
"render": "remotion render MainVideo out/video.mp4"
},
"dependencies": {
"@geist-ui/icons": "^1.0.2",
"@remotion/cli": "^4.0.0",
"@remotion/tailwind": "^4.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"remotion": "^4.0.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"tailwindcss": "^3.4.0",
"typescript": "^5.0.0"
}
}remotion.config.ts
import { Config } from '@remotion/cli/config';
import { enableTailwind } from '@remotion/tailwind';
Config.overrideWebpackConfig((config) => {
return enableTailwind(config);
});tailwind.config.js
module.exports = {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
background: { 100: '#0a0a0a', 200: '#171717' },
gray: {
100: '#ededed', 200: '#d4d4d4', 300: '#a3a3a3',
400: '#737373', 500: '#525252', 600: '#404040',
700: '#262626', 800: '#171717', 900: '#0a0a0a', 1000: '#000000'
},
// Semantic colors - success=green, error=red, warning=amber, info=blue
blue: { 500: '#3b82f6', 600: '#2563eb', 700: '#0070F3' },
red: { 500: '#ef4444', 700: '#E5484D' },
amber: { 500: '#f59e0b', 700: '#FFB224' },
green: { 500: '#22c55e', 700: '#46A758' }, // Success color
violet: { 500: '#8b5cf6', 700: '#8B5CF6' },
cyan: { 500: '#06b6d4', 700: '#06B6D4' },
},
fontFamily: {
sans: ['Geist', 'sans-serif'],
mono: ['Geist Mono', 'monospace'],
},
},
},
plugins: [],
};src/styles.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: 'Geist';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-sans/Geist-Regular.woff2') format('woff2');
font-weight: 400;
}
@font-face {
font-family: 'Geist';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-sans/Geist-Medium.woff2') format('woff2');
font-weight: 500;
}
@font-face {
font-family: 'Geist';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-sans/Geist-SemiBold.woff2') format('woff2');
font-weight: 600;
}
@font-face {
font-family: 'Geist';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-sans/Geist-Bold.woff2') format('woff2');
font-weight: 700;
}
@font-face {
font-family: 'Geist Mono';
src: url('https://cdn.jsdelivr.net/npm/geist@1.5.1/dist/fonts/geist-mono/GeistMono-Regular.woff2') format('woff2');
font-weight: 400;
}src/index.tsx (Entry Point)
IMPORTANT: The entry point must be .tsx (not .ts) and must call registerRoot().
import { registerRoot } from 'remotion';
import { RemotionRoot } from './Root';
registerRoot(RemotionRoot);src/Root.tsx (Composition Definitions)
import { Composition } from 'remotion';
import { MainVideo } from './MainVideo';
import './styles.css';
export const RemotionRoot = () => {
return (
<Composition
id="MainVideo"
component={MainVideo}
durationInFrames={45 * 30} // 45 seconds at 30fps
fps={30}
width={1920}
height={1080}
/>
);
};src/utils/animations.ts
import { interpolate, spring } from 'remotion';
export const springConfig = {
smooth: { damping: 200 },
snappy: { damping: 20, stiffness: 200 },
bouncy: { damping: 8 },
};
export function fadeIn(frame: number, fps: number, delay = 0, duration = 0.4) {
const delayFrames = delay * fps;
const durationFrames = duration * fps;
return interpolate(frame, [delayFrames, delayFrames + durationFrames], [0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
}
export function slideUp(frame: number, fps: number, delay = 0, distance = 30) {
const progress = spring({ frame: frame - delay * fps, fps, config: springConfig.smooth });
return interpolate(progress, [0, 1], [distance, 0]);
}
export function slideRight(frame: number, fps: number, delay = 0, distance = 30) {
const progress = spring({ frame: frame - delay * fps, fps, config: springConfig.smooth });
return interpolate(progress, [0, 1], [-distance, 0]);
}
export function scaleIn(frame: number, fps: number, delay = 0, from = 0.8) {
const progress = spring({ frame: frame - delay * fps, fps, config: springConfig.snappy });
return interpolate(progress, [0, 1], [from, 1]);
}
export function springIn(frame: number, fps: number, delay = 0) {
return spring({ frame: frame - delay * fps, fps, config: springConfig.smooth });
}src/components/VercelLogo.tsx
NOTE: For official brand assets, download from https://assets.vercel.com/raw/upload/front/press/vercel-assets.zip See references/geist-icons.md for more brand asset download links.
type VercelLogoProps = { size?: number; color?: string };
export function VercelLogo({ size = 80, color = 'white' }: VercelLogoProps) {
return (
<svg width={size} height={size * 0.87} viewBox="0 0 76 65" fill="none">
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" fill={color} />
</svg>
);
}Scene Patterns
Templates for common Remotion scene types using Geist design system.
IMPORTANT: Never use emojis. Use icons from @geist-ui/icons package.
Base Scene Structure
import { AbsoluteFill, useCurrentFrame, useVideoConfig } from 'remotion';
import { fadeIn, springIn, slideUp, slideRight } from '../utils/animations';
export function SceneName() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Animation values
const titleOpacity = fadeIn(frame, fps, 0, 0.4);
const titleScale = springIn(frame, fps, 0);
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center px-20">
<h2
className="text-white font-bold"
style={{
fontSize: 64,
opacity: titleOpacity,
transform: `scale(${titleScale})`,
}}
>
Scene Title
</h2>
{/* Content */}
</AbsoluteFill>
);
}Title Scene
export function TitleScene() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const logoOpacity = fadeIn(frame, fps, 0, 0.4);
const logoScale = scaleIn(frame, fps, 0, 0.5);
const titleOpacity = fadeIn(frame, fps, 0.3, 0.5);
const titleY = slideUp(frame, fps, 0.3, 40);
const subtitleOpacity = fadeIn(frame, fps, 0.6, 0.4);
const taglineOpacity = fadeIn(frame, fps, 0.9, 0.3);
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center">
<div style={{ opacity: logoOpacity, transform: `scale(${logoScale})` }}>
<VercelLogo size={80} />
</div>
<h1 className="text-white font-bold mt-8"
style={{ fontSize: 120, letterSpacing: '-0.03em', opacity: titleOpacity, transform: `translateY(${titleY}px)` }}>
TITLE
</h1>
<p className="text-gray-400 mt-2" style={{ fontSize: 48, opacity: subtitleOpacity }}>
Subtitle
</p>
<p className="text-gray-500 mt-12" style={{ fontSize: 24, opacity: taglineOpacity }}>
Tagline • Words • Here
</p>
</AbsoluteFill>
);
}Card Grid Scene (2x2)
import { Eye, Zap, Monitor, Smartphone } from '@geist-ui/icons';
// Define items with icon components, NOT emojis
const items = [
{ Icon: Eye, title: 'Feature 1', desc: 'Description' },
{ Icon: Zap, title: 'Feature 2', desc: 'Description' },
{ Icon: Monitor, title: 'Feature 3', desc: 'Description' },
{ Icon: Smartphone, title: 'Feature 4', desc: 'Description' },
];
export function CardGridScene() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center px-20">
<h2 className="text-white font-bold mb-16" style={{ fontSize: 64 }}>Title</h2>
<div className="grid grid-cols-2 gap-8">
{items.map((item, index) => {
const delay = 0.3 + index * 0.15;
const opacity = fadeIn(frame, fps, delay, 0.4);
const y = slideUp(frame, fps, delay, 30);
const { Icon } = item;
return (
<div key={item.title}
className="bg-background-200 border border-gray-400 rounded-lg p-8 flex items-center gap-6"
style={{ opacity, transform: `translateY(${y}px)`, width: 400 }}>
<Icon size={48} color="white" />
<div>
<h3 className="text-white font-semibold text-2xl">{item.title}</h3>
<p className="text-gray-400 text-lg mt-1">{item.desc}</p>
</div>
</div>
);
})}
</div>
</AbsoluteFill>
);
}Color Scale Scene
const colors = [
{ value: '#ededed', label: '100' },
{ value: '#d4d4d4', label: '200' },
// ... continue scale
{ value: '#000000', label: '1000' },
];
export function ColorScaleScene() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center px-20">
<h2 className="text-white font-bold" style={{ fontSize: 64 }}>Color System</h2>
<p className="text-gray-400 mt-4 mb-12" style={{ fontSize: 24 }}>
10-step scale: 100 → 1000
</p>
<div className="flex gap-2">
{colors.map((color, index) => {
const delay = 0.4 + index * 0.08;
const opacity = fadeIn(frame, fps, delay, 0.2);
const scale = springIn(frame, fps, delay);
return (
<div key={color.label}
className="rounded-md flex items-center justify-center"
style={{ width: 80, height: 80, backgroundColor: color.value, opacity, transform: `scale(${scale})` }}>
<span style={{ fontSize: 14, color: index < 4 ? '#0a0a0a' : '#ededed', fontFamily: 'Geist Mono' }}>
{color.label}
</span>
</div>
);
})}
</div>
</AbsoluteFill>
);
}Typography Showcase Scene
const sections = [
{ title: 'Headers', items: [
{ class: 'text-heading-48', size: '48px', sample: 'Heading' },
{ class: 'text-heading-32', size: '32px', sample: 'Heading' },
]},
{ title: 'Labels', items: [
{ class: 'text-label-14', size: '14px', sample: 'Label Text' },
]},
{ title: 'Copy', items: [
{ class: 'text-copy-14', size: '14px', sample: 'Body text' },
{ class: 'text-copy-13-mono', size: '13px', sample: 'code', mono: true },
]},
];
// Render with staggered animations per section and itemSpacing Visualization Scene
const spacing = [
{ name: 'space-2', px: 8, label: 'tight' },
{ name: 'space-4', px: 16, label: 'default' },
{ name: 'space-6', px: 24, label: 'comfortable' },
{ name: 'space-8', px: 32, label: 'spacious' },
];
// Render with animated bar widths:
const widthProgress = springIn(frame, fps, delay);
const barWidth = interpolate(widthProgress, [0, 1], [0, space.px * 5]);Checklist Summary Scene
import { Check } from '@geist-ui/icons';
const items = ['Feature 1', 'Feature 2', 'Feature 3'];
export function SummaryScene() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
return (
<AbsoluteFill className="bg-background-100 flex flex-col items-center justify-center">
<h2 className="text-white font-bold mb-12" style={{ fontSize: 80 }}>Title</h2>
<div className="flex flex-col gap-3">
{items.map((item, index) => {
const delay = 0.2 + index * 0.12;
const opacity = fadeIn(frame, fps, delay, 0.3);
const x = slideRight(frame, fps, delay, 20);
return (
<div key={item} className="flex items-center gap-4" style={{ opacity, transform: `translateX(${x}px)` }}>
<div className="w-6 h-6 rounded-full bg-green-700/20 border border-green-700/40 flex items-center justify-center">
<Check size={14} color="#46A758" />
</div>
<span className="text-white text-xl">{item}</span>
</div>
);
})}
</div>
</AbsoluteFill>
);
}Main Video Composition
import { AbsoluteFill, Sequence, useVideoConfig } from 'remotion';
export function MainVideo() {
const { fps } = useVideoConfig();
const scenes = [
{ component: TitleScene, duration: 3 },
{ component: FeatureScene, duration: 5 },
{ component: ColorScene, duration: 6 },
// Add more scenes...
];
let currentFrame = 0;
return (
<AbsoluteFill className="bg-background-100">
{scenes.map((scene, index) => {
const Scene = scene.component;
const from = currentFrame;
currentFrame += scene.duration * fps;
return (
<Sequence key={index} from={from} durationInFrames={scene.duration * fps} premountFor={fps}>
<Scene />
</Sequence>
);
})}
</AbsoluteFill>
);
}Storyboard Template
Use this template to plan video structure before implementation.
Video Metadata
# [Video Title]
## Meta
| Property | Value |
|----------|-------|
| Duration | 45s |
| FPS | 30 |
| Resolution | 1920x1080 |
| Font | Geist Sans, Geist Mono |
| Style | Dark (#0a0a0a bg), spring animations |
## Colors
| Name | Hex | Usage |
|------|-----|-------|
| bg-100 | #0a0a0a | Primary background |
| bg-200 | #171717 | Secondary background |
| primary | #ffffff | Primary text |
| muted | #737373 | Secondary text |
| blue | #3b82f6 | Success/info |
| red | #ef4444 | Error |
| amber | #f59e0b | Warning |Scene Template
## Scene N: [Scene Name]
**Time:** 0:00 → 0:03
### Layout┌─────────────────────────────────────┐ │ │ │ [ASCII diagram] │ │ │ └─────────────────────────────────────┘
### Elements
1. **Element Name** — Description — style notes
2. **Element Name** — Description — style notes
### Animation
| Element | Effect | Delay | Duration |
|---------|--------|-------|----------|
| Title | spring-in | 0ms | 400ms |
| Content | fade-in + slide-up | 300ms | 400ms |
### Transition
Crossfade 200msExample Storyboard
# Geist Design System Explainer
## Scene 1: Title (0:00 → 0:03)
### Layout┌─────────────────────────────────────┐ │ ▲ (Vercel logo) │ │ GEIST │ │ Design System │ │ High Contrast • Minimal • Dev │ └─────────────────────────────────────┘
### Elements
1. **Vercel Logo** — Triangle — 80px, white, center
2. **Title** — "GEIST" — 120px, bold, white
3. **Subtitle** — "Design System" — 48px, muted
4. **Tagline** — Principles — 24px, muted
### Animation
| Element | Effect | Delay | Duration |
|---------|--------|-------|----------|
| Logo | scale-in + fade-in | 0ms | 400ms |
| Title | spring-in + slide-up | 300ms | 500ms |
| Subtitle | fade-in + slide-up | 600ms | 400ms |
| Tagline | fade-in | 900ms | 300ms |
---
## Scene 2: Core Principles (0:03 → 0:08)
### Layout┌─────────────────────────────────────┐ │ "Core Principles" │ │ ┌─────────┐ ┌─────────┐ │ │ │ HIGH │ │ MINIMAL │ │ │ │CONTRAST │ │ -IST │ │ │ └─────────┘ └─────────┘ │ │ ┌─────────┐ ┌─────────┐ │ │ │ DEV │ │ RESPON- │ │ │ │ FOCUSED │ │ SIVE │ │ │ └─────────┘ └─────────┘ │ └─────────────────────────────────────┘
### Elements
1. **Title** — "Core Principles" — 64px, bold
2. **Card 1-4** — Feature cards — bg-200, border, icon + text
### Animation
| Element | Effect | Delay | Duration |
|---------|--------|-------|----------|
| Title | spring-in | 0ms | 400ms |
| Card 1 | spring-in + slide-up | 300ms | 400ms |
| Card 2 | spring-in + slide-up | 450ms | 400ms |
| Card 3 | spring-in + slide-up | 600ms | 400ms |
| Card 4 | spring-in + slide-up | 750ms | 400ms |Timing Guidelines
| Scene Type | Suggested Duration |
|---|---|
| Title/Intro | 2-4 seconds |
| Feature cards (4 items) | 4-6 seconds |
| Color/typography demo | 5-7 seconds |
| Component showcase | 4-6 seconds |
| Summary/outro | 3-5 seconds |
Animation Timing
| Animation | Typical Duration | When to Use |
|---|---|---|
| fade-in | 300-500ms | Subtle entrances |
| spring-in | 400-600ms | Primary elements |
| slide-up | 300-400ms | Cascading items |
| scale-in | 400-500ms | Emphasis elements |
| stagger | 100-200ms | Lists, grids |
Checklist
- [ ] All scenes have clear layout diagrams
- [ ] Total duration matches video length
- [ ] Animation delays create readable flow
- [ ] Scene transitions defined
- [ ] Color palette documented
- [ ] Typography choices noted
Related skills
How it compares
Pick create-remotion-geist for Geist-branded Remotion code videos; generic Remotion skills omit Vercel tokens and prism-react-renderer guardrails.
FAQ
What does create-remotion-geist do?
Create Remotion videos using the Geist design system aesthetic. Use when asked to create videos, animations, or motion graphics that should follow Vercel's visual style - dark theme, spri...
When should I use create-remotion-geist?
Invoke when Create Remotion videos using the Geist design system aesthetic. Use when asked to create videos, animations, or motion graphics that should .
Is create-remotion-geist safe to install?
Review the Security Audits panel on this page before installing in production.