请帮我使用 Clawhub 安装 loopwind。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。
loopwind 应用场景
为博客文章和文档自动生成 Open Graph (OG) 图像。
使用内置动画类创建动态 YouTube 片头视频或社交媒体预告片。
大规模生成 T@witter、LinkedIn 或 In@stagram 的品牌社交媒体卡片。
在共享的 Git 仓库中为营销资产构建可重用的设计系统。
为宣传材料和交易卡片实时生成二维码。
loopwind 工作原理
初始化项目配置以定义主题颜色、自定义字体和设计令牌。
在专门的目录中创建或安装 React 模板以定义视觉结构。
为每个模板定义元数据和属性,指定输出尺寸和媒体类型(图像或视频)。
使用 CLI 将模板渲染为各种格式,包括 PNG、JPEG、SVG 或 MP4。
使用 Openclaw Skills 与 AI 代理集成,通过自然语言命令自动执行资产创建过程。
loopwind 配置指南
首先,通过官方安装脚本安装 loopwind CLI:
curl -fsSL https://loopwind.dev/install.sh | bash
导航到您的项目文件夹并初始化环境:
loopwind init
最后,通过添加技能定义为您的 AI 代理配备必要的 Openclaw Skills:
npx skills add https://loopwind.dev/skill.md
loopwind 数据架构与分类体系
该工具通过本地目录和结构化的 JSON 元数据组织其生态系统:
组件
描述
.loopwind/
包含所有模板、配置和本地资产的核心目录。
loopwind.json
用于全局主题颜色、品牌令牌和字体映射的项目配置文件。
template.tsx
定义视觉布局和样式的函数式 React 组件。
meta 对象
模板中必需的导出项,定义名称、类型、尺寸和属性模式。
props.json
可选的本地文件,用于在渲染期间向模板提供数据。
name: loopwind
description: Generate images and videos from React + Tailwind CSS templates using the loopwind CLI.
metadata:
version: "0.25.11"
loopwind
A CLI tool for generating images and videos from JSX templates using Tailwind CSS and Satori. Templates live in a .loopwind/ directory alongside your codebase.
Quick Start
Loopwind is a CLI tool for generating images and videos with React and Tailwind CSS. It's designed to be used with AI Agents and Cursor.
Installation
curl -fsSL https://loopwind.dev/install.sh | bash
This installs loopwind to ~/.loopwind/ and adds the loopwind command to your PATH. Requires Node.js 18+.
Initialize in Your Project
Navigate to any project folder and run:
loopwind init
This creates .loopwind/loopwind.json — a configuration file with your project's theme colors.
Install AI Skill
Give your AI agent expertise in loopwind:
npx skills add https://loopwind.dev/skill.md
This installs a skill that teaches Claude Code (or other AI agents) how to create templates, use animation classes, and render images/videos.
Use with Claude Code
With the loopwind skill installed, Claude has deep knowledge of template structure, animation classes, and Tailwind CSS patterns for Satori. Just ask:
Create an OG image for my blog post about TypeScript tips
Create an animated intro video for my YouTube channel
Claude will create optimized templates and render the final output automatically.
Creates .loopwind/loopwind.json configuration file with your project's design tokens.
Animation Classes (Video Only)
Use Tailwind-style animation classes - no manual calculations needed:
// Fade in: starts at 0ms, lasts 500ms
Hello
// Loop: ping effect every 500ms
// Combined with easing
Title
See Animation for the complete reference.
Next Steps
Templates
Embedding Images
Animation
Helpers (QR, Template Composition)
Styling with Tailwind & shadcn/ui
Custom Fonts
AI Agent Integration
Templates
Templates are React components that define your images and videos. They use Tailwind CSS for styling and export metadata that loopwind uses for rendering.
Layouts let you wrap templates with consistent headers, footers, and styling. A child template specifies a layout in its meta, and the layout receives the child content as a children prop.
{/* Bounce in from below: starts at 0, lasts 400ms */}
{title}
{/* Fade in with upward motion: starts at 300ms, lasts 400ms */}
{subtitle}
{/* Continuous floating animation: repeats every 1s (1000ms) */}
??
);
}
Animation Format
loopwind uses three types of animations with millisecond timing:
Type
Format
Description
Enter
enter-{type}/{start}/{duration}
Animations that play when entering
Exit
exit-{type}/{start}/{duration}
Animations that play when exiting
Loop
loop-{type}/{duration}
Continuous looping animations
All timing values are in milliseconds (1000ms = 1 second).
Utility-Based Animations
In addition to predefined animations, loopwind supports Tailwind utility-based animations that let you animate any transform or opacity property directly:
// Slide in 20px from the left
Content
// Rotate 90 degrees on entrance
Spinning
// Fade to 50% opacity in a loop
Pulsing
// Scale down with negative value
Shrinking
Supported Utilities
Utility
Format
Description
Example
translate-x
enter-translate-x-{value}
Translate horizontally
enter-translate-x-5 = 20px enter-translate-x-full = 100% enter-translate-x-[20px] = 20px
// Continuous rotation in loop (360 degrees per cycle)
Spinning
// Rotate backwards with negative value
Counter Rotation
Skew Animations
// Skew on X axis
Slanted
// Skew on Y axis
Tilted
// Oscillating skew in loop
Wobbling
// Negative skew
Reverse Slant
Combining Utilities
You can combine multiple utility animations on the same element:
// Translate and rotate together
Flying In
// Fade and scale
Appearing
// Enter with translate, exit with rotation
Slide and Spin
Bracket Notation
For more CSS-like syntax, you can use brackets with units:
// Using bracket notation with seconds
Hello
// Using bracket notation with milliseconds
World
// Mix and match - plain numbers are milliseconds
Mixed
Enter Animations
Format: enter-{type}/{startMs}/{durationMs}
startMs - when the animation begins (milliseconds from start)
durationMs - how long the animation lasts
When values are omitted (enter-fade-in), it uses the full video duration.
Fade Animations
Simple opacity transitions with optional direction.
// Fade in from 0ms to 500ms
Hello
// Fade in with upward motion
Hello
Class
Description
enter-fade-in/0/500
Fade in (opacity 0 → 1)
enter-fade-in-up/0/500
Fade in + slide up (30px)
enter-fade-in-down/0/500
Fade in + slide down (30px)
enter-fade-in-left/0/500
Fade in + slide from left (30px)
enter-fade-in-right/0/500
Fade in + slide from right (30px)
Slide Animations
Larger movement (100px) with fade.
// Slide in from left: starts at 0, lasts 500ms
Content
// Slide up from bottom: starts at 200ms, lasts 600ms
Content
Class
Description
enter-slide-left/0/500
Slide in from left (100px)
enter-slide-right/0/500
Slide in from right (100px)
enter-slide-up/0/500
Slide in from bottom (100px)
enter-slide-down/0/500
Slide in from top (100px)
Bounce Animations
Playful entrance with overshoot effect.
// Bounce in with scale overshoot
Bouncy!
// Bounce in from below
Pop!
Class
Description
enter-bounce-in/0/500
Bounce in with scale overshoot
enter-bounce-in-up/0/500
Bounce in from below
enter-bounce-in-down/0/500
Bounce in from above
enter-bounce-in-left/0/500
Bounce in from left
enter-bounce-in-right/0/500
Bounce in from right
Scale & Zoom Animations
Size-based transitions.
// Scale in from 50%
Growing
// Zoom in from 0%
Zooming
Class
Description
enter-scale-in/0/500
Scale up from 50% to 100%
enter-zoom-in/0/500
Zoom in from 0% to 100%
Rotate & Flip Animations
Rotation-based transitions.
// Rotate in 180 degrees
Spinning
// 3D flip on X axis
Flipping
Class
Description
enter-rotate-in/0/500
Rotate in from -180°
enter-flip-in-x/0/500
3D flip on horizontal axis
enter-flip-in-y/0/500
3D flip on vertical axis
Exit Animations
Format: exit-{type}/{startMs}/{durationMs}
startMs - when the exit animation begins
durationMs - how long the exit animation lasts
Exit animations use the same timing system but animate elements out.
// Fade out starting at 2500ms, lasting 500ms (ends at 3000ms)
Goodbye
// Combined enter and exit on same element
Hello and Goodbye
Class
Description
exit-fade-out/2500/500
Fade out (opacity 1 → 0)
exit-fade-out-up/2500/500
Fade out + slide up
exit-fade-out-down/2500/500
Fade out + slide down
exit-fade-out-left/2500/500
Fade out + slide left
exit-fade-out-right/2500/500
Fade out + slide right
exit-slide-up/2500/500
Slide out upward (100px)
exit-slide-down/2500/500
Slide out downward (100px)
exit-slide-left/2500/500
Slide out to left (100px)
exit-slide-right/2500/500
Slide out to right (100px)
exit-scale-out/2500/500
Scale out to 150%
exit-zoom-out/2500/500
Zoom out to 200%
exit-rotate-out/2500/500
Rotate out to 180°
exit-bounce-out/2500/500
Bounce out with scale
exit-bounce-out-up/2500/500
Bounce out upward
exit-bounce-out-down/2500/500
Bounce out downward
exit-bounce-out-left/2500/500
Bounce out to left
exit-bounce-out-right/2500/500
Bounce out to right
Loop Animations
Format: loop-{type}/{durationMs}
Loop animations repeat every {durationMs} milliseconds:
/1000 = 1 second loop
/500 = 0.5 second loop
/2000 = 2 second loop
When duration is omitted (loop-bounce), it defaults to 1000ms (1 second).
// Pulse opacity every 500ms
Pulsing
// Bounce every 800ms
Bouncing
// Full rotation every 2000ms
Spinning
Class
Description
loop-fade/{ms}
Opacity pulse (0.5 → 1 → 0.5)
loop-bounce/{ms}
Bounce up and down
loop-spin/{ms}
Full 360° rotation
loop-ping/{ms}
Scale up + fade out (radar effect)
loop-wiggle/{ms}
Side to side wiggle
loop-float/{ms}
Gentle up and down floating
loop-pulse/{ms}
Scale pulse (1.0 → 1.05 → 1.0)
loop-shake/{ms}
Shake side to side
Easing Functions
Add an easing class before the animation class to control the timing curve.
// Ease in (accelerate)
Accelerating
// Ease out (decelerate) - default
Decelerating
// Ease in-out (smooth)
Smooth
// Strong cubic easing
Dramatic
Class
Description
Best For
linear
Constant speed
Mechanical motion
ease-in
Slow start, fast end
Exit animations
ease-out
Fast start, slow end (default)
Enter animations
ease-in-out
Slow start and end
Subtle transitions
ease-in-cubic
Strong slow start
Dramatic exits
ease-out-cubic
Strong fast start
Impactful entrances
ease-in-out-cubic
Strong both ends
Emphasis animations
ease-in-quart
Very strong slow start
Powerful exits
ease-out-quart
Very strong fast start
Punchy entrances
ease-in-out-quart
Very strong both ends
Maximum drama
Per-Animation-Type Easing
You can apply different easing functions to enter, exit, and loop animations on the same element using enter-ease-*, exit-ease-*, and loop-ease-* classes.
// Different easing for enter and exit
Smooth entrance, sharp exit
// Loop with linear easing, enter with bounce
Bouncy entrance, linear loop
// Default easing still works (applies to all animations)
Same easing for both
// Mix default with specific overrides
Default ease-out for enter, cubic-in for exit
How it works:
Default easing (ease-*) applies to ALL animations if no specific override is set
Specific easing (enter-ease-*, exit-ease-*, loop-ease-*) overrides the default for that animation type
If both are present, specific easing takes priority for its animation type
Available easing classes:
Default (all animations)
Enter only
Exit only
Loop only
ease-in
enter-ease-in
exit-ease-in
loop-ease-in
ease-out
enter-ease-out
exit-ease-out
loop-ease-out
ease-in-out
enter-ease-in-out
exit-ease-in-out
loop-ease-in-out
ease-in-cubic
enter-ease-in-cubic
exit-ease-in-cubic
loop-ease-in-cubic
ease-out-cubic
enter-ease-out-cubic
exit-ease-out-cubic
loop-ease-out-cubic
ease-in-out-cubic
enter-ease-in-out-cubic
exit-ease-in-out-cubic
loop-ease-in-out-cubic
ease-in-quart
enter-ease-in-quart
exit-ease-in-quart
loop-ease-in-quart
ease-out-quart
enter-ease-out-quart
exit-ease-out-quart
loop-ease-out-quart
ease-in-out-quart
enter-ease-in-out-quart
exit-ease-in-out-quart
loop-ease-in-out-quart
linear
enter-ease-linear
exit-ease-linear
loop-ease-linear
ease-spring
enter-ease-spring
exit-ease-spring
loop-ease-spring
Spring Easing
Spring easing creates natural, physics-based bouncy animations. Use the built-in ease-spring easing or create custom springs with configurable parameters.
// Default spring easing
Bouncy spring!
// Per-animation-type spring
Spring entrance, smooth exit
// Custom spring with parameters: ease-spring/mass/stiffness/damping
Custom spring (mass=1, stiffness=100, damping=10)
// More bouncy spring (lower damping)
Extra bouncy!
// Stiffer spring (higher stiffness, faster)
Snappy spring
// Per-animation-type custom springs
Different springs for enter and exit
Spring parameters:
Parameter
Description
Effect when increased
Default
mass
Mass of the spring
Slower, more inertia
1
stiffness
Spring stiffness
Faster, snappier
100
damping
Damping coefficient
Less bounce, smoother
10
Common spring presets:
// Gentle bounce (default)
ease-spring/1/100/10
// Extra bouncy
ease-spring/1/170/8
// Snappy (no bounce)
ease-spring/1/200/15
// Slow and bouncy
ease-spring/2/100/8
// Fast and tight
ease-spring/0.5/300/20
How spring works:
Default ease-spring - Uses a pre-calculated spring curve optimized for most use cases
Custom ease-spring/mass/stiffness/damping - Generates a physics-based spring curve using the damped harmonic oscillator formula
The spring automatically calculates its ideal duration to reach the final state
Works with all animation types: ease-spring, enter-ease-spring, exit-ease-spring, loop-ease-spring
Combining Enter and Exit
You can use both enter and exit animations on the same element:
export default function EnterExit({ tw, title }) {
return (
{/* Fade in during first 500ms, fade out during last 500ms (assuming 3s video) */}
{title}
);
}
The opacities from multiple animations are multiplied together, so you get smooth transitions that combine properly.
Staggered Animations
Create sequenced animations by offsetting start times:
export default function StaggeredList({ tw, items }) {
return (
{/* First item: starts at 0ms, lasts 300ms */}
{items[0]}
{/* Second item: starts at 100ms, lasts 300ms */}
{items[1]}
{/* Third item: starts at 200ms, lasts 300ms */}
{items[2]}
);
}
Dynamic Staggering
For dynamic lists, calculate the timing programmatically:
export default function DynamicStagger({ tw, items }) {
return (
{items.map((item, i) => {
const start = i * 100; // Each item starts 100ms later
const duration = 300; // Each animation lasts 300ms
return (
{item}
);
})}
);
}
Common Patterns
Intro Sequence
export default function IntroVideo({ tw, title, subtitle, logo }) {
return (
{/* Logo appears first */}
{/* Title bounces in */}
{title}
{/* Subtitle fades in last */}
{subtitle}
);
}
Text Reveal
export default function TextReveal({ tw, words }) {
return (
{words.split(' ').map((word, i) => (
{word}
))}
);
}
Looping Background Element
export default function AnimatedBackground({ tw, children }) {
return (
{/* Floating background circles */}
{/* Main content */}
{children}
);
}
Full Enter/Exit Animation
export default function FullAnimation({ tw, title }) {
return (
{/* Enter: starts at 0, lasts 400ms. Exit: starts at 2600ms, lasts 400ms */}
{title}
);
}
Programmatic Animations
For complete control beyond animation classes, use progress and frame directly.
Available Props
Prop
Type
Description
progress
number
0 to 1 through the video (0% to 100%)
frame
number
Current frame number (0, 1, 2, ... totalFrames-1)
These are only available in video templates. Use them when animation classes aren't flexible enough.
Using frame
export default function FrameAnimation({ tw, frame, title }) {
// Color cycling using frame number
const hue = (frame * 5) % 360; // Cycle through colors
// Pulsing based on frame
const fps = 30;
const pulse = Math.sin(frame / fps * Math.PI * 2) * 0.2 + 0.8; // 0.6 to 1.0
return (
{title}
);
}
Using progress
export default function ProgressAnimation({ tw, progress, title }) {
// Custom fade based on progress
const opacity = progress < 0.3 ? progress / 0.3 : 1;
// Custom scale based on progress
const scale = 0.8 + progress * 0.2; // 0.8 to 1.0
return (
{/* Text rotates around circle using progress */}
{textPath.onCircle(
"SPINNING TEXT ? AROUND ? ",
960, // center x
540, // center y
400, // radius
progress, // rotation offset (0-1 animates full rotation)
{
fontSize: "3xl",
fontWeight: "bold",
color: "yellow-300"
}
)}
);
}
Animated text reveal along a path:
export default function PathTextReveal({ tw, textPath, progress }) {
// Create custom path follower that animates position
const pathFollower = (t) => {
// Only show characters up to current progress
const visibleProgress = progress * 1.5; // Extend range for smooth reveal
const opacity = t < visibleProgress ? 1 : 0;
// Follow quadratic curve
const pos = {
x: (1 - t) * (1 - t) * 200 + 2 * (1 - t) * t * 960 + t * t * 1720,
y: (1 - t) * (1 - t) * 400 + 2 * (1 - t) * t * 150 + t * t * 400,
angle: 0
};
return { ...pos, opacity };
};
return (
// Text along a circular arc
textPath.onArc(
"ARC TEXT",
960, // center x
540, // center y
400, // radius
0, // start angle (degrees)
180, // end angle (degrees)
{ fontSize: "2xl", color: "pink-300" }
)
Options
All textPath functions accept an optional options object:
{
fontSize?: string; // Tailwind size: "xl", "2xl", "4xl", etc.
fontWeight?: string; // Tailwind weight: "bold", "semibold", etc.
color?: string; // Tailwind color: "white", "blue-500", etc.
letterSpacing?: number; // Space between characters (0-1, default: 0)
style?: any; // Additional inline styles
}
export default function MyTemplate({
// Core helpers (RESERVED - cannot be used as prop names)
tw, // Tailwind class converter
qr, // QR code generator (this page)
template, // Template composer (this page)
config, // User config from loopwind.json (this page)
textPath, // Text on path helpers (this page)
// Media helpers (RESERVED)
image, // Image embedder → see /images
path, // Path following → see /animation
// Video-specific (RESERVED - only in video templates)
frame, // Current frame number → see /templates
progress, // Animation progress 0-1 → see /templates
// Your custom props (use any names EXCEPT the reserved ones above)
...props // Any props from your meta.props
}) {
// Your template code
}
Next Steps
Embedding Images
Templates
Styling with Tailwind & shadcn/ui
Custom Fonts
Styling Templates
Style your templates with Tailwind utility classes and shadcn/ui's beautiful design system.
Quick Start
export default function MyTemplate({ title, tw }) {
return (
{title}
);
}
The tw() Function
Every template receives a tw() function that converts Tailwind classes to inline styles compatible with Satori:
Use Tailwind's slash syntax for opacity with any color:
export default function OpacityExample({ tw }) {
return (
{/* 50% opacity */}
{/* 75% opacity */}
Subtle text
{/* 30% opacity */}
Faint border
);
}
Supported syntax:
bg-{color}/{opacity} - Background with opacity
text-{color}/{opacity} - Text with opacity
border-{color}/{opacity} - Border with opacity
Text Hierarchy
// Primary text
tw('text-foreground')
// Secondary/muted text
tw('text-muted-foreground')
// Accent/brand text
tw('text-primary')
// Destructive/error text
tw('text-destructive')
tw('text-blue-500') // Standard Tailwind color
tw('bg-purple-600') // Standard Tailwind color
tw('text-primary') // shadcn semantic color
tw('bg-card') // shadcn semantic color
// Gradient direction
tw('bg-gradient-to-r') // left to right
tw('bg-gradient-to-br') // top-left to bottom-right
tw('bg-gradient-to-t') // bottom to top
// Gradient colors
tw('from-blue-500') // Start color
tw('via-purple-500') // Middle color
tw('to-pink-500') // End color
// Complete gradient
tw('bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500')
Gradient Examples
export default function GradientCard({ title, tw }) {
return (
{title}
);
}
Custom Theme Colors
You can override the default shadcn colors or add your own custom colors in .loopwind/loopwind.json:
{/* Uses Inter Bold from loopwind.json */}
{title}
Available classes:
font-sans - Uses fonts.sans from loopwind.json
font-serif - Uses fonts.serif from loopwind.json
font-mono - Uses fonts.mono from loopwind.json
Supported formats:
? WOFF (.woff) - Recommended for best compatibility
? TTF (.ttf) - Also supported
? OTF (.otf) - Also supported
? WOFF2 (.woff2) - Not supported by renderer
Font Loading Priority
loopwind loads fonts in this order:
loopwind.json fonts (if configured with files)
Bundled Inter fonts (included with CLI)
This ensures fonts work out of the box with no configuration.
Default Fonts
If no fonts are configured, loopwind uses Inter (Regular 400, Bold 700) which is bundled with the CLI. This means fonts work offline with no configuration required.
Best Practices
? Use loopwind.json for project-wide fonts - Configure once, use everywhere
? Use font classes - tw('font-sans') instead of fontFamily: 'Inter'
? Include fallbacks - Always add system fonts: ["Inter", "system-ui", "sans-serif"]
? Match names - First font in family array is used as the loaded font name
? Relative paths - Font paths are relative to loopwind.json location