remotion-video
npx skills add https://github.com/cdeistopened/skill-stack --skill remotion-video
Agent 安装分布
Skill 文档
Remotion Video Creator
Create programmatic videos using Remotion – React components that render to video. This skill encodes the Skill Stack visual style and lessons learned from building explainer content.
Purpose
Build short-form video content (10-60 seconds) that explains Skill Stack concepts with a distinctive risograph-inspired aesthetic. Videos are code, so they’re version-controlled, reproducible, and infinitely editable.
When to Use This Skill
- Creating explainer videos for Skill Stack concepts
- Building animated social content (vertical 9:16, square 1:1, landscape 16:9)
- Visualizing technical workflows or progressive disclosure
- Any video where precise timing and typography matter
Not for:
- Live footage editing (use traditional video tools)
- Complex 3D graphics (Remotion is 2D-focused)
- Quick one-off graphics (use Figma or Canva)
Project Setup
Quick Start
# Create new Remotion project
npx create-video@latest my-video
# Install dependencies
cd my-video && npm install
# Add Google Fonts
npm install @remotion/google-fonts
# Start studio
npm run start # Opens http://localhost:3000
File Structure
my-video/
âââ src/
â âââ Root.tsx # Composition definitions
â âââ Main.tsx # Main video component
â âââ components/ # Reusable elements
âââ package.json
âââ remotion.config.ts
âââ out/ # Rendered videos
Composition Setup (Root.tsx)
Always create multiple aspect ratios for each video:
import { Composition, Folder } from "remotion";
import { MyVideo } from "./MyVideo";
export const RemotionRoot = () => (
<>
<Folder name="MyVideo">
<Composition
id="MyVideo-Vertical"
component={MyVideo}
durationInFrames={600} // 20 seconds at 30fps
fps={30}
width={1080}
height={1920} // 9:16
/>
<Composition
id="MyVideo-Square"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1080}
height={1080} // 1:1
/>
<Composition
id="MyVideo-Landscape"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1920}
height={1080} // 16:9
/>
</Folder>
</>
);
Visual Style: Skill Stack Risograph
Color Palette
const C = {
paper: "#FAF8F5", // Warm off-white background
coral: "#D4694A", // Accent, CTAs, highlights
teal: "#1E4D4D", // Headers, selected states
ink: "#1C1C1C", // Body text
muted: "#666666", // Secondary text
dimmed: "#AAAAAA", // Tertiary, disabled
white: "#FFFFFF", // Cards, containers
};
Typography
import { loadFont as loadInter } from "@remotion/google-fonts/Inter";
import { loadFont as loadPlayfair } from "@remotion/google-fonts/PlayfairDisplay";
import { loadFont as loadJetBrains } from "@remotion/google-fonts/JetBrainsMono";
// Body text, UI labels
const { fontFamily: inter } = loadInter("normal", {
weights: ["400", "500", "600"],
subsets: ["latin"],
});
// Headlines, quotes, emotional text
const { fontFamily: playfair } = loadPlayfair("normal", {
weights: ["400", "500", "600", "700"],
subsets: ["latin"],
});
// Code, technical content, skill names
const { fontFamily: mono } = loadJetBrains("normal", {
weights: ["400", "500"],
subsets: ["latin"],
});
Font Size Guidelines
Minimum readable sizes for video:
| Element | Square (1080) | Vertical (1080w) | Landscape (1920w) |
|---|---|---|---|
| Headlines | 64-84px | 64-84px | 72-96px |
| Skill names | 36-40px | 36-40px | 40-48px |
| Body text | 28-32px | 28-32px | 32-36px |
| Labels | 24-28px | 24-28px | 28-32px |
| Annotation | 22-24px | 22-24px | 24-28px |
Key lesson: Always larger than you think. Video compresses detail.
Grain Overlay
const GrainOverlay: React.FC = () => {
const frame = useCurrentFrame();
return (
<AbsoluteFill
style={{
pointerEvents: "none",
opacity: 0.04,
mixBlendMode: "multiply",
}}
>
<svg width="100%" height="100%">
<defs>
<filter id="grain">
<feTurbulence
type="fractalNoise"
baseFrequency="0.8"
numOctaves="4"
seed={Math.floor(frame / 4)} // Animate grain
/>
</filter>
</defs>
<rect width="100%" height="100%" filter="url(#grain)" />
</svg>
</AbsoluteFill>
);
};
Animation Patterns
Core Tools
import {
useCurrentFrame,
useVideoConfig,
AbsoluteFill,
interpolate,
spring,
Sequence,
} from "remotion";
Fade In/Out
const fadeIn = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const fadeOut = interpolate(frame, [150, 180], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Combine for scene opacity
<div style={{ opacity: fadeIn * fadeOut }}>
Spring Animations
const { fps } = useVideoConfig();
// Smooth entrance
const entrance = spring({
frame: frame - 20, // Delay by 20 frames
fps,
config: { damping: 100 }, // Smooth, no bounce
});
// Bouncy selection
const selectPulse = spring({
frame: frame - 15,
fps,
config: { damping: 12, stiffness: 100 }, // Bouncy
});
// Apply to transform
<div style={{
opacity: interpolate(entrance, [0, 1], [0, 1]),
transform: `translateY(${interpolate(entrance, [0, 1], [20, 0])}px)`,
}}>
Typewriter Effect
const ScenePrompt: React.FC<{ frame: number }> = ({ frame }) => {
const text = "Your prompt text here";
const charsToShow = Math.floor(frame / 2); // 15 chars/sec at 30fps
const visibleText = text.slice(0, charsToShow);
const isTyping = charsToShow < text.length;
const cursorBlink = Math.floor(frame / 18) % 2 === 0;
return (
<div>
"{visibleText}
{(isTyping || cursorBlink) && (
<span style={{
backgroundColor: C.coral,
marginLeft: 4,
opacity: cursorBlink ? 1 : 0,
}}>
{"\u00A0"}
</span>
)}
{!isTyping && '"'}
</div>
);
};
Staggered List Animation
const ITEMS = ["item-1", "item-2", "item-3"];
{ITEMS.map((item, i) => {
const delay = i * 25; // 25 frames between each
const s = spring({
frame: Math.max(0, frame - delay - 20),
fps,
config: { damping: 100 },
});
return (
<div
key={item}
style={{
opacity: interpolate(s, [0, 1], [0, 1]),
transform: `translateY(${interpolate(s, [0, 1], [20, 0])}px)`,
}}
>
{item}
</div>
);
})}
Scene Timing Guidelines
Duration Math
- 30 fps = 30 frames per second
- 10 seconds = 300 frames
- 20 seconds = 600 frames
Pacing Lessons Learned
Too fast is the #1 mistake. Viewers need time to:
- Notice a scene change
- Read text
- Process meaning
- Prepare for next change
Minimum scene durations:
| Scene Type | Minimum | Comfortable |
|---|---|---|
| Typewriter text | 3-4 sec | 5-6 sec |
| List appearing | 4-5 sec | 6-8 sec |
| Selection/highlight | 3-4 sec | 5 sec |
| Technical diagram | 4-5 sec | 6-8 sec |
| Punchline/CTA | 2-3 sec | 3-4 sec |
Scene Overlap Pattern
Scenes should cross-fade, not hard cut:
// Scene timing for 20-second video (600 frames)
{frame < 200 && <ScenePrompt frame={frame} />}
{frame >= 160 && frame < 340 && <SceneScan frame={frame - 160} />}
{frame >= 300 && frame < 460 && <SceneSelect frame={frame - 300} />}
{frame >= 420 && frame < 560 && <SceneLoad frame={frame - 420} />}
{frame >= 520 && <ScenePunchline frame={frame - 520} />}
The 40-frame overlap (1.3 seconds) creates smooth cross-fades when combined with fadeIn/fadeOut interpolations.
Workflow
Phase 1: Storyboard
Before coding, define:
- Core message – What’s the one thing viewers should learn?
- Scene breakdown – 4-6 scenes, each with one idea
- Total duration – 10-20 seconds for social, 30-60 for explainers
- Text content – Exact words for each scene
Phase 2: Scaffold
- Create composition with proper duration
- Build scene components with placeholder content
- Set up basic timing (scene ranges)
- Test that all scenes appear
Phase 3: Style
- Apply color palette and fonts
- Add grain overlay
- Ensure font sizes are readable
- Test on phone (vertical) and desktop (landscape)
Phase 4: Animate
- Add fadeIn/fadeOut to each scene
- Add spring animations for entrances
- Fine-tune timing – almost always needs to be slower
- Test full playback multiple times
Phase 5: Render
# Render specific composition
npx remotion render MyVideo-Square out/square.mp4
# Render all formats
npx remotion render MyVideo-Vertical out/vertical.mp4
npx remotion render MyVideo-Square out/square.mp4
npx remotion render MyVideo-Landscape out/landscape.mp4
Common Mistakes
â Centering Issues
Problem: Content appears in top-left corner.
Fix: Use AbsoluteFill with flexbox, not position: absolute.
// â
Correct
<AbsoluteFill style={{
justifyContent: "center",
alignItems: "center",
}}>
// â Wrong
<div style={{ position: "absolute", left: "50%", top: "50%" }}>
â Tiny Fonts
Problem: Text readable in studio, illegible on phone.
Fix: Minimum 28px for body text, 64px for headlines.
â Too Fast
Problem: Can’t read text before it disappears.
Fix: Double your initial duration estimate. Each scene needs 4-8 seconds minimum.
â Hard Cuts
Problem: Jarring transitions between scenes.
Fix: Overlap scenes by 30-50 frames with fadeIn/fadeOut.
â No Aspect Ratio Support
Problem: Video looks wrong on different platforms.
Fix: Create all three compositions (vertical, square, landscape) from the start.
Caption Integration
Remotion has first-class caption support. Three options by cost:
Option 1: Native Whisper (Recommended – Free)
npm install @remotion/captions @remotion/install-whisper-cpp
npx @remotion/install-whisper-cpp --model large-v3-turbo
import { transcribe } from "@remotion/captions";
const result = await transcribe({
inputPath: "/path/to/audio.mp3",
model: "large-v3-turbo",
language: "en",
});
// result.captions = [{ text: "Hello", startTime: 0, endTime: 0.5 }, ...]
Option 2: ZapCap API ($0.10/min)
For batch processing without local model setup.
Option 3: Submagic API ($0.69/min)
Pre-styled “viral” caption templates, but expensive.
Full workflow details: See references/caption-workflow.md
Community Resources
Discord
Remotion Discord – 6,000+ members. Active #help and #showcase channels. Creator (Jonny Burger) responds directly.
Key Templates to Study
| Template | Use Case | Link |
|---|---|---|
| TikTok | Vertical social video | remotion-dev/template-tiktok |
| Audiogram | Podcast clips | remotion-dev/template-audiogram |
| GitHub Unwrapped | Data-driven video | remotion-dev/github-unwrapped |
| claude-remotion-kickstart | AI-assisted workflow | Community starter for Claude + Remotion |
Essential Packages
# Captions
npm install @remotion/captions @remotion/install-whisper-cpp
# Graphics
npm install @remotion/skia # 2D vector graphics
npm install @remotion/three # 3D with Three.js
npm install @remotion/lottie # Lottie animations
# Rendering
npm install @remotion/lambda # AWS serverless rendering
npm install @remotion/player # Embed in web apps
Full resource list: See references/community-resources.md
Bundled Resources
references/what-is-a-skill.tsx– Full example component from “What Is A Skill” videoreferences/caption-workflow.md– Complete caption integration guide (Whisper, ZapCap, Submagic)references/community-resources.md– Templates, packages, learning path
Related Skills
- video-caption-creation – Captions and hashtags for the rendered video
- youtube-scriptwriting – For longer explainer video scripts
- social-content-creation – Repurpose video concepts to static posts
Version History
-
v1.1 (2026-01-22): Caption & community integration
- Added native Whisper caption workflow via
@remotion/captions - Added caption style presets (minimal, bold, karaoke, brand)
- Added community resources (Discord, templates, packages)
- New reference files:
caption-workflow.md,community-resources.md - Cost comparison: Whisper (free) vs ZapCap ($0.10/min) vs Submagic ($0.69/min)
- Added native Whisper caption workflow via
-
v1.0 (2026-01-21): Initial skill creation
- Risograph visual style
- Animation patterns (spring, interpolate, typewriter)
- Timing guidelines (learned from “too fast” iteration)
- Scene overlap pattern
Videos are code. Version control them, iterate on them, and build a library of reusable components.