# Video Animation

> Build agency-quality animated videos (motion graphics, brand showcases, product reveals) using the video-js artifact type with React, Framer Motion, and Tailwind. Use when the user asks to create an animation, showcase video, motion graphic, or brand film.

- **Type:** Skill
- **Install:** `agentstack add skill-draguris-dragonclaw-video-animation`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [draguris](https://agentstack.voostack.com/s/draguris)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [draguris](https://github.com/draguris)
- **Source:** https://github.com/draguris/dragonclaw/tree/main/src/skills/video-animation
- **Website:** https://www.dragonclaw.asia

## Install

```sh
agentstack add skill-draguris-dragonclaw-video-animation
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Video Animation Skill

Build smooth, cinematic motion graphics for any brand or product. This skill covers the full workflow from setup to scene authoring — brand-agnostic and reusable for any project.

---

## Setup

### 1. Create the artifact

```javascript
const result = await createArtifact({
  artifactType: "video-js",
  slug: "my-video",
  previewPath: "/",
  title: "My Brand Showcase"
});
```

### 2. Define your brand system in `index.css`

Replace the placeholder values with your actual brand. This is the only place brand colors and fonts are defined — all scenes reference these variables.

```css
/* index.css */
:root {
  /* --- YOUR BRAND COLORS --- */
  --color-primary: #YOUR_PRIMARY;      /* main brand color, CTAs, accents */
  --color-secondary: #YOUR_SECONDARY;  /* secondary accent */
  --color-bg-dark: #YOUR_BG;           /* scene background */

  --color-text-primary: #ffffff;
  --color-text-secondary: #aaaaaa;
  --color-text-muted: #666666;

  /* --- YOUR BRAND FONTS --- */
  --font-display: 'YourDisplayFont', sans-serif;  /* titles, headings */
  --font-body: 'YourBodyFont', sans-serif;         /* body, labels */
}
```

### 3. Load fonts in `index.html`

```html

```

**Font selection by brand personality:**
| Mood | Display font | Body font |
|---|---|---|
| Tech/Developer | Space Grotesk | JetBrains Mono |
| Bold/Energy | Bungee or Anton | DM Sans |
| Premium/Luxury | Cormorant Garamond | Inter |
| Playful | Nunito | Baloo 2 |
| Editorial | Fraunces | IBM Plex Sans |

---

## File Structure

Every video follows this layout inside `artifacts//src/`:

```
components/video/
├── VideoTemplate.tsx       ← scene orchestrator + timing
├── PersistentLayers.tsx    ← background, shapes, accents (OUTSIDE AnimatePresence)
├── Scene1.tsx
├── Scene2.tsx
└── Scene3.tsx        ← as many scenes as needed
lib/video/
├── hooks.ts                ← useVideoPlayer (auto-advances scenes, loops)
└── animations.ts           ← spring/easing presets
```

---

## VideoTemplate.tsx — Scene Orchestrator

```tsx
import { AnimatePresence } from 'framer-motion';
import { useVideoPlayer } from '@/lib/video';
import { PersistentLayers } from './PersistentLayers';
import { Scene1Intro } from './Scene1Intro';
import { Scene2Features } from './Scene2Features';
import { Scene3Lockup } from './Scene3Lockup';

// Durations in milliseconds. Mix short punchy beats with longer dramatic holds.
const SCENE_DURATIONS = {
  intro:    4000,   // brand reveal — let it breathe
  features: 5000,   // staggered content — needs reading time
  lockup:   6000,   // final impression — hold it longer
};

export default function VideoTemplate() {
  const { currentScene } = useVideoPlayer({ durations: SCENE_DURATIONS });

  return (
    
      {/* Persistent background — lives OUTSIDE AnimatePresence */}
      

      {/* Scenes swap in/out with AnimatePresence */}
      
        {currentScene === 0 && }
        {currentScene === 1 && }
        {currentScene === 2 && }
      
    
  );
}
```

**Timing rules:**
- First scene: 3–4s (brand reveal needs to land)
- Feature/content scenes: 4–6s (staggered lists need time)
- Final scene: 5–7s (leave impression before loop)
- Never make every scene the same duration — rhythm dies

---

## PersistentLayers.tsx — Continuous Background

Elements here **never unmount**. They animate to new states when `currentScene` changes, creating visual continuity across scene cuts instead of hard resets.

```tsx
import { motion } from 'framer-motion';

export function PersistentLayers({ currentScene }: { currentScene: number }) {
  return (
    <>
      {/* Gradient that shifts between scenes */}
      

      {/* Floating shape that drifts and rotates between scenes */}
      

      {/* Second floating shape — opposite movement */}
      

      {/* Accent line that morphs between scenes */}
      
    
  );
}
```

---

## Scene Patterns

### Pattern A — Hero Brand Reveal

Use for the first scene. Stagger container fades in children one by one.

```tsx
import { motion } from 'framer-motion';

export function Scene1Intro() {
  const container = {
    hidden: { opacity: 0 },
    visible: { opacity: 1, transition: { staggerChildren: 0.2, delayChildren: 0.3 } },
    exit: { opacity: 0, scale: 1.05, filter: 'blur(10px)', transition: { duration: 0.8 } },
  };
  const item = {
    hidden: { opacity: 0, y: 30, filter: 'blur(8px)' },
    visible: { opacity: 1, y: 0, filter: 'blur(0px)', transition: { duration: 1.0, ease: [0.16, 1, 0.3, 1] } },
  };

  return (
    
      {/* Logo / Icon */}
      
        
        {/* Place your logo SVG or image here */}
        
      

      {/* Main title */}
      
        
          YOURBRAND
        
      

      {/* Subtitle */}
      
        
        
          YOUR TAGLINE
        
        
      
    
  );
}
```

### Pattern B — Staggered Feature List

Use for scenes showing multiple items that reveal one by one with a timer.

```tsx
import { motion } from 'framer-motion';
import { useState, useEffect } from 'react';

export function Scene2Features() {
  const [step, setStep] = useState(0);

  useEffect(() => {
    // Stagger item reveals at 800ms intervals
    const timers = [
      setTimeout(() => setStep(1), 800),
      setTimeout(() => setStep(2), 1600),
      setTimeout(() => setStep(3), 2400),
    ];
    return () => timers.forEach(clearTimeout);
  }, []);

  const features = [
    { label: 'Feature One',   sub: 'Short description' },
    { label: 'Feature Two',   sub: 'Short description' },
    { label: 'Feature Three', sub: 'Short description' },
  ];

  return (
    
      
        
          SECTION TITLE
        
        
          Section Subtitle
        

        
          {features.map((f, i) => (
             i} />
          ))}
        
      
    
  );
}

function FeatureItem({ label, sub, active }: { label: string; sub: string; active: boolean }) {
  return (
    
      
        
      
      
        
          {label}
          {sub}
        
      
    
  );
}
```

### Pattern C — Architecture / Tech Nodes

Use for showing system diagrams, tech stacks, or connected components.

```tsx
import { motion } from 'framer-motion';

export function Scene3Architecture() {
  return (
    
      ARCHITECTURE

      
        
        
        
        
        
      
    
  );
}

function ArchNode({ label, main = false, delay }: { label: string; main?: boolean; delay: number }) {
  return (
    
      
        {main && (
          
        )}
      
      
        {label}
      
    
  );
}

function ArchConnector({ delay }: { delay: number }) {
  return (
    
      
      
    
  );
}
```

### Pattern D — Full-Bleed Color Takeover

Use for a high-impact accent scene. Floods the screen with your brand color.

```tsx
import { motion } from 'framer-motion';

export function Scene4Takeover() {
  const chars = "YOUR MESSAGE".split('');

  return (
    
      
        {/* Character-by-character text reveal */}
        
          {chars.map((char, i) => (
            
              {char === ' ' ? '\u00A0' : char}
            
          ))}
        

        
          Supporting line
        
      
    
  );
}
```

### Pattern E — Final Lockup

Use for the closing scene. Brand name + tagline + subtle pulse.

```tsx
import { motion } from 'framer-motion';

export function Scene5Final() {
  return (
    
      {/* Glowing halo behind brand name */}
      

      
        YOURBRAND
      

      {/* Animated divider */}
      

      
        Your main tagline here
        
          Supporting descriptor
        
      
    
  );
}
```

---

## Motion Reference

### Springs (from `lib/video/animations.ts`)

```ts
springs.snappy  // stiffness 400, damping 30  — UI elements, quick snaps
springs.bouncy  // stiffness 300, damping 15  — playful elements
springs.smooth  // stiffness 120, damping 25  — default smooth motion
springs.gentle  // stiffness 100, damping 20  — floaty / atmospheric
```

### Timing

| Role | Duration |
|---|---|
| Micro shifts | 0.1–0.2s |
| Element entrance | 0.3–0.6s |
| Scene transition | 0.8–1.0s |
| Hero reveal | 1.2–1.5s |
| Background atmosphere | 2–4s |

### Preferred easing
```ts
ease: [0.16, 1, 0.3, 1]   // expressive ease-out — use for most entrances
ease: 'circOut'             // sharp deceleration — good for slides
ease: [0.76, 0, 0.24, 1]  // sharp ease-in-out — dramatic takeovers
```

### Glow effects (add to `index.css`)
```css
.glow-primary { box-shadow: 0 0 30px rgba(VAR_R, VAR_G, VAR_B, 0.4); }
.text-gradient {
  background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-secondary) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
```

---

## Rules

1. **No emojis** — replace with inline SVG icons using brand color stroke
2. **No flat backgrounds** — minimum 3 layers: atmosphere gradient + floating shapes + foreground content
3. **Font sizes in `vw`** — ensures consistent scaling: `text-[5vw]` hero, `text-[2vw]` subtitle, `text-[1.2vw]` label
4. **Every scene needs an exit animation** — or the loop will look broken
5. **Background elements belong in PersistentLayers** — not inside individual scenes
6. **Scene duration ≥ longest internal setTimeout + 1 second buffer**
7. **Stagger everything** — never reveal all elements at once
8. **Never use the same transition duration twice in a row** — vary rhythm

---

## Adding a New Scene

1. Create `SceneN.tsx` in `src/components/video/`
2. Add the import to `VideoTemplate.tsx`
3. Add `{currentScene === N && }` inside ``
4. Add a duration key to `SCENE_DURATIONS`
5. Update `PersistentLayers.tsx` to include the new scene index in gradient/shape animations

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [draguris](https://github.com/draguris)
- **Source:** [draguris/dragonclaw](https://github.com/draguris/dragonclaw)
- **License:** MIT
- **Homepage:** https://www.dragonclaw.asia

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-draguris-dragonclaw-video-animation
- Seller: https://agentstack.voostack.com/s/draguris
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
