Score
9.0
/ 10
Installs
—
Repo Stars
—
Last Updated
0d ago
Quality Ratio
95%
Description
Verified
Language
TypeScript
First Published
Feb 2026
Platforms
1
Skill Definition
VIDEO ANIMATION MISSION (MANDATORY READING)
DELIVERABLE TYPE: ANIMATED VIDEO (.mp4 file)
YOU ARE CREATING A PROGRAMMATIC VIDEO ANIMATION using Remotion. This is for kinetic typography, motion graphics, UI mockup animations, and promotional videos.
DO NOT CREATE: index.html, website, landing page, React web app, HTML page MUST CREATE: A rendered .mp4 video file using Remotion
If you create an HTML file instead of a video, YOU HAVE FAILED THE MISSION.
The ONLY acceptable output is: /home/user/output/video.mp4
WHAT REMOTION CAN DO
Remotion is React that renders to video. Anything you can build in React, you can animate in Remotion.
YOU CAN BUILD ANY UI FROM SCRATCH
Remotion doesn't just animate images - it can CREATE entire interfaces with code:
- Chat interfaces with messages appearing
- Dashboard UIs with charts and metrics
- Browser windows with content loading
- Mobile app mockups with interactions
- Code editors with typing animations
- Any React component = animatable video content
If the request is for a product demo, chatbot promo, or app showcase, you can BUILD the UI entirely with React components - no screenshots required (though you can use them too).
COLOR & DESIGN SYSTEM
When choosing colors, follow this system (unless the user specifies otherwise):
Color Structure:
- Primary: The main brand/accent color (choose something modern and vibrant)
- Secondary: A complementary color that pairs well with primary
- Neutral: Use primary color at 10-15% opacity for subtle backgrounds, or a desaturated version
- Background: Dark backgrounds work well for video (Slate-950, Zinc-950, or near-black)
- Text: High contrast against background (white or very light gray)
If user/company preferences are provided, use those colors. Otherwise, choose a cohesive modern palette.
Palette principles:
- Avoid clashing colors - secondary should complement, not compete with primary
- Use neutral tones for supporting elements (borders, subtle backgrounds)
- Gradients can add depth but use sparingly
- Ensure sufficient contrast for readability
REMOTION CAPABILITIES
Below are the key features available. These are approaches and examples - combine them creatively.
SPRING PHYSICS - Natural Motion
Springs create organic motion. Different configs for different feels:
// Example: Multiple spring configs for different animation feels
const SPRING_CONFIGS = {
// Smooth & professional (minimal bounce) - good for UI elements, subtle reveals
smooth: { damping: 200, stiffness: 100, mass: 1 },
// Bouncy & playful - good for attention-grabbing elements, logos
bouncy: { damping: 10, stiffness: 100, mass: 0.5, overshootClamping: false },
// Snappy & responsive - good for quick transitions, clicks
snappy: { damping: 20, stiffness: 300, mass: 0.3 },
// Elastic & wobbly - good for playful text, cartoon effects
elastic: { damping: 5, stiffness: 80, mass: 0.8, overshootClamping: false },
};
// Usage example
const value = spring({ frame, fps, config: SPRING_CONFIGS.bouncy });
SCENE TRANSITIONS - TransitionSeries
For professional scene-to-scene transitions, use TransitionSeries with effects:
// Example: Scene transitions with fade, wipe, slide effects
import { TransitionSeries, linearTiming, springTiming } from '@remotion/transitions';
import { fade } from '@remotion/transitions/fade';
import { wipe } from '@remotion/transitions/wipe';
import { slide } from '@remotion/transitions/slide';
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={90}>
<Scene1 />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
timing={springTiming({ config: { damping: 200 } })}
presentation={fade()}
/>
<TransitionSeries.Sequence durationInFrames={90}>
<Scene2 />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
timing={linearTiming({ durationInFrames: 20 })}
presentation={wipe({ direction: 'from-left' })}
/>
<TransitionSeries.Sequence durationInFrames={90}>
<Scene3 />
</TransitionSeries.Sequence>
</TransitionSeries>
Available transition effects: fade, wipe, slide, flip, clockWipe
SEQUENCING & TIMING
Control when elements appear and for how long:
// Example: Staggered element reveals
<AbsoluteFill>
<Sequence from={0} durationInFrames={120}>
<Title />
</Sequence>
<Sequence from={30} durationInFrames={90}>
<Subtitle />
</Sequence>
<Sequence from={60} durationInFrames={60}>
<CallToAction />
</Sequence>
</AbsoluteFill>
// Example: Auto-sequential with Series
import { Series } from 'remotion';
<Series>
<Series.Sequence durationInFrames={60}><Intro /></Series.Sequence>
<Series.Sequence durationInFrames={90}><MainContent /></Series.Sequence>
<Series.Sequence durationInFrames={60}><Outro /></Series.Sequence>
</Series>
TEXT ANIMATION APPROACHES
Many ways to animate text - pick what fits the mood:
// APPROACH 1: Whole word/line fade + scale (clean, professional)
const WordReveal = ({ children, delay = 0 }) => {
const frame = useCurrentFrame();
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 20, stiffness: 100 } });
return (
<div style={{
opacity: progress,
transform: `translateY(${(1 - progress) * 30}px)`,
}}>
{children}
</div>
);
};
// APPROACH 2: Character stagger (energetic, playful)
const CharacterStagger = ({ text, delay = 0 }) => (
<div style={{ display: 'flex' }}>
{text.split('').map((char, i) => {
const charProgress = spring({ frame: frame - delay - i * 2, fps: 60, config: { damping: 15 } });
return <span key={i} style={{ opacity: charProgress }}>{char === ' ' ? ' ' : char}</span>;
})}
</div>
);
// APPROACH 3: Typewriter effect (technical, code-like)
const Typewriter = ({ text, delay = 0, charsPerFrame = 0.5 }) => {
const frame = useCurrentFrame();
const visibleChars = Math.floor((frame - delay) * charsPerFrame);
return <span>{text.slice(0, Math.max(0, visibleChars))}</span>;
};
// APPROACH 4: Scale pop (impactful, attention-grabbing)
const ScalePop = ({ children, delay = 0 }) => {
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 8, overshootClamping: false } });
return (
<div style={{ transform: `scale(${progress})`, opacity: Math.min(1, progress * 2) }}>
{children}
</div>
);
};
// APPROACH 5: Slide from direction (directional, cinematic)
const SlideIn = ({ children, delay = 0, from = 'bottom' }) => {
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 20 } });
const offsets = { bottom: [0, 60], top: [0, -60], left: [-100, 0], right: [100, 0] };
const [x, y] = offsets [from] || offsets.bottom;
return (
<div style={{
opacity: progress,
transform: `translate(${x * (1-progress)}px, ${y * (1-progress)}px)`,
}}>
{children}
</div>
);
};
Choose the approach that matches the video's tone. Mix approaches for variety within a single video.
BUILDING UIs FROM SCRATCH
You can create entire interfaces with React - no images needed:
// Example: Chat interface built from scratch
const ChatMessage = ({ text, isUser, delay }) => {
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 15 } });
return (
<div style={{
alignSelf: isUser ? 'flex-end' : 'flex-start',
backgroundColor: isUser ? PRIMARY_COLOR : NEUTRAL_COLOR,
borderRadius: 16,
padding: '12px 18px',
maxWidth: '70%',
opacity: progress,
transform: `translateY(${(1-progress) * 20}px)`,
}}>
{text}
</div>
);
};
const ChatDemo = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, padding: 40 }}>
<ChatMessage text="How can I help you today?" isUser={false} delay={0} />
<ChatMessage text="I need help with my project" isUser={true} delay={30} />
<ChatMessage text="Of course! What are you working on?" isUser={false} delay={60} />
</div>
);
// Example: Dashboard card built from scratch
const DashboardCard = ({ title, value, delay }) => {
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 12 } });
return (
<div style={{
background: NEUTRAL_COLOR,
borderRadius: 16,
padding: 24,
opacity: progress,
transform: `scale(${0.9 + progress * 0.1})`,
}}>
<div style={{ color: '#888', fontSize: 14 }}>{title}</div>
<div style={{ color: '#fff', fontSize: 36, fontWeight: 700 }}>{value}</div>
</div>
);
};
// Example: Browser window frame
const BrowserWindow = ({ children, url = 'example.com' }) => (
<div style={{ borderRadius: 12, overflow: 'hidden', boxShadow: '0 25px 50px rgba(0,0,0,0.4)' }}>
<div style={{ background: '#333', padding: '8px 16px', display: 'flex', gap: 8 }}>
<div style={{ width: 12, height: 12, borderRadius: '50%', background: '#ff5f57' }} />
<div style={{ width: 12, height: 12, borderRadius: '50%', background: '#ffbd2e' }} />
<div style={{ width: 12, height: 12, borderRadius: '50%', background: '#28c840' }} />
<div style={{ flex: 1, background: '#222', borderRadius: 4, padding: '2px 12px', color: '#888', fontSize: 12 }}>{url}</div>
</div>
<div style={{ background: '#1a1a1a' }}>{children}</div>
</div>
);
ANIMATING UI MOCKUPS (with images)
If using screenshots, animate them with perspective and effects:
// Fly-in with perspective
const FlyIn = ({ children, delay = 0 }) => {
const progress = spring({ frame: frame - delay, fps: 60, config: { damping: 15, stiffness: 80 } });
return (
<div style={{
transform: `perspective(1000px) rotateX(${(1-progress) * 30}deg) translateY(${(1-progress) * 200}px) scale(${0.5 + progress * 0.5})`,
opacity: progress,
boxShadow: `0 ${progress * 30}px ${progress * 60}px rgba(0,0,0,0.4)`,
}}>
{children}
</div>
);
};
// Cursor with click effect
const Cursor = ({ x, y, clicking = false }) => (
<>
<div style={{ position: 'absolute', left: x, top: y, width: 20, height: 20, borderRadius: '50%', background: '#fff', boxShadow: '0 2px 8px rgba(0,0,0,0.3)' }} />
{clicking && <div style={{ position: 'absolute', left: x - 15, top: y - 15, width: 50, height: 50, borderRadius: '50%', border: '2px solid rgba(255,255,255,0.4)' }} />}
</>
);
AUDIO INTEGRATION
Add sound effects for impacts, whooshes, music:
// Example: Adding audio
import { Audio, Sequence } from 'remotion';
<Sequence from={30}>
<Audio src={staticFile('whoosh.mp3')} volume={0.5} />
</Sequence>
<Sequence from={60}>
<Audio src={staticFile('impact.mp3')} volume={0.8} />
</Sequence>
// Background music with fade
<Audio
src={staticFile('music.mp3')}
volume={(f) => interpolate(f, [0, 30, 270, 300], [0, 0.3, 0.3, 0], { extrapolateRight: 'clamp' })}
/>
IMAGES & MEDIA
Use Remotion's media components for proper asset handling:
import { Img, Video, Gif, staticFile } from 'remotion';
// Images from public folder
<Img src={staticFile('logo.png')} style={{ width: 200 }} />
// Remote images
<Img src="https://example.com/image.png" />
// Animated GIFs
import { Gif } from '@remotion/gif';
<Gif src={staticFile('animation.gif')} />
TECHNICAL REQUIREMENTS
- NO PYTHON f-strings: Use triple-quoted strings and
.replace()instead. - TARGET FILE:
/home/user/project/src/index.tsx - ASSET BRIDGE: Copy images from
/home/user/output/to/home/user/project/public/, usestaticFile("filename.png"). - ENVIRONMENT:
- COMPOSITION ID: Must be
"OmegaPromo". - RENDER COMMAND:
npx remotion render src/index.tsx OmegaPromo /home/user/output/video.mp4 --concurrency=4 --gl=angle-egl --overwrite
QUALITY OPTIONS (optional flags):
--crf=18for higher quality (lower = better, default 18 for H.264)--codec=h264(default) or--codec=proresfor professional quality
BUILDER SCRIPT PATTERN
import os, json, subprocess, shutil
PROJECT_DIR = "/home/user/project"
PUBLIC_DIR = os.path.join(PROJECT_DIR, "public")
INDEX_FILE = os.path.join(PROJECT_DIR, "src/index.tsx")
OUTPUT_VIDEO = "/home/user/output/video.mp4"
# 1. Prepare Asset Bridge
os.makedirs(PUBLIC_DIR, exist_ok=True)
if os.path.exists("/home/user/output"):
input_assets = [f for f in os.listdir("/home/user/output") if f.endswith(('.png', '.jpg', '.jpeg', '.svg', '.mp3', '.wav'))]
for asset in input_assets:
shutil.copy(os.path.join("/home/user/output", asset), os.path.join(PUBLIC_DIR, asset))
# 2. Define React/Remotion code
CODE = """
import React from 'react';
import {
registerRoot,
Composition,
AbsoluteFill,
useCurrentFrame,
useVideoConfig,
interpolate,
spring,
Sequence,
Img,
staticFile,
} from 'remotion';
import { TransitionSeries, linearTiming, springTiming } from '@remotion/transitions';
import { fade } from '@remotion/transitions/fade';
// Your creative implementation here...
// Use the Remotion capabilities above as needed for the request.
const MainVideo = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
return (
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={120}>
{/* Scene 1 */}
</TransitionSeries.Sequence>
<TransitionSeries.Transition
timing={springTiming({ config: { damping: 200 } })}
presentation={fade()}
/>
<TransitionSeries.Sequence durationInFrames={120}>
{/* Scene 2 */}
</TransitionSeries.Sequence>
</TransitionSeries>
);
};
const RemotionRoot = () => (
<Composition
id="OmegaPromo"
component={MainVideo}
durationInFrames={600}
fps={60}
width={1920}
height={1080}
/>
);
registerRoot(RemotionRoot);
"""
# 3. Write and Render
with open(INDEX_FILE, "w") as f:
f.write(CODE)
render_cmd = [
"npx", "remotion", "render",
"src/index.tsx", "OmegaPromo", OUTPUT_VIDEO,
"--concurrency=4", # Match E2B sandbox cpu_count=4 for parallel rendering
"--gl=angle-egl",
"--overwrite"
]
# Use a generous timeout for the render process
RENDER_TIMEOUT = 900
try:
res = subprocess.run(render_cmd, cwd=PROJECT_DIR, capture_output=True, text=True, timeout=RENDER_TIMEOUT)
# 4. Validate output
if res.returncode == 0 and os.path.exists(OUTPUT_VIDEO):
file_size = os.path.getsize(OUTPUT_VIDEO)
if file_size > 10000:
print(json.dumps({"success": True, "summary": "Video animation rendered successfully.", "output_files": ["video.mp4"]}))
else:
print(json.dumps({"success": False, "summary": f"Render produced empty file ({file_size} bytes)."}))
else:
print(json.dumps({"success": False, "summary": f"Render failed: {res.stderr}"}))
except subprocess.TimeoutExpired:
print(json.dumps({"success": False, "summary": f"Render timed out after {RENDER_TIMEOUT} seconds."}))