Install
$ agentstack add skill-draguris-dragonclaw-video-animation ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →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
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.
/* 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
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
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.
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.
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.
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.
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.
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.
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)
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
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)
.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
- No emojis — replace with inline SVG icons using brand color stroke
- No flat backgrounds — minimum 3 layers: atmosphere gradient + floating shapes + foreground content
- Font sizes in
vw— ensures consistent scaling:text-[5vw]hero,text-[2vw]subtitle,text-[1.2vw]label - Every scene needs an exit animation — or the loop will look broken
- Background elements belong in PersistentLayers — not inside individual scenes
- Scene duration ≥ longest internal setTimeout + 1 second buffer
- Stagger everything — never reveal all elements at once
- Never use the same transition duration twice in a row — vary rhythm
Adding a New Scene
- Create
SceneN.tsxinsrc/components/video/ - Add the import to
VideoTemplate.tsx - Add
{currentScene === N && }inside `` - Add a duration key to
SCENE_DURATIONS - Update
PersistentLayers.tsxto 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
- Source: draguris/dragonclaw
- License: MIT
- Homepage: https://www.dragonclaw.asia
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.