---
name: text-animation-copier
description: Copy and recreate text animations from video examples using Remotion. This skill analyzes video frames to identify text animation patterns (timing, movement, styling, effects) and generates corresponding Remotion React components. Use when the user asks to replicate, copy, or recreate text animations from a video sample.
---
# Text Animation Copier for Remotion
Analyze and recreate text animations from video examples as Remotion React components with precise timing, styling, and effects.
## Quick Start
### Prerequisites
Before using this skill, ensure you have:
1. **ffmpeg installed** - Required for video frame extraction
2. **Remotion project set up** - Working remotion-animations repository
3. **Video URL or file path** - Direct link or local path to the video containing the animation
### Basic Workflow
When the user provides a video with a text animation to copy:
1. **Download and extract frames** from the video (use `claude-skills/video-viewing`)
2. **Analyze the animation** by examining key frames
3. **Identify animation properties** (timing, effects, positioning, styling)
4. **Generate Remotion component** that recreates the animation
5. **Test and refine** the animation in Remotion Studio
## Detailed Process
### Step 1: Download Video and Extract Frames
Use the `video-viewing` skill to download the video and extract frames:
```bash
python scripts/download_video.py "VIDEO_URL" -f
```
This downloads the video to `/mnt/user-data/outputs/` and extracts frames for analysis.
**Alternative:** If the user provides a local video file path, use ffmpeg directly:
```bash
# Extract frames at 1 frame per second
ffmpeg -i path/to/video.mp4 -vf fps=1 /tmp/frames/frame-%04d.png
# Extract frames at specific time interval (e.g., 00:07 to 00:13)
ffmpeg -i path/to/video.mp4 -ss 00:07 -to 00:13 -vf fps=2 /tmp/frames/frame-%04d.png
```
### Step 2: Analyze Animation by Examining Frames
The user will typically specify a time range (e.g., "00:07 - 00:13"). Extract and analyze frames from that range:
1. **Identify start and end frames** of the animation
2. **Examine key transition points** (when animation changes behavior)
3. **Ignore background video** - focus ONLY on text elements
4. **Document observations** about:
- Text content and positioning
- Font family, size, weight, color
- Animation type (fade, slide, scale, rotate, flip, etc.)
- Timing and easing curves
- Multi-stage animations (e.g., bar fill, then text appear)
- Special effects (3D transforms, shadows, glows, particles)
### Step 3: Identify Animation Properties
Based on frame analysis, document these key properties:
#### Timing Configuration
- **Duration**: Total animation length in seconds/frames
- **FPS**: Video frame rate (typically 30fps for web videos)
- **Key moments**: Frame numbers for important transitions
- **Easing**: Type of easing curve (linear, ease-in-out, cubic, bezier)
Example timing structure:
```typescript
const TIMING = {
PHASE_1_START: 0,
PHASE_1_END: 45,
PHASE_2_START: 48,
PHASE_2_END: 90,
HOLD_END: 180,
};
```
#### Text Styling
- **Font family**: Arial, Helvetica, custom fonts
- **Font size**: In pixels
- **Font weight**: normal, bold, 300-900
- **Color**: Hex or rgba values
- **Letter spacing**: Additional spacing between characters
- **Text alignment**: left, center, right
#### Positioning
- **Alignment**: center, top-left, bottom-left, etc.
- **Offset values**: Distance from edges in pixels
- **Responsive positioning**: Use viewport width/height for centering
#### Animation Effects
Common text animation patterns:
**1. Fade In/Out**
```typescript
const opacity = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
}
);
```
**2. Slide In/Out**
```typescript
const translateX = interpolate(
frame,
[START_FRAME, END_FRAME],
[-500, 0], // from left to center
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
}
);
```
**3. Scale Animation**
```typescript
const scale = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.elastic(1),
}
);
```
**4. 3D Rotation/Flip**
```typescript
const rotateY = interpolate(
frame,
[START_FRAME, END_FRAME],
[0, 360],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
// Apply with CSS transform
transform: `rotateY(${rotateY}deg)`,
transformStyle: "preserve-3d",
perspective: "1000px"
```
**5. Bar Fill Animation**
```typescript
const barProgress = interpolate(
frame,
[BAR_START, BAR_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}
);
// Apply to width
width: `${barProgress * 100}%`
```
**6. Staggered Animation (for multiple letters/words)**
```typescript
// Each letter starts with a delay
const letterStart = BASE_START + index * STAGGER_DELAY;
const letterEnd = letterStart + ANIMATION_DURATION;
const letterOpacity = interpolate(
frame,
[letterStart, letterEnd],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
```
**7. Spring Physics**
```typescript
const scale = spring({
frame: frame - START_FRAME,
fps: 30,
config: {
damping: 10,
stiffness: 100,
mass: 0.5,
},
});
```
### Step 4: Generate Remotion Component
Create a new React component in `src/animations/text-animation-N/` following these patterns:
#### Component Structure Template
```typescript
import React from "react";
import {
AbsoluteFill,
useCurrentFrame,
useVideoConfig,
interpolate,
Easing,
spring,
} from "remotion";
// Animation timing configuration (in frames, at 30fps)
// Reference video time range: HH:MM:SS - HH:MM:SS
const TIMING = {
ANIMATION_START: 0,
ANIMATION_END: 60,
// Add more timing points as needed
};
// Configuration constants
const TEXT = "YOUR TEXT HERE";
const FONT_SIZE = 48;
const FONT_FAMILY = "Arial, sans-serif";
const TEXT_COLOR = "#FFFFFF";
export const TextAnimationN: React.FC = () => {
const frame = useCurrentFrame();
const { width, height } = useVideoConfig();
// Calculate animation values based on current frame
const opacity = interpolate(
frame,
[TIMING.ANIMATION_START, TIMING.ANIMATION_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
return (
{/* Your animation elements here */}
{TEXT}
);
};
```
#### Important Requirements
1. **Resolution**: Always use 1920x1080 (configured in Root.tsx)
2. **Transparent background**: `backgroundColor: "transparent"`
3. **Center positioning**: Use `width/2` and `height/2` for centering
4. **Timing precision**: Match the original video timing as closely as possible
5. **Clean code**: Add comments explaining each animation phase
### Step 5: Register the Composition
Add the new animation to `src/Root.tsx`:
```typescript
import { TextAnimationN } from "./animations/text-animation-N/TextAnimationN";
```
### Step 6: Test in Remotion Studio
```bash
npm start
```
This opens Remotion Studio at `http://localhost:3000` where you can:
- Preview the animation in real-time
- Scrub through frames to verify timing
- Compare with the original video
- Adjust values and see immediate results
### Step 7: Render the Animation
Once satisfied with the animation:
```bash
# Render as WebM with transparency (recommended)
npm run render:text-animation-N
# Or add custom render script to package.json:
npx remotion render src/index.ts TextAnimationN out/text-animation-N.webm --codec vp9 --pixel-format yuva420p
```
## Advanced Techniques
### Per-Letter Animation
For animations where each letter animates independently:
```typescript
const Letter: React.FC<{
char: string;
index: number;
totalLetters: number;
}> = ({ char, index, totalLetters }) => {
const frame = useCurrentFrame();
// Stagger each letter's animation
const letterDelay = index * 3; // 3 frames delay per letter
const letterStart = TIMING.ANIMATION_START + letterDelay;
const opacity = interpolate(
frame,
[letterStart, letterStart + 15],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
{char}
);
};
// In main component:
const letters = TEXT.split("").map((char, i) => (
));
```
### Multi-Stage Animations
For complex animations with multiple sequential phases:
```typescript
// Phase 1: Slide in
const slideProgress = interpolate(
frame,
[TIMING.SLIDE_START, TIMING.SLIDE_END],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
}
);
// Phase 2: Scale pulse (starts after slide completes)
const scaleProgress = interpolate(
frame,
[TIMING.SCALE_START, TIMING.SCALE_END],
[1, 1.2],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.ease),
}
);
// Phase 3: Fade out
const fadeOutProgress = interpolate(
frame,
[TIMING.FADEOUT_START, TIMING.FADEOUT_END],
[1, 0],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
}
);
// Combine all phases
const translateX = slideProgress * width;
const scale = frame >= TIMING.SCALE_START ? scaleProgress : 1;
const opacity = frame >= TIMING.FADEOUT_START ? fadeOutProgress : 1;
```
### Background Effects
For text with animated backgrounds (like TextAnimation2):
```typescript
// Background appears behind text with 3D rotation