
Remotion Spec Translator
- 126 installs
- 37 repo stars
- Updated February 26, 2026
- ncklrs/startup-os-skills
Turn motion-design markdown specs into typed Remotion scene code with springs, timing, and audio wiring.
About
Remotion Spec Translator is an agent skill for solo builders who already wrote animation briefs in markdown and need them turned into working Remotion TypeScript without hand-translating every spring and interpolate block. It packages translation patterns for scene layout, animation conversion, frame timing, and constants extraction, plus implementation guides for Audio timing, staticFile imports, reusable components, and interfaces. Use it when you are building launch videos, product demos, or content pipelines in Remotion and want consistent code from a motion spec instead of ad-hoc chat guesses. The skill emphasizes CRITICAL-impact conversion rules so scale, opacity, and position timelines map cleanly to spring-driven progress values. It suits indie SaaS founders and content-heavy products who treat video as a ship artifact alongside the app.
- Four translation rule sections: scene structure, animation conversion, timing math, and constants extraction
- Four implementation patterns: audio components, staticFile asset imports, reusable components, and TypeScript interfaces
- CRITICAL spring/interpolate recipes for spec phrases like scale 0.8→1.0 with damping configs
- Multi-property entrance patterns combining scale, opacity, and Y offset on frame ranges
- Organizes colors, springs, and frame durations into shared constants during translation
Remotion Spec Translator by the numbers
- 126 all-time installs (skills.sh)
- +2 installs in the week ending Jul 26, 2026 (Skillselion tracking)
- Ranked #764 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ncklrs/startup-os-skills --skill remotion-spec-translatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 126 |
|---|---|
| repo stars | ★ 37 |
| Security audit | 3 / 3 scanners passed |
| Last updated | February 26, 2026 |
| Repository | ncklrs/startup-os-skills ↗ |
What it does
Turn motion-design markdown specs into typed Remotion scene code with springs, timing, and audio wiring.
Files
Remotion Spec Translator
Orchestrates the complete translation pipeline from motion design specifications to working Remotion code. This skill acts as a coordinator that delegates work to specialized skills for each aspect of the translation.
What This Skill Does
Orchestrates the translation by:
1. Coordinating pipeline — Calls specialized skills in correct order 2. Parsing specs — Extracts requirements for each skill 3. Managing handoffs — Ensures output from one skill feeds into next 4. Validating completeness — Confirms all scenes implemented 5. Documenting workflow — Tracks pipeline progress
Scope Boundaries
IN SCOPE:
- Pipeline orchestration and coordination
- Spec parsing and requirement extraction
- Skill delegation and sequencing
- Progress tracking and validation
- Workflow documentation
OUT OF SCOPE:
- Direct code generation (delegated to specialist skills)
- Implementation details (handled by component/animation skills)
- Manual file creation (handled by scaffold skill)
Input/Output Formats
Input Format: VIDEO_SPEC.md
Expects complete motion design specification (from /motion-designer):
# Video Title: ProductDemo
## Overview
- Duration: 30 seconds
- Frame Rate: 30 fps
- Aspect Ratio: 16:9 (1920x1080)
- Total Scenes: 4
## Color Palette
Primary: #FF6B35 - Ember Orange
Secondary: #4ECDC4 - Teal
Background: #0A0A0A - Black
Text: #FFFFFF - White
## Scene 1: Intro (0s - 5s)
Visual Description: Centered logo with smooth entrance
Animation Details:
- Logo: Scale 0.8 → 1.0, Spring (damping: 200)
- Subtitle: Fade in with upward slide
## Scene 2: Features (5s - 15s)
Visual Description: Three feature cards stagger in
Animation Details:
- Cards: Stagger delay 10 frames, slide from left
## Scene 3: Demo (15s - 25s)
Visual Description: Product screenshot with highlights
Animation Details:
- Screenshot: Fade in, scale 0.95 → 1.0
- Highlights: Sequential pulse effect
## Scene 4: CTA (25s - 30s)
Visual Description: Call-to-action with button
Animation Details:
- Text: Fade in
- Button: Scale bounce effect
## Assets
- Logo: public/images/logo.svg (400x400)
- Product screenshot: public/images/product.png (1200x800)Output Format: TRANSLATION_COMPLETE.md
Generates orchestration summary document:
# Translation Complete: ProductDemo
## Status
✅ Pipeline execution complete
✅ All scenes implemented
⏳ Ready for render
## Pipeline Execution Summary
### Step 1: Scaffold Generation (/remotion-scaffold)
✅ Complete
- Created: Project structure
- Output: SCAFFOLD_MANIFEST.md
- Files: index.tsx, constants.ts, types.ts, 4 scene templates
### Step 2: Animation Configuration (/remotion-animation)
✅ Complete
- Created: Animation parameters
- Output: ANIMATION_CONFIG.md
- Configs: Spring settings, interpolations, timing
### Step 3: Composition Structure (/remotion-composition)
✅ Complete
- Created: Sequence layout
- Output: COMPOSITION_STRUCTURE.md
- Timing: All scene durations calculated
### Step 4: Scene Implementation (/remotion-component-gen)
✅ Complete - 4/4 scenes
- Scene 1 (Intro): SCENE_COMPONENT.md → Scene1Intro.tsx
- Scene 2 (Features): SCENE_COMPONENT.md → Scene2Features.tsx
- Scene 3 (Demo): SCENE_COMPONENT.md → Scene3Demo.tsx
- Scene 4 (CTA): SCENE_COMPONENT.md → Scene4CTA.tsx
### Step 5: Render Configuration (/remotion-render-config)
✅ Complete
- Created: Render settings
- Output: RENDER_CONFIG.md
- Target: YouTube (H.264, CRF 18)
## Generated Files
src/remotion/compositions/ProductDemo/ ├── index.tsx # ✅ Composition with all scenes ├── constants.ts # ✅ Colors, springs, timing ├── types.ts # ✅ TypeScript interfaces └── scenes/ ├── Scene1Intro.tsx # ✅ Implemented ├── Scene2Features.tsx # ✅ Implemented ├── Scene3Demo.tsx # ✅ Implemented └── Scene4CTA.tsx # ✅ Implemented
## Next Steps
1. **Add assets** to public/ folders
- Logo: public/images/logo.svg
- Product screenshot: public/images/product.png
2. **Test in preview**npm run dev
3. **Verify timing** matches spec exactly
4. **Run render** when readynpm run render:youtube
5. **Review and iterate** if adjustments needed
## Asset Checklist
Required assets from spec:
- [ ] public/images/logo.svg (400x400)
- [ ] public/images/product.png (1200x800)
Use `/remotion-asset-coordinator` for asset sourcing guidance.
## Quality Checklist
- [x] All scenes implemented
- [x] Timing matches spec
- [x] Animations configured
- [x] Colors from palette applied
- [x] Composition structure complete
- [ ] Assets added
- [ ] Preview tested
- [ ] Final render complete
## Translation Summary
**Input:** VIDEO_SPEC.md (motion design specification)
**Pipeline:** 5 specialized skills executed in sequence
**Output:** Complete, working Remotion composition
**Status:** Implementation complete, assets and testing pendingOrchestration Workflow
The pipeline executes in this sequence:
VIDEO_SPEC.md (Input)
↓
Step 1: /remotion-scaffold
↓ outputs: SCAFFOLD_MANIFEST.md + folder structure
Step 2: /remotion-animation
↓ outputs: ANIMATION_CONFIG.md + animation constants
Step 3: /remotion-composition
↓ outputs: COMPOSITION_STRUCTURE.md + Sequence layout
Step 4: /remotion-component-gen (per scene)
↓ outputs: SCENE_COMPONENT.md × N scenes
Step 5: /remotion-render-config
↓ outputs: RENDER_CONFIG.md + render commands
↓
TRANSLATION_COMPLETE.md (Output)Skill Delegation Strategy
When to Delegate
1. Parse spec → Extract requirements for each skill 2. Check dependencies → Ensure prerequisites met 3. Call skill → Provide focused input 4. Capture output → Store for next skill 5. Validate → Confirm output quality 6. Proceed → Move to next step
Delegation Examples
// Step 1: Scaffold
const scaffoldInput = {
projectName: "ProductDemo",
duration: 30,
fps: 30,
dimensions: "1920x1080",
scenes: ["Intro", "Features", "Demo", "CTA"]
};
// Call: /remotion-scaffold
// Step 2: Animation
const animationInput = {
springConfigs: extractSpringConfigs(spec),
interpolations: extractInterpolations(spec),
timing: extractAnimationTiming(spec)
};
// Call: /remotion-animation
// Step 3: Composition
const compositionInput = {
scenes: [
{ name: "intro", durationSeconds: 5 },
{ name: "features", durationSeconds: 10 },
{ name: "demo", durationSeconds: 10 },
{ name: "cta", durationSeconds: 5 }
],
fps: 30
};
// Call: /remotion-composition
// Step 4: Component Gen (per scene)
for (const scene of spec.scenes) {
const componentInput = {
sceneName: scene.name,
visualDescription: scene.visual,
animationDetails: scene.animation,
assets: scene.assets
};
// Call: /remotion-component-gen
}
// Step 5: Render Config
const renderInput = {
platform: "YouTube",
quality: "high",
format: "MP4"
};
// Call: /remotion-render-configSpec Parsing Helpers
Extract Spring Configs
function extractSpringConfigs(spec: string) {
// Parse animation details for spring parameters
// Look for: damping, stiffness, mass values
// Return: SPRING_CONFIGS object
}Extract Scene Timing
function extractSceneTiming(spec: string) {
// Parse scene headers for timing (0s - 5s)
// Calculate frame numbers
// Return: Scene timing array
}Extract Color Palette
function extractColorPalette(spec: string) {
// Parse Color Palette section
// Extract hex codes and names
// Return: COLORS object
}Extract Asset List
function extractAssets(spec: string) {
// Parse Assets sections per scene
// Collect all required assets
// Return: Asset checklist
}Progress Tracking
The orchestrator tracks pipeline progress:
Pipeline Progress: ProductDemo
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Step 1/5: Scaffold (remotion-scaffold)
✅ Step 2/5: Animation (remotion-animation)
✅ Step 3/5: Composition (remotion-composition)
⏳ Step 4/5: Scenes (remotion-component-gen) - 2/4 complete
⬜ Step 5/5: Render Config (remotion-render-config)
Current: Implementing Scene 3 (Demo)
Next: Scene 4 (CTA)Error Handling
Missing Information
If spec lacks required information:
- Identify gap (e.g., missing spring config)
- Use sensible defaults where possible
- Document assumption in output
- Flag for review by user
Skill Failures
If a delegated skill fails:
- Log error with context
- Attempt recovery if possible
- Skip to next step if non-blocking
- Report issue in final summary
Incomplete Specs
If spec is incomplete:
- Parse what's available
- Generate with TODO markers
- List missing requirements
- Suggest spec improvements
Validation Checklist
Before marking translation complete:
- [ ] All scenes from spec have components
- [ ] Animation configs match spec parameters
- [ ] Scene timing adds up to total duration
- [ ] Color palette extracted and applied
- [ ] Asset list generated
- [ ] Render config targets correct platform
- [ ] No TODO markers in critical sections
Best Practices
1. Parse thoroughly — Extract all details from spec 2. Delegate appropriately — Use right skill for each task 3. Maintain context — Pass relevant info between skills 4. Validate outputs — Check each skill's result 5. Document clearly — Explain what was done 6. Track progress — Show pipeline status 7. Handle errors — Gracefully manage failures
Integration with Other Skills
This skill orchestrates the pipeline:
remotion-spec-translator (this skill - ORCHESTRATOR)
↓ coordinates
remotion-scaffold → remotion-animation → remotion-composition → remotion-component-gen → remotion-render-configWorks with:
/motion-designer— Consumes VIDEO_SPEC.md from this skill/remotion-scaffold— Delegates scaffolding/remotion-animation— Delegates animation config/remotion-composition— Delegates composition structure/remotion-component-gen— Delegates scene implementation (per scene)/remotion-render-config— Delegates render settings
Triggers:
- "Translate spec to code"
- "Implement video spec"
- "Generate Remotion from spec"
- "Build Remotion project from design"
---
This skill ensures motion design specs translate systematically into complete, working Remotion projects through intelligent orchestration and delegation.
Rule Sections
Translation Patterns
- scene-structure.md — Scene component structure and layout patterns
- animation-conversion.md — Converting animation descriptions to spring/interpolate code
- timing-calculations.md — Frame timing and duration calculations
- constants-extraction.md — Organizing colors, springs, and timing constants
Implementation Patterns
- audio-implementation.md — Generating Audio components with proper timing
- asset-imports.md — Import statements and staticFile usage
- reusable-components.md — Extracting reusable components during translation
- typescript-types.md — Generating proper TypeScript interfaces
Animation Spec to Code Conversion
Impact: CRITICAL
Converting motion design animation descriptions into working spring and interpolate code.
Spring Animation Pattern
Spec Description:
Element scales from 0.8 to 1.0 with smooth spring
Spring config: { damping: 200 }Code Translation:
const elementProgress = spring({
frame,
fps,
config: { damping: 200 },
});
const scale = interpolate(elementProgress, [0, 1], [0.8, 1]);
<div style={{
transform: `scale(${scale})`,
}} />Multi-Property Animations
Spec:
Logo entrance:
- Scale: 0.8 → 1.0
- Opacity: 0 → 1
- Y position: 50px → 0px
Timing: 0-30 frames
Spring: { damping: 200 }Code:
const logoProgress = spring({
frame,
fps,
config: { damping: 200 },
});
const scale = interpolate(logoProgress, [0, 1], [0.8, 1]);
const opacity = logoProgress; // 0 to 1 naturally
const y = interpolate(logoProgress, [0, 1], [50, 0]);
<div style={{
transform: `scale(${scale}) translateY(${y}px)`,
opacity,
}} />Delayed Animations
Spec:
Title appears after 30 frame delayCode:
const titleProgress = spring({
frame: frame - 30,
fps,
config: SPRING_CONFIGS.smooth,
});
// Progress will be 0 until frame 30, then animateHold and Exit Pattern
Spec:
Element behavior:
- Frames 0-30: Enter
- Frames 30-120: Hold
- Frames 120-135: ExitCode:
// Entrance
const enterProgress = spring({
frame,
fps,
config: SPRING_CONFIGS.smooth,
});
// Exit
const exitProgress = spring({
frame: frame - 120,
fps,
config: SPRING_CONFIGS.smooth,
});
// Combine: fade in, hold, fade out
const opacity = frame < 120
? enterProgress
: 1 - exitProgress;Easing vs Spring
When spec says "smooth ease":
// Use interpolate with easing
const progress = frame / totalFrames;
const eased = Easing.inOut(Easing.cubic)(progress);
const x = interpolate(eased, [0, 1], [0, 1000]);When spec says "spring" or "bounce":
// Use spring
const progress = spring({
frame,
fps,
config: { damping: 20, stiffness: 200 }, // bouncy
});Continuous Animations
Spec:
Element rotates continuouslyCode:
// Linear rotation, no spring
const rotation = (frame * 2) % 360; // 2 degrees per frame
<div style={{
transform: `rotate(${rotation}deg)`,
}} />Oscillating Animations
Spec:
Element pulses between 0.9 and 1.1 scaleCode:
const pulse = Math.sin(frame * 0.1) * 0.1 + 1;
// Oscillates: 0.9 → 1.0 → 1.1 → 1.0 → 0.9
<div style={{
transform: `scale(${pulse})`,
}} />Sequence Timing
Spec:
Three elements stagger in:
- Element 1 at frame 0
- Element 2 at frame 15
- Element 3 at frame 30Code:
const elements = [
{ text: 'First', delay: 0 },
{ text: 'Second', delay: 15 },
{ text: 'Third', delay: 30 },
];
{elements.map((el, i) => {
const progress = spring({
frame: frame - el.delay,
fps,
config: SPRING_CONFIGS.smooth,
});
return (
<div key={i} style={{ opacity: progress }}>
{el.text}
</div>
);
})}Path Animations
Spec:
Element follows arc from (0, 0) to (500, 300)Code:
const progress = spring({
frame,
fps,
config: SPRING_CONFIGS.smooth,
});
// Arc calculation
const x = interpolate(progress, [0, 1], [0, 500]);
const y = interpolate(progress, [0, 1], [0, 300]) +
Math.sin(progress * Math.PI) * 100; // Arc height
<div style={{
transform: `translate(${x}px, ${y}px)`,
}} />Common Spring Configs
Map spec descriptions to configs:
| Spec Description | Spring Config | Use Case |
|---|---|---|
| "smooth", "elegant" | { damping: 200 } | Refined animations |
| "snappy", "quick" | { damping: 20, stiffness: 200 } | UI interactions |
| "bouncy", "playful" | { damping: 8 } | Energetic entrances |
| "heavy", "dramatic" | { damping: 15, stiffness: 80, mass: 2 } | Big reveals |
| "subtle", "gentle" | { damping: 300 } | Background elements |
Animation Checklist
When converting animation specs:
- [ ] Identify animation type (spring vs easing vs continuous)
- [ ] Extract timing values to frame calculations
- [ ] Create progress variable with spring/interpolate
- [ ] Apply progress to correct CSS properties
- [ ] Handle delays with frame offsets
- [ ] Use appropriate spring config from constants
- [ ] Combine multiple properties on same progress
- [ ] Add comments referencing spec timing
- [ ] Test edge cases (frame 0, last frame)
Constants Organization and Extraction
Impact: HIGH
Proper organization of colors, spring configurations, and timing values in dedicated constants sections.
Color Palette Constants
Spec:
## Color Palette
Primary: #FF6B35 - Ember Orange
Secondary: #A855F7 - Purple
Background: #0A0A0A - Black
Text: #FFFFFF - White
Accent: #22C55E - EmeraldCode:
// ============================================
// COLOR PALETTE
// ============================================
const COLORS = {
primary: '#FF6B35', // Ember Orange
secondary: '#A855F7', // Purple
background: '#0A0A0A', // Black
text: '#FFFFFF', // White
accent: '#22C55E', // Emerald
} as const;Extended Color Palette
For complex palettes with shades:
const COLORS = {
// Base colors
background: '#0a0a0a',
charcoal: '#171717',
slate: '#262626',
silver: '#a3a3a3',
white: '#ffffff',
// Brand colors
emberOrange: '#ff6b35',
flameOrange: '#ff8c42',
goldenOrange: '#ffb347',
// Accent colors
purple: '#a855f7',
emerald: '#22c55e',
recordRed: '#ef4444',
} as const;Spring Configuration Constants
Spec:
## Spring Configurations
Smooth: { damping: 200 } - elegant transitions
Snappy: { damping: 20, stiffness: 200 } - UI elements
Bouncy: { damping: 8 } - playful animationsCode:
// ============================================
// SPRING CONFIGURATIONS
// ============================================
const SPRING_CONFIGS = {
smooth: { damping: 200 },
snappy: { damping: 20, stiffness: 200 },
bouncy: { damping: 8 },
} as const;
// OR with descriptive names
const SMOOTH_SPRING = { damping: 200 };
const SNAPPY_SPRING = { damping: 20, stiffness: 200 };
const BOUNCY_SPRING = { damping: 8 };Scene Timing Constants
Spec:
Scene 1: Intro (0s - 5s)
Scene 2: Demo (5s - 15s)
Scene 3: CTA (15s - 20s)Code:
// ============================================
// SCENE TIMING CONSTANTS
// ============================================
const SCENE_TIMING = {
scene1: { start: 0, end: 150, duration: 150 }, // 0-5s
scene2: { start: 150, end: 450, duration: 300 }, // 5-15s
scene3: { start: 450, end: 600, duration: 150 }, // 15-20s
} as const;Animation Duration Constants
Extract common durations:
// ============================================
// ANIMATION CONSTANTS
// ============================================
const ANIMATION = {
transitionDuration: 15, // 0.5s
staggerDelay: 10, // 0.33s
holdDuration: 90, // 3s
fadeInDuration: 30, // 1s
} as const;Typography Constants
Spec:
## Typography
Headline: Inter, 64px, Bold
Subheadline: Inter, 32px, SemiBold
Body: Inter, 18px, RegularCode:
// ============================================
// TYPOGRAPHY CONSTANTS
// ============================================
const TYPOGRAPHY = {
headline: {
fontSize: 64,
fontWeight: 700,
fontFamily: 'Inter, sans-serif',
},
subheadline: {
fontSize: 32,
fontWeight: 600,
fontFamily: 'Inter, sans-serif',
},
body: {
fontSize: 18,
fontWeight: 400,
fontFamily: 'Inter, sans-serif',
},
} as const;Layout Constants
For positioning and sizing:
// ============================================
// LAYOUT CONSTANTS
// ============================================
const LAYOUT = {
padding: {
small: 16,
medium: 32,
large: 64,
},
spacing: {
tight: 8,
normal: 16,
relaxed: 24,
},
borderRadius: {
small: 4,
medium: 8,
large: 12,
},
} as const;Asset Path Constants
// ============================================
// ASSET PATHS
// ============================================
const ASSETS = {
logo: 'logo.svg',
backgroundMusic: 'background-music.mp3',
whooshSfx: 'whoosh.mp3',
productImage: 'product.jpg',
} as const;Placement in File
Organize constants at the top of the file:
import {
AbsoluteFill,
spring,
useCurrentFrame,
useVideoConfig,
Sequence,
} from "remotion";
// ============================================
// TYPE DEFINITIONS
// ============================================
export interface VideoNameProps {}
// ============================================
// COLOR PALETTE
// ============================================
const COLORS = { ... } as const;
// ============================================
// SPRING CONFIGURATIONS
// ============================================
const SPRING_CONFIGS = { ... } as const;
// ============================================
// SCENE TIMING CONSTANTS
// ============================================
const SCENE_TIMING = { ... } as const;
// ============================================
// UTILITY FUNCTIONS
// ============================================
const seededRandom = (seed: number) => { ... };
// ============================================
// REUSABLE COMPONENTS
// ============================================
function ParticleSystem() { ... }
// ============================================
// SCENE COMPONENTS
// ============================================
function Scene1() { ... }
// ============================================
// MAIN COMPOSITION
// ============================================
export function VideoName() { ... }Using Constants
Reference constants consistently:
// Good - using constants
<AbsoluteFill style={{ backgroundColor: COLORS.background }}>
<div
style={{
fontSize: TYPOGRAPHY.headline.fontSize,
color: COLORS.primary,
}}
>
{/* Content */}
</div>
</AbsoluteFill>
const progress = spring({
frame,
fps,
config: SPRING_CONFIGS.smooth,
});
// Bad - hardcoded values
<AbsoluteFill style={{ backgroundColor: '#0A0A0A' }}>
<div
style={{
fontSize: 64,
color: '#FF6B35',
}}
>
{/* Content */}
</div>
</AbsoluteFill>
const progress = spring({
frame,
fps,
config: { damping: 200 },
});Constants Checklist
When extracting constants from spec:
- [ ] All colors in COLORS constant with descriptive names
- [ ] Spring configs in SPRING_CONFIGS or individual constants
- [ ] Scene timing in SCENE_TIMING with start/duration/end
- [ ] Common animation durations extracted
- [ ] Typography styles in TYPOGRAPHY constant
- [ ] Asset paths in ASSETS constant
- [ ] Constants placed before components
- [ ] All constants use
as constfor type safety - [ ] Constants have inline comments matching spec
- [ ] Sections separated with comment dividers
Scene Component Structure
Impact: CRITICAL
Every scene in a motion design spec must translate to a properly structured Remotion scene component.
Core Pattern
Each scene component follows this structure:
function SceneNName() {
const frame = useCurrentFrame();
const { fps, width, height } = useVideoConfig();
// Animation progress calculations
const progress = spring({
frame,
fps,
config: SPRING_CONFIGS.configName,
});
// Element-specific animations
const element1Progress = spring({
frame: frame - delayFrames,
fps,
config: SPRING_CONFIGS.configName,
});
return (
<AbsoluteFill style={{ backgroundColor: COLORS.background }}>
{/* Background layer */}
<div>{/* Background elements */}</div>
{/* Midground layer */}
<div>{/* Primary content */}</div>
{/* Foreground layer */}
<div>{/* Overlay elements */}</div>
</AbsoluteFill>
);
}Naming Convention
From spec scene name to component name:
Spec:
## Scene 1: Logo Reveal (0s - 5s)
## Scene 2: Product Showcase (5s - 15s)Code:
function Scene1LogoReveal() { }
function Scene2ProductShowcase() { }Pattern: Scene[N][PascalCaseName]
Layer Organization
Organize elements by visual depth:
<AbsoluteFill style={{ backgroundColor: COLORS.background }}>
{/* BACKGROUND LAYER - slowest movement, deepest */}
<div style={{ position: 'absolute', ... }}>
{/* Gradients, patterns, ambient elements */}
</div>
{/* MIDGROUND LAYER - primary content */}
<div style={{ position: 'absolute', ... }}>
{/* Main UI, text, key visuals */}
</div>
{/* FOREGROUND LAYER - fastest movement, closest */}
<div style={{ position: 'absolute', ... }}>
{/* Overlays, particles, focal elements */}
</div>
</AbsoluteFill>State Management
Extract animation progress variables:
// Good - reusable progress
const titleProgress = spring({
frame: frame - 30,
fps,
config: SPRING_CONFIGS.smooth,
});
const titleOpacity = titleProgress;
const titleY = interpolate(titleProgress, [0, 1], [50, 0]);
<div style={{
opacity: titleOpacity,
transform: `translateY(${titleY}px)`,
}}>
{title}
</div>
// Bad - repeated calculations
<div style={{
opacity: spring({ frame: frame - 30, fps, config: { damping: 200 } }),
transform: `translateY(${interpolate(
spring({ frame: frame - 30, fps, config: { damping: 200 } }),
[0, 1],
[50, 0]
)}px)`,
}}>
{title}
</div>Delayed Animations
Handle staggered entrances:
// Spec: "Elements stagger in with 10 frame delays"
const elements = ['Item 1', 'Item 2', 'Item 3'];
{elements.map((text, index) => {
const delay = index * 10;
const elementProgress = spring({
frame: frame - delay,
fps,
config: SPRING_CONFIGS.smooth,
});
return (
<div
key={index}
style={{
opacity: elementProgress,
transform: `translateX(${interpolate(
elementProgress,
[0, 1],
[-30, 0]
)}px)`,
}}
>
{text}
</div>
);
})}Scene Dimensions
Use VideoConfig for responsive positioning:
function Scene1() {
const { width, height } = useVideoConfig();
return (
<AbsoluteFill>
{/* Center element */}
<div style={{
position: 'absolute',
left: width / 2,
top: height / 2,
transform: 'translate(-50%, -50%)',
}}>
Centered
</div>
{/* Percentage-based positioning */}
<div style={{
position: 'absolute',
left: width * 0.2,
top: height * 0.3,
}}>
20% from left, 30% from top
</div>
</AbsoluteFill>
);
}Checklist
When translating scene specs to components:
- [ ] Component name matches spec scene name
- [ ] Uses AbsoluteFill as root wrapper
- [ ] Destructures frame, fps, width, height from hooks
- [ ] Animation progress variables are extracted
- [ ] Elements organized by visual depth layers
- [ ] Delayed animations use frame offsets
- [ ] Positions use width/height from VideoConfig
- [ ] Background color from COLORS constant
- [ ] Spring configs from SPRING_CONFIGS constant
- [ ] Comments reference spec sections
Frame Timing and Duration Calculations
Impact: CRITICAL
Accurate conversion of seconds to frames and proper timing calculations for Remotion.
Basic Conversion Formula
// Seconds to frames: seconds * fps
const durationInFrames = seconds * 30; // assuming 30 fps
// Example: 5 seconds = 150 frames
const fiveSeconds = 5 * 30; // 150 framesScene Timing Constant Pattern
Spec:
Scene 1: Logo (0s - 5s, Duration: 5s)
Scene 2: Product (5s - 15s, Duration: 10s)
Scene 3: CTA (15s - 20s, Duration: 5s)Code:
const SCENE_TIMING = {
scene1: { start: 0, end: 150, duration: 150 }, // 0-5s
scene2: { start: 150, end: 450, duration: 300 }, // 5-15s
scene3: { start: 450, end: 600, duration: 150 }, // 15-20s
} as const;
// Usage in Sequence
<Sequence
from={SCENE_TIMING.scene1.start}
durationInFrames={SCENE_TIMING.scene1.duration}
>
<Scene1 />
</Sequence>Calculating Scene Timing
Pattern for generating timing constants:
// Given: Scene starts at X seconds, duration Y seconds, fps 30
const fps = 30;
const sceneStart = startSeconds * fps;
const sceneDuration = durationSeconds * fps;
const sceneEnd = sceneStart + sceneDuration;
// Example: Scene starts at 5s, lasts 10s
const scene2 = {
start: 5 * 30, // 150
duration: 10 * 30, // 300
end: 150 + 300, // 450
};Sub-Scene Timing
For animations within scenes:
Spec:
Scene 1 (0-5s):
- Title enters: 0-1s
- Subtitle enters: 1-2s
- Logo enters: 2-3s
- Hold: 3-5sCode:
function Scene1() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Scene-relative timing (frame 0 is scene start)
const titleEnterEnd = 1 * fps; // 30 frames
const subtitleEnterEnd = 2 * fps; // 60 frames
const logoEnterEnd = 3 * fps; // 90 frames
// Title animation (0-30 frames)
const titleProgress = spring({
frame: Math.min(frame, titleEnterEnd),
fps,
config: SPRING_CONFIGS.smooth,
});
// Subtitle animation (30-60 frames)
const subtitleProgress = spring({
frame: frame - titleEnterEnd,
fps,
config: SPRING_CONFIGS.smooth,
});
// Logo animation (60-90 frames)
const logoProgress = spring({
frame: frame - subtitleEnterEnd,
fps,
config: SPRING_CONFIGS.smooth,
});
return (
<AbsoluteFill>
{/* Elements with calculated timing */}
</AbsoluteFill>
);
}Transition Overlap Timing
Spec:
Scene 1 fades out while Scene 2 fades in
Overlap duration: 0.5s (15 frames)Code:
const TRANSITION_DURATION = 0.5 * 30; // 15 frames
const SCENE_TIMING = {
scene1: {
start: 0,
duration: 150 + TRANSITION_DURATION, // Extend for fade out
},
scene2: {
start: 150 - TRANSITION_DURATION, // Start early for fade in
duration: 300 + TRANSITION_DURATION,
},
};
// In Scene1
const fadeOut = spring({
frame: frame - (150 - TRANSITION_DURATION),
fps,
config: SPRING_CONFIGS.smooth,
});
const opacity = 1 - fadeOut;
// In Scene2
const fadeIn = spring({
frame,
fps,
config: SPRING_CONFIGS.smooth,
});
const opacity = fadeIn;Delay Calculations
Spec:
Elements appear with 0.5s stagger delayCode:
const STAGGER_DELAY = 0.5 * fps; // 15 frames
elements.map((el, index) => {
const delay = index * STAGGER_DELAY;
const progress = spring({
frame: frame - delay,
fps,
config: SPRING_CONFIGS.smooth,
});
// Element renders
});Hold Pattern
Spec:
Element holds for 3 seconds after entranceCode:
const ENTRANCE_DURATION = 1 * fps; // 30 frames
const HOLD_DURATION = 3 * fps; // 90 frames
const HOLD_END = ENTRANCE_DURATION + HOLD_DURATION; // 120 frames
const enterProgress = spring({
frame: Math.min(frame, ENTRANCE_DURATION),
fps,
config: SPRING_CONFIGS.smooth,
});
// Element visible from frame 0 to HOLD_END
const isVisible = frame <= HOLD_END;BPM to Frame Timing
Spec:
Background music: 120 BPM
Sync animations to beatsCode:
const BPM = 120;
const fps = 30;
// Frames per beat
const framesPerBeat = (60 / BPM) * fps;
// 120 BPM = 2 beats/sec = 0.5 sec/beat = 15 frames/beat
// Animation on every beat
const beatNumber = Math.floor(frame / framesPerBeat);
const beatProgress = (frame % framesPerBeat) / framesPerBeat;
// Pulse on each beat
const pulse = beatProgress < 0.3
? interpolate(beatProgress, [0, 0.3], [1, 1.2])
: interpolate(beatProgress, [0.3, 1], [1.2, 1]);Duration from Spec
Extract total duration:
Spec:
## Overview
- Duration: 30 seconds
- Frame Rate: 30 fpsCode:
// In composition registry
{
id: 'video-name',
component: VideoName,
durationInFrames: 30 * 30, // 900 frames
fps: 30,
width: 1920,
height: 1080,
}Timing Checklist
When converting time specs to code:
- [ ] All durations in seconds converted to frames (seconds * fps)
- [ ] Scene timing constants use start/duration/end pattern
- [ ] Delays calculated as frame offsets
- [ ] Transitions account for overlap
- [ ] BPM converted to frames per beat if audio synced
- [ ] Hold durations properly calculated
- [ ] Frame 0 handled correctly (animations start from 0)
- [ ] Total composition duration matches spec
- [ ] Comments show both seconds and frames
- [ ] Constants use const fps = 30 for clarity
Related skills
FAQ
Is Remotion Spec Translator safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.