Remotion Composition
Generates composition structure documents that define how scenes are ordered, timed, and transitioned in a Remotion video. This skill focuses exclusively on Sequence layout and timing orchestration.
What This Skill Does
Generates composition structure for:
Sequence layout — Ordering and positioning of scene Sequences Timing calculations — Start frames, end frames, duration for each scene Scene transitions — Overlap and crossfade timing between scenes Duration mapping — Converting seconds to frames for all scenes Timing constants — Structured timing object for constants.ts Scope Boundaries
IN SCOPE:
Sequence component organization Frame calculations for scene timing Scene overlap and transition timing Duration constant generation Scene ordering logic
OUT OF SCOPE:
Scene component implementation (use /remotion-component-gen) Animation parameters (use /remotion-animation) Visual styling (colors, layouts) Asset management (use /remotion-asset-coordinator) Input/Output Formats Input Format: Scene List with Durations
Accepts scene timing specifications:
Natural Language:
Scene 1 (Intro): 0-5 seconds Scene 2 (Features): 5-15 seconds Scene 3 (Demo): 15-25 seconds Scene 4 (CTA): 25-30 seconds
Structured Format:
Scene Timing
Total Duration: 30 seconds Frame Rate: 30 fps Total Frames: 900
Scenes: 1. Scene 1 - Intro: 5 seconds (0s - 5s) 2. Scene 2 - Features: 10 seconds (5s - 15s) 3. Scene 3 - Demo: 10 seconds (15s - 25s) 4. Scene 4 - CTA: 5 seconds (25s - 30s)
Transitions: - Fade transition between scenes: 0.5 seconds (15 frames)
Output Format: COMPOSITION_STRUCTURE.md
Generates composition structure document:
Composition Structure: ProductDemo
Status
✅ Sequence layout defined ✅ Timing calculations complete ⏳ Ready for scene implementation
Composition Overview
Total Duration: 30 seconds (900 frames @ 30fps) Scenes: 4 Transitions: Crossfade (15 frames)
Scene Timing Constants
```typescript const FPS = 30;
export const SCENE_TIMING = { intro: { start: 0, end: 150, duration: 150, // 0s - 5s }, features: { start: 150, end: 450, duration: 300, // 5s - 15s }, demo: { start: 450, end: 750, duration: 300, // 15s - 25s }, cta: { start: 750, end: 900, duration: 150, // 25s - 30s }, } as const;
// Transition timing export const TRANSITIONS = { crossfadeDuration: 15, // frames (0.5 seconds) } as const;
Composition Layout
Main composition with Sequence structure:
import { AbsoluteFill, Sequence } from "remotion"; import { SCENE_TIMING } from "./constants"; import { Scene1Intro } from "./scenes/Scene1Intro"; import { Scene2Features } from "./scenes/Scene2Features"; import { Scene3Demo } from "./scenes/Scene3Demo"; import { Scene4CTA } from "./scenes/Scene4CTA";
export function ProductDemo() {
return (
{/* Scene 2: Features (5s - 15s) */}
<Sequence
from={SCENE_TIMING.features.start}
durationInFrames={SCENE_TIMING.features.duration}
>
<Scene2Features />
</Sequence>
{/* Scene 3: Demo (15s - 25s) */}
<Sequence
from={SCENE_TIMING.demo.start}
durationInFrames={SCENE_TIMING.demo.duration}
>
<Scene3Demo />
</Sequence>
{/* Scene 4: CTA (25s - 30s) */}
<Sequence
from={SCENE_TIMING.cta.start}
durationInFrames={SCENE_TIMING.cta.duration}
>
<Scene4CTA />
</Sequence>
</AbsoluteFill>
); }
Scene Timing Breakdown Scene Name Duration Frames Start Frame End Frame 1 Intro 5s 150 0 150 2 Features 10s 300 150 450 3 Demo 10s 300 450 750 4 CTA 5s 150 750 900
Total: 30 seconds (900 frames)
Timeline Visualization Frame: 0 150 450 750 900 Time: 0s 5s 15s 25s 30s |---------|---------|---------|---------| Scene: | Intro | Features| Demo | CTA | |---------|---------|---------|---------|
Next Steps Implement scenes via /remotion-component-gen Add transitions if needed (crossfades, wipes) Integrate constants into composition constants.ts Test timing in Remotion preview Adjust durations if scenes feel too fast/slow Checklist Scene timing calculated Sequence layout defined Constants generated Timing constants structured Scene components implemented (next step) Transitions added (if needed) Timing tested in preview
Composition Patterns
Pattern 1: Sequential Scenes (No Overlap)
Standard sequential layout where scenes don't overlap:
```typescript
Pattern 2: Overlapping Scenes (Crossfade)
Scenes overlap for smooth transitions:
const CROSSFADE = 15; // frames
// Scene 1: Full duration
// Scene 2: Starts before Scene 1 ends
// Scene 3: Starts before Scene 2 ends
Pattern 3: Layered Composition
Background + foreground scenes running simultaneously:
{/ Background layer - runs full duration /}
{/ Foreground scenes - sequential /}
Pattern 4: Nested Sequences
Sub-scenes within main scenes:
{/* Sub-scene 2 */}
<Sequence from={100} durationInFrames={200}>
<MainContent />
</Sequence>
Timing Calculation Helpers
Common frame calculations:
// Convert seconds to frames const secondsToFrames = (seconds: number, fps: number = 30): number => Math.round(seconds * fps);
// Calculate scene timing interface SceneTiming { start: number; end: number; duration: number; }
const calculateSceneTiming = ( startSeconds: number, durationSeconds: number, fps: number = 30 ): SceneTiming => { const start = secondsToFrames(startSeconds, fps); const duration = secondsToFrames(durationSeconds, fps); const end = start + duration;
return { start, end, duration }; };
// Calculate crossfade overlap const calculateCrossfade = ( scene1Start: number, scene1Duration: number, crossfadeDuration: number ) => ({ scene1: { from: scene1Start, durationInFrames: scene1Duration, }, scene2: { from: scene1Start + scene1Duration - crossfadeDuration, durationInFrames: crossfadeDuration, // or more if scene is longer }, });
// Validate total duration const validateDuration = ( scenes: SceneTiming[], expectedTotal: number ): boolean => { const lastScene = scenes[scenes.length - 1]; return lastScene.end === expectedTotal; };
Scene Timing Generation
Automated timing generation from scene list:
interface SceneSpec { name: string; durationSeconds: number; }
const generateSceneTiming = (
scenes: SceneSpec[],
fps: number = 30
) => {
let currentFrame = 0;
const timing: Record
for (const scene of scenes) { const duration = secondsToFrames(scene.durationSeconds, fps);
timing[scene.name] = {
start: currentFrame,
end: currentFrame + duration,
duration,
};
currentFrame += duration;
}
return { timing, totalFrames: currentFrame, totalSeconds: currentFrame / fps, }; };
// Usage: const scenes = [ { name: 'intro', durationSeconds: 5 }, { name: 'features', durationSeconds: 10 }, { name: 'demo', durationSeconds: 10 }, { name: 'cta', durationSeconds: 5 }, ];
const result = generateSceneTiming(scenes, 30); // Result: // { // timing: { // intro: { start: 0, end: 150, duration: 150 }, // features: { start: 150, end: 450, duration: 300 }, // ... // }, // totalFrames: 900, // totalSeconds: 30, // }
Transition Patterns Crossfade Transition
Smooth opacity crossfade between scenes:
const CROSSFADE = 15;
// Scene 1 - fades out at end
// Scene 2 - fades in at start
// In Scene component: function Scene1({ crossfadeOut = 0 }) { const frame = useCurrentFrame(); const { durationInFrames } = useVideoConfig();
const opacity = crossfadeOut > 0 ? interpolate( frame, [durationInFrames - crossfadeOut, durationInFrames], [1, 0], { extrapolateRight: 'clamp' } ) : 1;
return
Hard Cut Transition
No transition, instant scene change:
Slide Transition
One scene slides out while next slides in:
const TRANSITION_DURATION = 20;
Duration Validation
Ensuring timing adds up correctly:
// Validation helper
const validateCompositionTiming = (
scenes: Record
// Check for gaps const sceneList = Object.entries(scenes).sort((a, b) => a[1].start - b[1].start);
for (let i = 0; i < sceneList.length - 1; i++) { const currentEnd = sceneList[i][1].end; const nextStart = sceneList[i + 1][1].start;
if (nextStart > currentEnd) {
issues.push(`Gap detected: ${currentEnd} to ${nextStart} (${(nextStart - currentEnd) / fps}s)`);
}
if (nextStart < currentEnd) {
issues.push(`Overlap detected: ${sceneList[i][0]} and ${sceneList[i + 1][0]}`);
}
}
// Check total duration
const lastScene = sceneList[sceneList.length - 1][1];
if (lastScene.end !== expectedDuration) {
issues.push(
Total duration mismatch: expected ${expectedDuration}, got ${lastScene.end} (${lastScene.end / fps}s)
);
}
return { valid: issues.length === 0, issues, }; };
Timeline Visualization Helper
Generate ASCII timeline:
const generateTimeline = (
scenes: Record
const timeline: string[] = [];
// Frame markers const frameMarkers = Array.from({ length: width + 1 }, (_, i) => { const frame = Math.round((i / width) * lastScene); return frame.toString().padStart(4); }).join(''); timeline.push('Frame: ' + frameMarkers);
// Time markers const timeMarkers = Array.from({ length: width + 1 }, (_, i) => { const time = ((i / width) * lastScene) / fps; return time.toFixed(1) + 's'; }).join(' '); timeline.push('Time: ' + timeMarkers);
// Scene bars
for (const [name, timing] of Object.entries(scenes)) {
const startPos = Math.round((timing.start / lastScene) * width);
const endPos = Math.round((timing.end / lastScene) * width);
const bar = ' '.repeat(startPos) + '|' + '='.repeat(endPos - startPos - 1) + '|';
timeline.push(${name.padEnd(8)}: ${bar});
}
return timeline.join('\n'); };
Best Practices Timing Guidelines // Minimum scene duration for readability const MIN_SCENE_DURATION = 30; // 1 second at 30fps
// Standard transition duration const STANDARD_TRANSITION = 15; // 0.5 seconds
// Maximum scene duration before pacing feels slow const MAX_SCENE_DURATION = 600; // 20 seconds
// Recommended scene duration range const IDEAL_SCENE_DURATION = { min: 60, // 2 seconds max: 300, // 10 seconds };
Composition Organization
// Group related Sequences
// Good:
<>
{/ Background layer /}
{/ Content scenes /}
// Bad: Mixed layers without organization
Integration Workflow Define scene durations → Input to this skill Generate composition structure → COMPOSITION_STRUCTURE.md Add to composition file (index.tsx) Add timing to constants (constants.ts) Implement scenes via /remotion-component-gen Test timing in preview Adjust if needed and regenerate Integration with Other Skills
This skill coordinates with:
remotion-composition (this skill) ↓ outputs: COMPOSITION_STRUCTURE.md remotion-component-gen ↓ implements scenes with timing awareness remotion-animation ↓ animation timing works within scene durations
Works with:
/motion-designer — Scene timing from design specs /remotion-scaffold — Structure added to composition file /remotion-animation — Timing coordinates with animation configs /remotion-component-gen — Scenes fit within calculated durations /remotion-spec-translator — Orchestrates this skill in pipeline
This skill provides precise composition structure and timing calculations that ensure smooth, well-paced Remotion videos.