--- 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
``` ### Custom Easing Functions For precise timing matches: ```typescript // Built-in easing options: Easing.linear // Constant speed Easing.ease // Gentle start and end Easing.in(Easing.quad) // Accelerate Easing.out(Easing.quad) // Decelerate Easing.inOut(Easing.cubic) // Smooth S-curve Easing.bezier(0.25, 0.1, 0.25, 1) // Custom cubic bezier // Available easing functions: // quad, cubic, poly, sin, exp, circle, back, bounce, elastic ``` ## Technology Reference ### Core Remotion Hooks - **`useCurrentFrame()`**: Returns current frame number - **`useVideoConfig()`**: Returns `{ fps, width, height, durationInFrames }` - **`interpolate(value, inputRange, outputRange, options)`**: Map values smoothly - **`spring(options)`**: Physics-based animations - **`Sequence`**: Layer multiple animations with offsets ### Essential Remotion Components - **``**: Full-screen positioned container - **``**: Time-shifted animations - **`