# π¬ REMOTION ANIMATION PATTERNS
**Essential code patterns and rules for professional animations**
## π§ DYNAMIC CONFIGURATION SYSTEM
### **Component Structure (MANDATORY):**
```typescript
import React from 'react';
import { spring, useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
import { parseGuidelinesConfig, generateTypography, generateFontContainerStyles } from '../typography';
export const ComponentName: React.FC = () => {
const frame = useCurrentFrame();
// 1. Read config from guidelines
const config = parseGuidelinesConfig(guidelinesContent);
// 2. Apply dynamic values
const TYPOGRAPHY = generateTypography(
config.selectedFontStack,
config.typographyScale,
config.fontStacks,
config.baseSizes
);
const ANIMATION_CONFIG = config.animationConfig;
const COLORS = config.colors;
const SPACING = config.spacing;
// 3. Use in animations
return (
<div style={{...FONT_CONTAINER_STYLES, width: '100%', height: '100%'}}>
<h1 style={{...TYPOGRAPHY.h1, color: COLORS.text.primary}}>
Dynamic Title
</h1>
</div>
);
};
```
### **Benefits of Dynamic System:**
- β
**Single Source of Truth**: All settings in PROJECT_CONFIG.md
- β
**No Hardcoded Values**: Everything references guidelines
- β
**Easy Updates**: Change one value, entire project updates
- β
**Version Control**: Settings tracked with guidelines
- β
**User-Friendly**: Non-technical users can modify visuals
## β‘ MANDATORY ANIMATION RULES
### **Professional Animation Checklist:**
- β
**Overlapping scenes** - No empty screen time (15-frame overlaps)
- β
**Movement + fades** - Never fade-only transitions
- β
**Quick timing** - 20-frame entries, 15-frame exits
- β
**Safe interpolation** - Always use bounds checking
- β
**Cubic easing** - out for entries, in for exits
- β
**Staggered elements** - 5-8 frame delays within scenes
### **Timeline Formula (10-second animation):**
```typescript
// Scene overlaps - ALWAYS something visible:
// Scene 1: 0-80 frames (0-2.7s)
// Scene 2: 65-155 frames (2.2-5.2s) - 15 frame overlap
// Scene 3: 140-230 frames (4.7-7.7s) - 15 frame overlap
// Scene 4: 215-300 frames (7.2-10s) - 15 frame overlap
```
## π§ SAFE ANIMATION PATTERNS
### **Safe Interpolation (ALWAYS USE):**
```typescript
const safeInterpolate = (frame, inputRange, outputRange, easing) => {
const [inputStart, inputEnd] = inputRange;
const [outputStart, outputEnd] = outputRange;
if (inputEnd === inputStart) return outputStart;
if (frame <= inputStart) return outputStart;
if (frame >= inputEnd) return outputEnd;
return interpolate(frame, inputRange, outputRange, { easing });
};
```
### **Overlapping Scene Template:**
```typescript
const animations = {
scene1: {
opacity: safeInterpolate(frame, [0, 20], [0, 1], Easing.out(Easing.cubic)) *
safeInterpolate(frame, [60, 75], [1, 0], Easing.in(Easing.cubic)),
entryY: safeInterpolate(frame, [0, 20], [20, 0], Easing.out(Easing.cubic)),
exitY: safeInterpolate(frame, [60, 75], [0, -20], Easing.in(Easing.cubic))
},
scene2: {
opacity: safeInterpolate(frame, [65, 85], [0, 1], Easing.out(Easing.cubic)) *
safeInterpolate(frame, [140, 155], [1, 0], Easing.in(Easing.cubic)),
entryY: safeInterpolate(frame, [65, 85], [30, 0], Easing.out(Easing.cubic)),
exitX: safeInterpolate(frame, [140, 155], [0, -60], Easing.in(Easing.cubic))
}
};
// Calculate final visibility
const sceneVisibility = {
scene1: animations.scene1.opacity,
scene2: animations.scene2.opacity
};
// Render with visibility checks
{sceneVisibility.scene1 > 0.01 && <Scene1Content />}
{sceneVisibility.scene2 > 0.01 && <Scene2Content />}
```
### **Staggered Elements Pattern:**
```typescript
{items.map((item, index) => (
<div
key={item.id}
style={{
opacity: safeInterpolate(frame, [sceneStart + index * 5, sceneStart + 15 + index * 5], [0, 1]),
transform: `translateY(${safeInterpolate(frame, [sceneStart + index * 5, sceneStart + 15 + index * 5], [15, 0])}px)`
}}
>
{item.content}
</div>
))}
```
## π LAYOUT SAFETY RULES
### **Minimum Sizes (CRITICAL):**
- **Text**: 16px minimum
- **Badges**: 18px minimum
- **Buttons**: 20px minimum
- **Touch targets**: 44px minimum
- **Container padding**: 40px minimum
### **Safe Grid Pattern:**
```typescript
// β
CORRECT: Explicit columns
<div style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr', // EXPLICIT columns
gridTemplateRows: '1fr 1fr', // EXPLICIT rows
gap: '25px',
maxWidth: '600px'
}}>
// β BANNED: Auto-fit patterns
gridTemplateColumns: 'repeat(auto-fit, minmax(...))'
```
### **Safe Centering:**
```typescript
const centeredContentStyle = {
position: 'absolute' as const,
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '90%',
maxWidth: '800px',
textAlign: 'center' as const
};
```
## π¨ BANNED PATTERNS
**NEVER USE:**
- β **Empty screen time** - Always overlap scenes
- β **Fade-only transitions** - Always combine with movement
- β **Slow timing** - Use 15-20 frame transitions max
- β **Hard scene cuts** - Always use overlapping opacity
- β **Auto-fit grids** - Use explicit columns only
- β **Fixed height with text** - Use `minHeight`
- β **Small text** - Under 16px font size
- β **Multiple absolute positioned elements** in same scene
## π― COMPONENT TEMPLATE
```typescript
import React from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate, Easing } from 'remotion';
import { parseGuidelinesConfig, generateTypography, generateFontContainerStyles } from './typography';
export const ComponentName: React.FC = () => {
const frame = useCurrentFrame();
// Read configuration from PROJECT_CONFIG.md
const config = parseGuidelinesConfig(guidelinesContent);
const TYPOGRAPHY = generateTypography(
config.selectedFontStack,
config.typographyScale,
config.fontStacks,
config.baseSizes
);
const FONT_CONTAINER_STYLES = generateFontContainerStyles(
config.selectedFontStack,
config.fontStacks
);
// Safe interpolation
const safeInterpolate = (frame, inputRange, outputRange, easing) => {
const [inputStart, inputEnd] = inputRange;
if (inputEnd === inputStart) return inputRange[0];
if (frame <= inputStart) return outputRange[0];
if (frame >= inputEnd) return outputRange[1];
return interpolate(frame, inputRange, outputRange, { easing });
};
// Overlapping scenes
const animations = {
scene1: {
opacity: safeInterpolate(frame, [0, 20], [0, 1], Easing.out(Easing.cubic)) *
safeInterpolate(frame, [60, 75], [1, 0], Easing.in(Easing.cubic)),
entryY: safeInterpolate(frame, [0, 20], [config.animationConfig.entryDistance || 40, 0], Easing.out(Easing.cubic))
}
};
return (
<AbsoluteFill style={{...FONT_CONTAINER_STYLES, width: '100%', height: '100%'}}>
{animations.scene1.opacity > 0.01 && (
<div style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '90%',
maxWidth: '800px',
textAlign: 'center',
opacity: animations.scene1.opacity,
transform: `translate(-50%, -50%) translateY(${animations.scene1.entryY}px)`
}}>
<h1 style={{...TYPOGRAPHY.h1, color: config.colors.text.primary}}>
Title
</h1>
<p style={{...TYPOGRAPHY.body, color: config.colors.text.secondary}}>
Content
</p>
</div>
)}
</AbsoluteFill>
);
};
```
**This file contains the essential animation patterns - combine with PROJECT_CONFIG.md for complete system!**