loopwind 0.10.3 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- # dsgn - Complete Documentation for LLMs
1
+ # loopwind - Complete Documentation for LLMs
2
2
 
3
- This is a comprehensive, single-file documentation for dsgn, optimized for LLM consumption.
4
- Generated: 2025-11-17T21:03:55.855Z
3
+ This is a comprehensive, single-file documentation for loopwind, optimized for LLM consumption.
4
+ Generated: 2025-11-18T13:58:54.278Z
5
5
 
6
6
  ---
7
7
 
@@ -11,6 +11,38 @@ Generated: 2025-11-17T21:03:55.855Z
11
11
  FILE: index.mdx
12
12
  ================================================================================
13
13
 
14
+ import CodeVideoDemo from '../components/CodeVideoDemo.astro';
15
+
16
+ export const videoCode = `export default function VideoIntro({ tw, title, subtitle }) {
17
+ return (
18
+ <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gradient-to-br from-blue-600 to-purple-700 gap-4')}>
19
+ <h1 style={tw('text-8xl font-bold text-white ease-out animate-bounce-in/0/0.4')}>
20
+ {title}
21
+ </h1>
22
+ <p style={tw('text-2xl text-white/80 ease-out animate-fade-in-up/0.3/0.7')}>
23
+ {subtitle}
24
+ </p>
25
+ </div>
26
+ );
27
+ }`;
28
+
29
+ ## Video Templates
30
+
31
+ <CodeVideoDemo
32
+ code={videoCode}
33
+ videoSrc="/demo-intro.mp4"
34
+ title="Animated Intro Example"
35
+ />
36
+
37
+ **Render it:**
38
+ ```bash
39
+ loopwind render video-intro '{"title":"Welcome!","subtitle":"Built with loopwind"}' --out intro.mp4
40
+ ```
41
+
42
+ **Output:** `_loopwind/outputs/intro.mp4` (1920×1080px, 3 seconds @ 30fps)
43
+
44
+ **Perfect for:** Social media intros, animated logos, tutorial overlays, and product showcases.
45
+
14
46
  ## Image Templates
15
47
 
16
48
  ```tsx
@@ -20,7 +52,7 @@ export default function OGImage({ tw, image, title, description, logo }) {
20
52
  <div style={tw('flex w-full h-full bg-white')}>
21
53
  <div style={tw('flex-1 flex flex-col justify-between p-12')}>
22
54
  <img src={image(logo)} style={tw('h-12 w-auto')} />
23
-
55
+
24
56
  <div>
25
57
  <h1 style={tw('text-5xl font-bold text-gray-900 mb-4')}>
26
58
  {title}
@@ -29,13 +61,13 @@ export default function OGImage({ tw, image, title, description, logo }) {
29
61
  {description}
30
62
  </p>
31
63
  </div>
32
-
64
+
33
65
  <p style={tw('text-gray-400')}>yoursite.com</p>
34
66
  </div>
35
-
67
+
36
68
  <div style={tw('flex-1')}>
37
- <img
38
- src={image(featuredImage)}
69
+ <img
70
+ src={image(featuredImage)}
39
71
  style={tw('w-full h-full object-cover')}
40
72
  />
41
73
  </div>
@@ -46,70 +78,39 @@ export default function OGImage({ tw, image, title, description, logo }) {
46
78
 
47
79
  **Render it:**
48
80
  ```bash
49
- dsgn render og-image '{"title":"Hello World","description":"My awesome blog post"}'
81
+ loopwind render og-image '{"title":"Hello World","description":"My awesome blog post"}'
50
82
  ```
51
83
 
52
- **Output:** `og-image.png` (1200×630px) in your current directory
84
+ **Output:** `_loopwind/outputs/og-image.png` (1200×630px)
53
85
 
54
86
  **Perfect for:** Open Graph images, Twitter cards, blog headers, product cards, and quote graphics.
55
87
 
56
- ## Video Templates
57
-
58
- ```tsx
59
- // Animated intro video
60
- export default function VideoIntro({ tw, progress, title }) {
61
- // Fade in animation
62
- const titleOpacity = progress < 0.3 ? progress / 0.3 : 1;
63
-
64
- return (
65
- <div style={tw('flex items-center justify-center w-full h-full bg-gradient-to-br from-blue-600 to-purple-700')}>
66
- <h1
67
- style={{
68
- ...tw('text-8xl font-bold text-white'),
69
- opacity: titleOpacity
70
- }}
71
- >
72
- {title}
73
- </h1>
74
- </div>
75
- );
76
- }
77
- ```
78
-
79
- **Render it:**
80
- ```bash
81
- dsgn render video-intro '{"title":"Welcome!"}' --out intro.mp4
82
- ```
83
-
84
- **Output:** `intro.mp4` (1920×1080px, 3 seconds @ 30fps) in your current directory
85
-
86
- **Perfect for:** Social media intros, animated logos, tutorial overlays, and product showcases.
87
-
88
88
  ## Features
89
89
 
90
90
  - 🎨 **shadcn/ui Design System**: Beautiful, semantic colors out of the box (`text-primary`, `bg-card`, etc.)
91
91
  - ✨ **Template-based**: Install design templates like you install UI components
92
+ - 🖼️ **Serverless Image Rendering**: Pure JavaScript rendering with Satori - works on Vercel, Netlify, Cloudflare Workers
93
+ - 🎬 **Serverless Video Rendering**: WASM-based MP4 encoding - 12x faster than traditional approaches
92
94
  - 🎨 **Tailwind CSS Support**: Style templates with Tailwind utility classes + opacity modifiers (`bg-primary/50`)
93
95
  - 📱 **Built-in Helpers**: QR codes, image embedding, video backgrounds, template composition
94
96
  - ✅ **Smart Validation**: Automatic prop and template validation with helpful error messages
95
97
  - 🚀 **Framework-agnostic**: Works with Node, Bun, Deno, Laravel, Python, and more
96
98
  - 🤖 **Agent-friendly**: Machine-readable metadata for LLMs
97
- - 📦 **Easy installation**: `npx dsgn add template-name`
98
- - 🎬 **Video support**: Render animated videos with frame-by-frame control
99
- - ⚡ **Powered by Satori**: Generate images from React + Tailwind
99
+ - 📦 **Easy installation**: `npx loopwind add template-name`
100
+ - 🌐 **Pure JavaScript/WASM**: No native dependencies, works everywhere
100
101
 
101
102
  ## Quick Start
102
103
 
103
104
  ### Installation
104
105
 
105
106
  ```bash
106
- npm install -g dsgn
107
+ npm install -g loopwind
107
108
  ```
108
109
 
109
110
  Or use with npx:
110
111
 
111
112
  ```bash
112
- npx dsgn --help
113
+ npx loopwind --help
113
114
  ```
114
115
 
115
116
  ### Initialize in Your Project
@@ -117,163 +118,110 @@ npx dsgn --help
117
118
  Navigate to any project folder and run:
118
119
 
119
120
  ```bash
120
- dsgn init
121
+ loopwind init
121
122
  ```
122
123
 
123
- This creates a `_dsgn/` folder where templates will be installed.
124
+ This creates a `_loopwind/` folder where templates and outputs will be located.
124
125
 
125
126
  ### Install a Template
126
127
 
127
- Templates can be installed from multiple sources:
128
-
129
- #### 1. Official Registry (Coming Soon)
128
+ #### 1. Official Templates
130
129
 
131
130
  ```bash
132
- dsgn add banner-hero
133
- dsgn add og-image --registry https://custom-registry.com/r
131
+ loopwind add image-template
132
+ loopwind add video-template
134
133
  ```
135
134
 
136
- #### 2. GitHub Repositories
137
-
138
- ```bash
139
- # From a GitHub repo (looks for template.json in repo root)
140
- dsgn add github:username/repo
141
-
142
- # From a specific path in the repo
143
- dsgn add github:username/repo/templates/banner-hero
144
-
145
- # From an organization
146
- dsgn add github:myorg/design-templates/social-media/og-image
147
- ```
148
-
149
- #### 3. Direct URLs
150
-
151
- ```bash
152
- # Install from any publicly accessible URL
153
- dsgn add https://example.com/templates/my-template.json
154
- dsgn add https://cdn.example.com/templates/awesome-banner.json
155
- ```
156
-
157
- **Requirements:**
158
- - URL must return JSON in the registry template format
159
- - Must be publicly accessible (no authentication)
160
-
161
- #### 4. Local Filesystem
162
-
163
- ```bash
164
- # Relative path
165
- dsgn add ./my-templates/banner-hero
166
- dsgn add ../shared-templates/product-card
167
-
168
- # Absolute path
169
- dsgn add /Users/you/templates/social-card
170
- ```
171
-
172
- **Use cases:**
173
- - Development and testing
174
- - Private templates
175
- - Shared team templates (monorepo)
176
- - Before publishing to registry
177
-
178
- Templates are installed to: `_dsgn/templates/<template>/` (customizable in `dsgn.json`)
135
+ Templates are installed to: `_loopwind/templates/<template>/` (customizable in `loopwind.json`)
179
136
 
180
137
  **Benefits:**
181
- - Templates are local to your project (like npm packages)
182
- - Different projects can use different template versions
138
+ - Templates are local to your project
183
139
  - Version controlled with your project
184
140
  - Easy to share within your team
185
- - Works offline once installed
186
141
 
187
- ### Render an Image
142
+ ### Output a Template
188
143
 
189
144
  ```bash
190
- dsgn render banner-hero '{"title":"Hello World","subtitle":"Built with dsgn"}'
191
- ```
192
-
193
- Output: `banner-hero.png` (1600x900px)
194
-
195
- You can also use a props file:
196
- ```bash
197
- dsgn render banner-hero props.json
145
+ loopwind render template-name '{"title":"Hello World","subtitle":"Built with loopwind"}'
198
146
  ```
199
147
 
200
148
  ## Commands
201
149
 
202
- ### `dsgn add <source>`
150
+ ### `loopwind add <source>`
203
151
 
204
152
  Install a template from various sources:
205
153
 
206
154
  ```bash
207
155
  # From registry
208
- dsgn add banner-hero
156
+ loopwind add banner-hero
209
157
 
210
158
  # From GitHub
211
- dsgn add github:username/repo/path/to/template
159
+ loopwind add github:username/repo/path/to/template
212
160
 
213
161
  # From URL
214
- dsgn add https://example.com/my-template.json
162
+ loopwind add https://example.com/my-template.json
215
163
 
216
164
  # From local path
217
- dsgn add ./my-templates/custom-banner
165
+ loopwind add ./my-templates/custom-banner
218
166
  ```
219
167
 
220
- ### `dsgn list`
168
+ ### `loopwind list`
221
169
 
222
170
  List all installed templates:
223
171
 
224
172
  ```bash
225
- dsgn list
173
+ loopwind list
226
174
  ```
227
175
 
228
- ### `dsgn render <template> <props> [options]`
176
+ ### `loopwind render <template> <props> [options]`
229
177
 
230
178
  Render an image or video:
231
179
 
232
180
  ```bash
233
181
  # Image with inline props
234
- dsgn render banner-hero '{"title":"Hello World"}'
182
+ loopwind render banner-hero '{"title":"Hello World"}'
235
183
 
236
184
  # Video with inline props
237
- dsgn render video-intro '{"title":"Welcome"}' --out intro.mp4
185
+ loopwind render video-intro '{"title":"Welcome"}' --out intro.mp4
238
186
 
239
187
  # Using a props file
240
- dsgn render banner-hero props.json
188
+ loopwind render banner-hero props.json
241
189
 
242
190
  # Custom output
243
- dsgn render banner-hero '{"title":"Hello"}' --out custom-name.png
191
+ loopwind render banner-hero '{"title":"Hello"}' --out custom-name.png
244
192
 
245
193
  # Different format
246
- dsgn render banner-hero '{"title":"Hello"}' --format jpeg
194
+ loopwind render banner-hero '{"title":"Hello"}' --format jpeg
247
195
  ```
248
196
 
249
197
  Options:
250
- - `--out, -o` - Output filename (default: `<template>.<ext>`)
198
+ - `--out, -o` - Output filename (default: `_loopwind/outputs/<template>.<ext>`)
251
199
  - `--format` - Output format: `png`, `jpeg`, `svg` (images only)
252
200
  - `--quality` - JPEG quality 1-100 (default: 92)
253
201
 
254
- ### `dsgn validate <template>`
202
+ ### `loopwind validate <template>`
255
203
 
256
204
  Validate a template:
257
205
 
258
206
  ```bash
259
- dsgn validate banner-hero
207
+ loopwind validate banner-hero
260
208
  ```
261
209
 
262
210
  Checks:
263
211
  - Template file exists and is valid React
264
- - `meta.json` exists and is valid
212
+ - `export const meta` exists and is valid
265
213
  - Required props are defined
266
214
  - Fonts exist (if specified)
267
215
 
268
- ### `dsgn init`
216
+ ### `loopwind init`
269
217
 
270
- Initialize dsgn in a project:
218
+ Initialize loopwind in a project:
271
219
 
272
220
  ```bash
273
- dsgn init
221
+ loopwind init
274
222
  ```
275
223
 
276
- Creates `dsgn.json` configuration file.
224
+ Creates `loopwind.json` configuration file.
277
225
 
278
226
  ## Next Steps
279
227
 
@@ -296,7 +244,7 @@ FILE: templates.mdx
296
244
 
297
245
  ## Overview
298
246
 
299
- dsgn supports installing templates from multiple sources:
247
+ loopwind supports installing templates from multiple sources:
300
248
 
301
249
  1. **Official Registry** (default)
302
250
  2. **Direct URLs**
@@ -305,25 +253,25 @@ dsgn supports installing templates from multiple sources:
305
253
 
306
254
  ## 1. Official Registry (Default)
307
255
 
308
- Install templates from the official dsgn registry at `https://dsgncli.com/r`
256
+ Install templates from the official loopwind registry at `https://loopwind.dev/r`
309
257
 
310
258
  ```bash
311
- dsgn add banner-hero
312
- dsgn add product-card
313
- dsgn add social-og-image
259
+ loopwind add banner-hero
260
+ loopwind add product-card
261
+ loopwind add social-og-image
314
262
  ```
315
263
 
316
264
  **How it works:**
317
- - Fetches from: `https://dsgncli.com/r/banner-hero`
265
+ - Fetches from: `https://loopwind.dev/r/banner-hero`
318
266
  - Returns JSON with template files
319
- - Installs to: `_dsgn/templates/banner-hero/`
267
+ - Installs to: `_loopwind/templates/banner-hero/`
320
268
 
321
269
  ### Custom Registry
322
270
 
323
271
  Use a different registry:
324
272
 
325
273
  ```bash
326
- dsgn add banner-hero --registry https://my-registry.com/templates
274
+ loopwind add banner-hero --registry https://my-registry.com/templates
327
275
  ```
328
276
 
329
277
  ## 2. Direct URLs
@@ -331,8 +279,8 @@ dsgn add banner-hero --registry https://my-registry.com/templates
331
279
  Install a template from any publicly accessible URL:
332
280
 
333
281
  ```bash
334
- dsgn add https://example.com/templates/my-template.json
335
- dsgn add https://cdn.example.com/templates/awesome-banner.json
282
+ loopwind add https://example.com/templates/my-template.json
283
+ loopwind add https://cdn.example.com/templates/awesome-banner.json
336
284
  ```
337
285
 
338
286
  **Requirements:**
@@ -365,13 +313,13 @@ Install templates directly from GitHub repos:
365
313
 
366
314
  ```bash
367
315
  # From a GitHub repo (looks for template.json in repo root)
368
- dsgn add github:username/repo
316
+ loopwind add github:username/repo
369
317
 
370
318
  # From a specific path in the repo
371
- dsgn add github:username/repo/templates/banner-hero
319
+ loopwind add github:username/repo/templates/banner-hero
372
320
 
373
321
  # From an organization
374
- dsgn add github:myorg/design-templates/social-media/og-image
322
+ loopwind add github:myorg/design-templates/social-media/og-image
375
323
  ```
376
324
 
377
325
  **How it works:**
@@ -404,11 +352,11 @@ Install templates from your local filesystem:
404
352
 
405
353
  ```bash
406
354
  # Relative path
407
- dsgn add ./my-templates/banner-hero
408
- dsgn add ../shared-templates/product-card
355
+ loopwind add ./my-templates/banner-hero
356
+ loopwind add ../shared-templates/product-card
409
357
 
410
358
  # Absolute path
411
- dsgn add /Users/you/templates/social-card
359
+ loopwind add /Users/you/templates/social-card
412
360
  ```
413
361
 
414
362
  **Use cases:**
@@ -419,9 +367,9 @@ dsgn add /Users/you/templates/social-card
419
367
 
420
368
  ## Template Installation Directory
421
369
 
422
- Templates are installed to `_dsgn/templates/<template-name>/` by default.
370
+ Templates are installed to `_loopwind/templates/<template-name>/` by default.
423
371
 
424
- Customize this in `dsgn.json`:
372
+ Customize this in `loopwind.json`:
425
373
 
426
374
  ```json
427
375
  {
@@ -455,22 +403,22 @@ FILE: images.mdx
455
403
 
456
404
  # Image Rendering
457
405
 
458
- Generate beautiful images from React components using dsgn's powerful image rendering engine powered by Satori.
406
+ Generate beautiful images from React components using loopwind's powerful image rendering engine powered by Satori.
459
407
 
460
408
  ## Quick Start
461
409
 
462
410
  ```bash
463
411
  # Render an image template with inline props
464
- dsgn render banner-hero '{"title":"Hello World","subtitle":"Welcome"}'
412
+ loopwind render banner-hero '{"title":"Hello World","subtitle":"Welcome"}'
465
413
 
466
414
  # Custom output name
467
- dsgn render banner-hero '{"title":"Hello"}' --out custom-name.png
415
+ loopwind render banner-hero '{"title":"Hello"}' --out custom-name.png
468
416
 
469
417
  # Different format
470
- dsgn render banner-hero '{"title":"Hello"}' --format jpeg --quality 95
418
+ loopwind render banner-hero '{"title":"Hello"}' --format jpeg --quality 95
471
419
 
472
420
  # Or use a props file
473
- dsgn render banner-hero props.json
421
+ loopwind render banner-hero props.json
474
422
  ```
475
423
 
476
424
  ## Image Template Structure
@@ -479,6 +427,14 @@ dsgn render banner-hero props.json
479
427
 
480
428
  ```tsx
481
429
  // banner-hero.tsx
430
+ export const meta = {
431
+ name: "banner-hero",
432
+ type: "image",
433
+ description: "Hero banner with gradient background",
434
+ size: { width: 1600, height: 900 },
435
+ props: { title: "string", subtitle: "string" }
436
+ };
437
+
482
438
  export default function BannerHero({ title, subtitle, tw }) {
483
439
  return (
484
440
  <div style={tw('flex flex-col justify-center items-center w-full h-full bg-gradient-to-br from-purple-600 to-blue-500 p-12')}>
@@ -493,29 +449,11 @@ export default function BannerHero({ title, subtitle, tw }) {
493
449
  }
494
450
  ```
495
451
 
496
- ### Metadata (meta.json)
497
-
498
- ```json
499
- {
500
- "name": "banner-hero",
501
- "type": "image",
502
- "description": "Hero banner with gradient background",
503
- "size": {
504
- "width": 1600,
505
- "height": 900
506
- },
507
- "props": {
508
- "title": "string",
509
- "subtitle": "string"
510
- }
511
- }
512
- ```
513
-
514
452
  ### Props File
515
453
 
516
454
  ```json
517
455
  {
518
- "title": "Welcome to dsgn",
456
+ "title": "Welcome to loopwind",
519
457
  "subtitle": "Generate beautiful images from React"
520
458
  }
521
459
  ```
@@ -525,8 +463,8 @@ export default function BannerHero({ title, subtitle, tw }) {
525
463
  ### PNG (Default)
526
464
 
527
465
  ```bash
528
- dsgn render my-template '{"title":"Hello"}'
529
- # Output: my-template.png
466
+ loopwind render my-template '{"title":"Hello"}'
467
+ # Output: _loopwind/outputs/my-template.png
530
468
  ```
531
469
 
532
470
  **Best for:**
@@ -538,7 +476,7 @@ dsgn render my-template '{"title":"Hello"}'
538
476
  ### JPEG
539
477
 
540
478
  ```bash
541
- dsgn render my-template '{"title":"Hello"}' --format jpeg --quality 92
479
+ loopwind render my-template '{"title":"Hello"}' --format jpeg --quality 92
542
480
  ```
543
481
 
544
482
  **Options:**
@@ -553,7 +491,7 @@ dsgn render my-template '{"title":"Hello"}' --format jpeg --quality 92
553
491
  ### SVG
554
492
 
555
493
  ```bash
556
- dsgn render my-template '{"title":"Hello"}' --format svg
494
+ loopwind render my-template '{"title":"Hello"}' --format svg
557
495
  ```
558
496
 
559
497
  **Best for:**
@@ -753,13 +691,13 @@ Render multiple images at once:
753
691
 
754
692
  ```bash
755
693
  # Using a script with inline props
756
- dsgn render my-template '{"title":"Image 1"}'
757
- dsgn render my-template '{"title":"Image 2"}'
758
- dsgn render my-template '{"title":"Image 3"}'
694
+ loopwind render my-template '{"title":"Image 1"}'
695
+ loopwind render my-template '{"title":"Image 2"}'
696
+ loopwind render my-template '{"title":"Image 3"}'
759
697
 
760
698
  # Or loop through props files
761
699
  for props in props/*.json; do
762
- dsgn render my-template "$props"
700
+ loopwind render my-template "$props"
763
701
  done
764
702
  ```
765
703
 
@@ -794,18 +732,21 @@ Templates are cached after first load for faster subsequent renders.
794
732
 
795
733
  ### Fonts Not Rendering
796
734
 
797
- Make sure fonts are properly loaded in `meta.json`:
735
+ Make sure fonts are properly defined in your template's meta:
798
736
 
799
- ```json
800
- {
801
- "fonts": [
737
+ ```tsx
738
+ export const meta = {
739
+ name: "my-template",
740
+ // ...
741
+ fonts: [
802
742
  {
803
- "name": "Inter",
804
- "path": "fonts/Inter-Bold.woff",
805
- "weight": 700
743
+ name: "Inter",
744
+ path: "fonts/Inter-Bold.woff",
745
+ weight: 700,
746
+ style: "normal"
806
747
  }
807
748
  ]
808
- }
749
+ };
809
750
  ```
810
751
 
811
752
  ### Images Not Loading
@@ -846,13 +787,13 @@ Create animated videos programmatically using React components. Perfect for auto
846
787
 
847
788
  ```bash
848
789
  # Render a video template with inline props
849
- dsgn render video-intro '{"title":"Welcome!"}' --out intro.mp4
790
+ loopwind render video-intro '{"title":"Welcome!"}' --out intro.mp4
850
791
 
851
792
  # With custom encoding
852
- dsgn render video-intro '{"title":"Welcome!"}' --preset ultrafast
793
+ loopwind render video-intro '{"title":"Welcome!"}' --preset ultrafast
853
794
 
854
795
  # Or use a props file
855
- dsgn render video-intro props.json --out intro.mp4
796
+ loopwind render video-intro props.json --out intro.mp4
856
797
  ```
857
798
 
858
799
  ## Video Template Structure
@@ -861,13 +802,22 @@ dsgn render video-intro props.json --out intro.mp4
861
802
 
862
803
  ```tsx
863
804
  // video-intro.tsx
805
+ export const meta = {
806
+ name: "video-intro",
807
+ type: "video",
808
+ description: "Animated intro with fade-in title",
809
+ size: { width: 1920, height: 1080 },
810
+ video: { fps: 30, duration: 3 },
811
+ props: { title: "string" }
812
+ };
813
+
864
814
  export default function VideoIntro({ tw, title, frame, progress }) {
865
815
  // Animate opacity based on progress
866
816
  const titleOpacity = progress < 0.3 ? progress / 0.3 : 1;
867
-
817
+
868
818
  return (
869
819
  <div style={tw('flex items-center justify-center w-full h-full bg-gradient-to-br from-blue-600 to-purple-700')}>
870
- <h1
820
+ <h1
871
821
  style={{
872
822
  ...tw('text-8xl font-bold text-white'),
873
823
  opacity: titleOpacity
@@ -875,7 +825,7 @@ export default function VideoIntro({ tw, title, frame, progress }) {
875
825
  >
876
826
  {title}
877
827
  </h1>
878
-
828
+
879
829
  {/* Show frame counter */}
880
830
  <div style={tw('absolute bottom-10 right-10 text-white text-sm')}>
881
831
  Frame: {frame}
@@ -885,27 +835,6 @@ export default function VideoIntro({ tw, title, frame, progress }) {
885
835
  }
886
836
  ```
887
837
 
888
- ### Metadata (meta.json)
889
-
890
- ```json
891
- {
892
- "name": "video-intro",
893
- "type": "video",
894
- "description": "Animated intro with fade-in title",
895
- "size": {
896
- "width": 1920,
897
- "height": 1080
898
- },
899
- "video": {
900
- "fps": 30,
901
- "duration": 3
902
- },
903
- "props": {
904
- "title": "string"
905
- }
906
- }
907
- ```
908
-
909
838
  ### Props File
910
839
 
911
840
  ```json
@@ -946,7 +875,48 @@ export default function MyVideo({ progress }) {
946
875
 
947
876
  ## Animation Patterns
948
877
 
949
- ### Fade In/Out
878
+ ### Pulse Animation
879
+
880
+ ```tsx
881
+ export default function PulseVideo({ tw, title }) {
882
+ return (
883
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
884
+ <h1 style={tw('text-8xl font-bold text-white animate-pulse')}>
885
+ {title}
886
+ </h1>
887
+ </div>
888
+ );
889
+ }
890
+ ```
891
+
892
+ ### Spin Animation
893
+
894
+ ```tsx
895
+ export default function SpinVideo({ tw, title }) {
896
+ return (
897
+ <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gradient-to-br from-purple-600 to-pink-600 gap-8')}>
898
+ <div style={tw('w-32 h-32 border-8 border-white border-t-transparent rounded-full animate-spin')} />
899
+ <h1 style={tw('text-6xl font-bold text-white')}>{title}</h1>
900
+ </div>
901
+ );
902
+ }
903
+ ```
904
+
905
+ ### Bounce Animation
906
+
907
+ ```tsx
908
+ export default function BounceVideo({ tw, title }) {
909
+ return (
910
+ <div style={tw('flex items-center justify-center w-full h-full bg-blue-600')}>
911
+ <h1 style={tw('text-8xl font-bold text-white animate-bounce')}>
912
+ {title}
913
+ </h1>
914
+ </div>
915
+ );
916
+ }
917
+ ```
918
+
919
+ ### Fade with Progress
950
920
 
951
921
  ```tsx
952
922
  export default function FadeVideo({ progress, title, tw }) {
@@ -1002,18 +972,76 @@ export default function ScaleVideo({ progress, tw }) {
1002
972
  }
1003
973
  ```
1004
974
 
1005
- ### Rotation
975
+ ### Progress-Based Rotation
1006
976
 
1007
977
  ```tsx
1008
978
  export default function RotateVideo({ progress, tw }) {
1009
- // Rotate 360 degrees
979
+ // Rotate 360 degrees based on progress
1010
980
  const rotation = progress * 360;
1011
981
 
1012
982
  return (
1013
- <div style={{
1014
- ...tw('w-32 h-32 bg-blue-500 rounded-lg'),
1015
- transform: `rotate(${rotation}deg)`
1016
- }}>
983
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
984
+ <div style={{
985
+ ...tw('w-32 h-32 bg-blue-500 rounded-lg'),
986
+ transform: `rotate(${rotation}deg)`
987
+ }}>
988
+ </div>
989
+ </div>
990
+ );
991
+ }
992
+ ```
993
+
994
+ ### Using Tailwind Animations
995
+
996
+ Combine Tailwind's built-in animations with progress-based animations:
997
+
998
+ ```tsx
999
+ export default function PulsingLogo({ tw, progress, image, logo }) {
1000
+ // Fade in based on progress
1001
+ const opacity = Math.min(progress / 0.3, 1);
1002
+
1003
+ return (
1004
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
1005
+ {/* Tailwind's animate-pulse + custom opacity */}
1006
+ <div style={{ ...tw('animate-pulse'), opacity }}>
1007
+ <img src={image(logo)} style={tw('w-64 h-64')} />
1008
+ </div>
1009
+ </div>
1010
+ );
1011
+ }
1012
+ ```
1013
+
1014
+ **Available Tailwind animations:**
1015
+ - `animate-spin` - Continuous rotation
1016
+ - `animate-pulse` - Subtle fade in/out
1017
+ - `animate-bounce` - Bouncing motion
1018
+ - `animate-ping` - Ripple effect (great for badges)
1019
+
1020
+ **Example with multiple animations:**
1021
+
1022
+ ```tsx
1023
+ export default function NotificationVideo({ tw, progress, title }) {
1024
+ const slideX = -100 + (progress * 100); // Slide in from left
1025
+
1026
+ return (
1027
+ <div style={tw('flex items-center justify-center w-full h-full bg-gradient-to-br from-purple-600 to-blue-600')}>
1028
+ <div
1029
+ style={{
1030
+ ...tw('flex items-center gap-4 bg-white rounded-2xl p-6 shadow-2xl'),
1031
+ transform: `translateX(${slideX}%)`
1032
+ }}
1033
+ >
1034
+ {/* Pinging indicator */}
1035
+ <div style={tw('relative')}>
1036
+ <div style={tw('w-3 h-3 bg-green-500 rounded-full animate-ping absolute')} />
1037
+ <div style={tw('w-3 h-3 bg-green-500 rounded-full')} />
1038
+ </div>
1039
+
1040
+ <div>
1041
+ <h2 style={tw('text-2xl font-bold text-gray-900')}>{title}</h2>
1042
+ <p style={tw('text-gray-600')}>New notification</p>
1043
+ </div>
1044
+ </div>
1017
1045
  </div>
1018
1046
  );
1019
1047
  }
@@ -1078,7 +1106,7 @@ export default function VideoOverlay({ tw, video, title, background }) {
1078
1106
  ### How Video Sync Works
1079
1107
 
1080
1108
  1. **First pass**: Template calls `video()` to register needed videos
1081
- 2. **Pre-processing**: dsgn extracts all frames at template's FPS
1109
+ 2. **Pre-processing**: loopwind extracts all frames at template's FPS
1082
1110
  3. **Rendering**: Each frame uses the corresponding video frame
1083
1111
  4. **Caching**: Frames are cached in memory for fast access
1084
1112
 
@@ -1386,31 +1414,28 @@ export default function TutorialVideo({
1386
1414
 
1387
1415
  ### Common Frame Rates
1388
1416
 
1389
- ```json
1390
- {
1391
- "video": {
1392
- "fps": 24, // Film standard
1393
- "duration": 5
1394
- }
1395
- }
1417
+ ```tsx
1418
+ // Film standard
1419
+ export const meta = {
1420
+ // ...
1421
+ video: { fps: 24, duration: 5 }
1422
+ };
1396
1423
  ```
1397
1424
 
1398
- ```json
1399
- {
1400
- "video": {
1401
- "fps": 30, // YouTube/web standard
1402
- "duration": 3
1403
- }
1404
- }
1425
+ ```tsx
1426
+ // YouTube/web standard
1427
+ export const meta = {
1428
+ // ...
1429
+ video: { fps: 30, duration: 3 }
1430
+ };
1405
1431
  ```
1406
1432
 
1407
- ```json
1408
- {
1409
- "video": {
1410
- "fps": 60, // Smooth animations
1411
- "duration": 2
1412
- }
1413
- }
1433
+ ```tsx
1434
+ // Smooth animations
1435
+ export const meta = {
1436
+ // ...
1437
+ video: { fps: 60, duration: 2 }
1438
+ };
1414
1439
  ```
1415
1440
 
1416
1441
  **Total frames = fps × duration**
@@ -1429,7 +1454,7 @@ export default function TutorialVideo({
1429
1454
  ### Default (Balanced)
1430
1455
 
1431
1456
  ```bash
1432
- dsgn render video-intro '{"title":"Welcome"}'
1457
+ loopwind render video-intro '{"title":"Welcome"}'
1433
1458
  ```
1434
1459
 
1435
1460
  Uses H.264 codec with good quality/size balance.
@@ -1437,7 +1462,7 @@ Uses H.264 codec with good quality/size balance.
1437
1462
  ### Fast Encoding
1438
1463
 
1439
1464
  ```bash
1440
- dsgn render video-intro '{"title":"Welcome"}' --preset ultrafast
1465
+ loopwind render video-intro '{"title":"Welcome"}' --preset ultrafast
1441
1466
  ```
1442
1467
 
1443
1468
  Faster encoding, slightly larger files. Good for previews.
@@ -1445,7 +1470,7 @@ Faster encoding, slightly larger files. Good for previews.
1445
1470
  ### High Quality
1446
1471
 
1447
1472
  ```bash
1448
- dsgn render video-intro '{"title":"Welcome"}' --preset slow
1473
+ loopwind render video-intro '{"title":"Welcome"}' --preset slow
1449
1474
  ```
1450
1475
 
1451
1476
  Better compression, slower encoding. Good for final output.
@@ -1481,44 +1506,41 @@ For long videos, consider rendering in segments.
1481
1506
 
1482
1507
  ## Common Video Templates
1483
1508
 
1484
- ### Social Media Intro
1509
+ ### Loading Spinner
1485
1510
 
1486
1511
  ```tsx
1487
- export default function SocialIntro({ tw, progress, brand, tagline }) {
1488
- const logoScale = progress < 0.4 ? progress / 0.4 : 1;
1489
- const taglineOpacity = progress > 0.5 ? (progress - 0.5) / 0.5 : 0;
1512
+ export default function LoadingVideo({ tw, progress, title }) {
1513
+ // Show spinner for first 60%, then fade to title
1514
+ const spinnerOpacity = progress < 0.6 ? 1 : (1 - (progress - 0.6) / 0.4);
1515
+ const titleOpacity = progress > 0.6 ? (progress - 0.6) / 0.4 : 0;
1490
1516
 
1491
1517
  return (
1492
- <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gradient-to-br from-pink-500 to-purple-600')}>
1518
+ <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gray-900')}>
1519
+ {/* Tailwind's animate-spin */}
1520
+ <div style={{ opacity: spinnerOpacity }}>
1521
+ <div style={tw('w-32 h-32 border-8 border-blue-500 border-t-transparent rounded-full animate-spin')} />
1522
+ </div>
1523
+
1493
1524
  <h1
1494
1525
  style={{
1495
- ...tw('text-9xl font-black text-white mb-8'),
1496
- transform: `scale(${logoScale})`
1526
+ ...tw('text-6xl font-bold text-white mt-12'),
1527
+ opacity: titleOpacity
1497
1528
  }}
1498
1529
  >
1499
- {brand}
1530
+ {title}
1500
1531
  </h1>
1501
-
1502
- <p
1503
- style={{
1504
- ...tw('text-3xl text-white'),
1505
- opacity: taglineOpacity
1506
- }}
1507
- >
1508
- {tagline}
1509
- </p>
1510
1532
  </div>
1511
1533
  );
1512
1534
  }
1513
1535
  ```
1514
1536
 
1515
- ### Progress Bar Animation
1537
+ ### Progress Bar with Pulse
1516
1538
 
1517
1539
  ```tsx
1518
1540
  export default function ProgressVideo({ tw, progress, title, subtitle }) {
1519
1541
  return (
1520
1542
  <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gray-900 p-12')}>
1521
- <h2 style={tw('text-5xl font-bold text-white mb-12')}>
1543
+ <h2 style={tw('text-5xl font-bold text-white mb-12 animate-pulse')}>
1522
1544
  {title}
1523
1545
  </h2>
1524
1546
 
@@ -1540,7 +1562,7 @@ export default function ProgressVideo({ tw, progress, title, subtitle }) {
1540
1562
  }
1541
1563
  ```
1542
1564
 
1543
- ### Countdown Timer
1565
+ ### Countdown Timer with Pulse
1544
1566
 
1545
1567
  ```tsx
1546
1568
  export default function CountdownVideo({ tw, frame, message }) {
@@ -1549,7 +1571,8 @@ export default function CountdownVideo({ tw, frame, message }) {
1549
1571
 
1550
1572
  return (
1551
1573
  <div style={tw('flex flex-col items-center justify-center w-full h-full bg-black')}>
1552
- <div style={tw('text-[200px] font-black text-white')}>
1574
+ {/* Add pulse animation when counting down */}
1575
+ <div style={tw('text-[200px] font-black text-white animate-pulse')}>
1553
1576
  {secondsRemaining}
1554
1577
  </div>
1555
1578
  <p style={tw('text-3xl text-gray-400 mt-8')}>
@@ -1560,9 +1583,56 @@ export default function CountdownVideo({ tw, frame, message }) {
1560
1583
  }
1561
1584
  ```
1562
1585
 
1563
- ## Output Format
1586
+ ## Output Formats
1564
1587
 
1565
- Videos are always rendered as MP4 (H.264 codec) for maximum compatibility.
1588
+ Videos can be rendered in two formats:
1589
+
1590
+ ### MP4 (Default)
1591
+
1592
+ ```bash
1593
+ # MP4 - H.264 codec, smaller file size, best quality
1594
+ loopwind render video-intro '{"title":"Welcome"}' --out intro.mp4
1595
+
1596
+ # With custom quality (lower CRF = better quality)
1597
+ loopwind render video-intro '{"title":"Welcome"}' --crf 18
1598
+ ```
1599
+
1600
+ **Benefits:**
1601
+ - Smaller file sizes
1602
+ - Better color reproduction
1603
+ - Universal playback support
1604
+ - Best for social media, websites
1605
+
1606
+ ### GIF
1607
+
1608
+ ```bash
1609
+ # GIF - animated, works everywhere
1610
+ loopwind render video-intro '{"title":"Welcome"}' --format gif --out intro.gif
1611
+
1612
+ # Or just use .gif extension
1613
+ loopwind render video-intro '{"title":"Welcome"}' --out intro.gif
1614
+ ```
1615
+
1616
+ **Benefits:**
1617
+ - Works in emails, GitHub READMEs, Slack
1618
+ - No video player needed
1619
+ - Auto-loops by default
1620
+ - Great for short animations
1621
+
1622
+ **Limitations:**
1623
+ - Limited to 256 colors per frame
1624
+ - Larger file sizes than MP4
1625
+ - Some color banding with gradients
1626
+
1627
+ **When to use GIF:**
1628
+ - Short loops (< 5 seconds)
1629
+ - Simple animations with solid colors
1630
+ - Platforms that don't support video (email, GitHub)
1631
+
1632
+ **When to use MP4:**
1633
+ - Longer videos
1634
+ - Complex gradients or photos
1635
+ - Best quality and smallest size
1566
1636
 
1567
1637
  ## Next Steps
1568
1638
 
@@ -1575,6 +1645,487 @@ Videos are always rendered as MP4 (H.264 codec) for maximum compatibility.
1575
1645
 
1576
1646
 
1577
1647
 
1648
+ ================================================================================
1649
+ FILE: animation.mdx
1650
+ ================================================================================
1651
+
1652
+ # Animation
1653
+
1654
+ loopwind provides **Tailwind-style animation classes** that work with `progress` and `frame` to create smooth video animations without writing custom code.
1655
+
1656
+ > **Note:** Animation classes only work with **video templates** and **GIFs**. For static images, animations will have no effect since there's no `progress` or `frame` context.
1657
+
1658
+ ## Quick Start
1659
+
1660
+ ```tsx
1661
+ export default function MyVideo({ tw, title, subtitle }) {
1662
+ return (
1663
+ <div style={tw('flex flex-col items-center justify-center w-full h-full bg-black')}>
1664
+ {/* Bounce in from below during first 40% */}
1665
+ <h1 style={tw('text-8xl font-bold text-white ease-out animate-bounce-in-up/0/0.4')}>
1666
+ {title}
1667
+ </h1>
1668
+
1669
+ {/* Fade in with upward motion from 30% to 70% */}
1670
+ <p style={tw('text-2xl text-white/80 mt-4 ease-out animate-fade-in-up/0.3/0.7')}>
1671
+ {subtitle}
1672
+ </p>
1673
+ </div>
1674
+ );
1675
+ }
1676
+ ```
1677
+
1678
+ ## Transition Animations
1679
+
1680
+ Format: `animate-{type}/{start}/{end}`
1681
+
1682
+ - `{type}` - The animation type (fade-in, bounce-in-up, etc.)
1683
+ - `{start}` - Progress value to start (0-1)
1684
+ - `{end}` - Progress value to end (0-1)
1685
+
1686
+ ### Fade Animations
1687
+
1688
+ Simple opacity transitions with optional direction.
1689
+
1690
+ ```tsx
1691
+ // Fade in from 0% to 50% of the video
1692
+ <h1 style={tw('animate-fade-in/0/0.5')}>Hello</h1>
1693
+
1694
+ // Fade out from 50% to 100%
1695
+ <h1 style={tw('animate-fade-out/0.5/1')}>Goodbye</h1>
1696
+ ```
1697
+
1698
+ | Class | Description |
1699
+ |-------|-------------|
1700
+ | `animate-fade-in/0/1` | Fade in (opacity 0 → 1) |
1701
+ | `animate-fade-out/0/1` | Fade out (opacity 1 → 0) |
1702
+ | `animate-fade-in-up/0/1` | Fade in + slide up (30px) |
1703
+ | `animate-fade-in-down/0/1` | Fade in + slide down (30px) |
1704
+ | `animate-fade-in-left/0/1` | Fade in + slide from left (30px) |
1705
+ | `animate-fade-in-right/0/1` | Fade in + slide from right (30px) |
1706
+ | `animate-fade-out-up/0/1` | Fade out + slide up |
1707
+ | `animate-fade-out-down/0/1` | Fade out + slide down |
1708
+ | `animate-fade-out-left/0/1` | Fade out + slide left |
1709
+ | `animate-fade-out-right/0/1` | Fade out + slide right |
1710
+
1711
+ ### Slide Animations
1712
+
1713
+ Larger movement (100px) with fade.
1714
+
1715
+ ```tsx
1716
+ // Slide in from left
1717
+ <div style={tw('animate-slide-left/0/0.5')}>Content</div>
1718
+
1719
+ // Slide up from bottom
1720
+ <div style={tw('animate-slide-up/0.2/0.8')}>Content</div>
1721
+ ```
1722
+
1723
+ | Class | Description |
1724
+ |-------|-------------|
1725
+ | `animate-slide-left/0/1` | Slide in from left (100px) |
1726
+ | `animate-slide-right/0/1` | Slide in from right (100px) |
1727
+ | `animate-slide-up/0/1` | Slide in from bottom (100px) |
1728
+ | `animate-slide-down/0/1` | Slide in from top (100px) |
1729
+
1730
+ ### Bounce Animations
1731
+
1732
+ Playful entrance with overshoot effect.
1733
+
1734
+ ```tsx
1735
+ // Bounce in with scale overshoot
1736
+ <h1 style={tw('animate-bounce-in/0/0.5')}>Bouncy!</h1>
1737
+
1738
+ // Bounce in from below
1739
+ <div style={tw('animate-bounce-in-up/0/0.6')}>Pop!</div>
1740
+ ```
1741
+
1742
+ | Class | Description |
1743
+ |-------|-------------|
1744
+ | `animate-bounce-in/0/1` | Bounce in with scale overshoot |
1745
+ | `animate-bounce-in-up/0/1` | Bounce in from below |
1746
+ | `animate-bounce-in-down/0/1` | Bounce in from above |
1747
+ | `animate-bounce-in-left/0/1` | Bounce in from left |
1748
+ | `animate-bounce-in-right/0/1` | Bounce in from right |
1749
+
1750
+ ### Scale & Zoom Animations
1751
+
1752
+ Size-based transitions.
1753
+
1754
+ ```tsx
1755
+ // Scale in from 50%
1756
+ <div style={tw('animate-scale-in/0/0.5')}>Growing</div>
1757
+
1758
+ // Zoom in from 0%
1759
+ <div style={tw('animate-zoom-in/0/1')}>Zooming</div>
1760
+ ```
1761
+
1762
+ | Class | Description |
1763
+ |-------|-------------|
1764
+ | `animate-scale-in/0/1` | Scale up from 50% to 100% |
1765
+ | `animate-scale-out/0/1` | Scale up to 150% + fade out |
1766
+ | `animate-zoom-in/0/1` | Zoom in from 0% to 100% |
1767
+ | `animate-zoom-out/0/1` | Zoom out from 100% to 200% + fade |
1768
+
1769
+ ### Rotate & Flip Animations
1770
+
1771
+ Rotation-based transitions.
1772
+
1773
+ ```tsx
1774
+ // Rotate in 180 degrees
1775
+ <div style={tw('animate-rotate-in/0/0.5')}>Spinning</div>
1776
+
1777
+ // 3D flip on X axis
1778
+ <div style={tw('animate-flip-in-x/0/0.5')}>Flipping</div>
1779
+ ```
1780
+
1781
+ | Class | Description |
1782
+ |-------|-------------|
1783
+ | `animate-rotate-in/0/1` | Rotate in from -180° |
1784
+ | `animate-rotate-out/0/1` | Rotate out to 180° |
1785
+ | `animate-flip-in-x/0/1` | 3D flip on horizontal axis |
1786
+ | `animate-flip-in-y/0/1` | 3D flip on vertical axis |
1787
+
1788
+ ## Loop Animations
1789
+
1790
+ Format: `animate-{type}/{frameLength}`
1791
+
1792
+ Loop animations repeat every `{frameLength}` frames. At 30fps:
1793
+ - `/30` = 1 second loop
1794
+ - `/15` = 0.5 second loop
1795
+ - `/60` = 2 second loop
1796
+
1797
+ ```tsx
1798
+ // Pulse opacity every 15 frames (0.5s at 30fps)
1799
+ <div style={tw('animate-pulse/15')}>Pulsing</div>
1800
+
1801
+ // Bounce every 20 frames
1802
+ <div style={tw('animate-bounce/20')}>Bouncing</div>
1803
+
1804
+ // Full rotation every 60 frames (2s)
1805
+ <div style={tw('animate-spin/60')}>Spinning</div>
1806
+ ```
1807
+
1808
+ | Class | Description |
1809
+ |-------|-------------|
1810
+ | `animate-pulse/{n}` | Opacity pulse (0.5 → 1 → 0.5) |
1811
+ | `animate-bounce/{n}` | Bounce up and down |
1812
+ | `animate-spin/{n}` | Full 360° rotation |
1813
+ | `animate-ping/{n}` | Scale up + fade out (radar effect) |
1814
+ | `animate-wiggle/{n}` | Side to side wiggle |
1815
+ | `animate-float/{n}` | Gentle up and down floating |
1816
+
1817
+ ## Easing Functions
1818
+
1819
+ Add an easing class **before** the animation class to control the timing curve.
1820
+
1821
+ ```tsx
1822
+ // Ease in (accelerate)
1823
+ <h1 style={tw('ease-in animate-fade-in/0/1')}>Accelerating</h1>
1824
+
1825
+ // Ease out (decelerate) - default
1826
+ <h1 style={tw('ease-out animate-fade-in/0/1')}>Decelerating</h1>
1827
+
1828
+ // Ease in-out (smooth)
1829
+ <h1 style={tw('ease-in-out animate-fade-in/0/1')}>Smooth</h1>
1830
+
1831
+ // Strong cubic easing
1832
+ <h1 style={tw('ease-out-cubic animate-bounce-in/0/0.5')}>Dramatic</h1>
1833
+ ```
1834
+
1835
+ | Class | Description | Best For |
1836
+ |-------|-------------|----------|
1837
+ | `linear` | Constant speed | Mechanical motion |
1838
+ | `ease-in` | Slow start, fast end | Exit animations |
1839
+ | `ease-out` | Fast start, slow end (default) | Enter animations |
1840
+ | `ease-in-out` | Slow start and end | Subtle transitions |
1841
+ | `ease-in-cubic` | Strong slow start | Dramatic exits |
1842
+ | `ease-out-cubic` | Strong fast start | Impactful entrances |
1843
+ | `ease-in-out-cubic` | Strong both ends | Emphasis animations |
1844
+ | `ease-in-quart` | Very strong slow start | Powerful exits |
1845
+ | `ease-out-quart` | Very strong fast start | Punchy entrances |
1846
+ | `ease-in-out-quart` | Very strong both ends | Maximum drama |
1847
+
1848
+ ## Staggered Animations
1849
+
1850
+ Create sequenced animations by offsetting the start/end times:
1851
+
1852
+ ```tsx
1853
+ export default function StaggeredList({ tw, items }) {
1854
+ return (
1855
+ <div style={tw('flex flex-col gap-4')}>
1856
+ {/* First item: 0% to 30% */}
1857
+ <div style={tw('ease-out animate-fade-in-left/0/0.3')}>
1858
+ {items[0]}
1859
+ </div>
1860
+
1861
+ {/* Second item: 10% to 40% */}
1862
+ <div style={tw('ease-out animate-fade-in-left/0.1/0.4')}>
1863
+ {items[1]}
1864
+ </div>
1865
+
1866
+ {/* Third item: 20% to 50% */}
1867
+ <div style={tw('ease-out animate-fade-in-left/0.2/0.5')}>
1868
+ {items[2]}
1869
+ </div>
1870
+ </div>
1871
+ );
1872
+ }
1873
+ ```
1874
+
1875
+ ### Dynamic Staggering
1876
+
1877
+ For dynamic lists, calculate the timing programmatically:
1878
+
1879
+ ```tsx
1880
+ export default function DynamicStagger({ tw, items }) {
1881
+ return (
1882
+ <div style={tw('flex flex-col gap-4')}>
1883
+ {items.map((item, i) => {
1884
+ const start = i * 0.1; // Each item starts 10% later
1885
+ const end = start + 0.3; // Each animation lasts 30%
1886
+
1887
+ return (
1888
+ <div
1889
+ key={i}
1890
+ style={tw(`ease-out animate-fade-in-up/${start}/${end}`)}
1891
+ >
1892
+ {item}
1893
+ </div>
1894
+ );
1895
+ })}
1896
+ </div>
1897
+ );
1898
+ }
1899
+ ```
1900
+
1901
+ ## Combining Animations
1902
+
1903
+ You can combine multiple animation classes. They will be applied together:
1904
+
1905
+ ```tsx
1906
+ // Note: Multiple transforms will be combined
1907
+ <h1 style={tw('animate-fade-in/0/0.5 animate-scale-in/0/0.5')}>
1908
+ Fade + Scale
1909
+ </h1>
1910
+ ```
1911
+
1912
+ For more complex combinations, use manual animation with `progress`:
1913
+
1914
+ ```tsx
1915
+ export default function ComplexAnimation({ tw, progress, title }) {
1916
+ // Custom compound animation
1917
+ const opacity = Math.min(1, progress * 3);
1918
+ const scale = 0.8 + progress * 0.2;
1919
+ const rotation = (1 - progress) * -10;
1920
+
1921
+ return (
1922
+ <div style={tw('flex items-center justify-center w-full h-full')}>
1923
+ <h1 style={{
1924
+ ...tw('text-8xl font-bold'),
1925
+ opacity,
1926
+ transform: `scale(${scale}) rotate(${rotation}deg)`
1927
+ }}>
1928
+ {title}
1929
+ </h1>
1930
+ </div>
1931
+ );
1932
+ }
1933
+ ```
1934
+
1935
+ ## Common Patterns
1936
+
1937
+ ### Intro Sequence
1938
+
1939
+ ```tsx
1940
+ export default function IntroVideo({ tw, title, subtitle, logo }) {
1941
+ return (
1942
+ <div style={tw('flex flex-col items-center justify-center w-full h-full bg-gradient-to-br from-blue-600 to-purple-700')}>
1943
+ {/* Logo appears first */}
1944
+ <img
1945
+ src={logo}
1946
+ style={tw('h-20 mb-8 ease-out animate-scale-in/0/0.3')}
1947
+ />
1948
+
1949
+ {/* Title bounces in */}
1950
+ <h1 style={tw('text-7xl font-bold text-white ease-out animate-bounce-in-up/0.2/0.5')}>
1951
+ {title}
1952
+ </h1>
1953
+
1954
+ {/* Subtitle fades in last */}
1955
+ <p style={tw('text-2xl text-white/80 mt-4 ease-out animate-fade-in-up/0.4/0.7')}>
1956
+ {subtitle}
1957
+ </p>
1958
+ </div>
1959
+ );
1960
+ }
1961
+ ```
1962
+
1963
+ ### Text Reveal
1964
+
1965
+ ```tsx
1966
+ export default function TextReveal({ tw, words }) {
1967
+ return (
1968
+ <div style={tw('flex flex-wrap gap-2 justify-center')}>
1969
+ {words.split(' ').map((word, i) => (
1970
+ <span
1971
+ key={i}
1972
+ style={tw(`text-4xl font-bold ease-out animate-fade-in-up/${i * 0.1}/${i * 0.1 + 0.2}`)}
1973
+ >
1974
+ {word}
1975
+ </span>
1976
+ ))}
1977
+ </div>
1978
+ );
1979
+ }
1980
+ ```
1981
+
1982
+ ### Looping Background Element
1983
+
1984
+ ```tsx
1985
+ export default function AnimatedBackground({ tw, children }) {
1986
+ return (
1987
+ <div style={tw('relative w-full h-full')}>
1988
+ {/* Floating background circles */}
1989
+ <div style={tw('absolute top-10 left-10 w-20 h-20 rounded-full bg-white/10 animate-float/60')} />
1990
+ <div style={tw('absolute bottom-20 right-20 w-32 h-32 rounded-full bg-white/10 animate-pulse/45')} />
1991
+
1992
+ {/* Main content */}
1993
+ <div style={tw('relative z-10')}>
1994
+ {children}
1995
+ </div>
1996
+ </div>
1997
+ );
1998
+ }
1999
+ ```
2000
+
2001
+ ### Exit Animation
2002
+
2003
+ ```tsx
2004
+ export default function ExitAnimation({ tw, title }) {
2005
+ return (
2006
+ <div style={tw('flex items-center justify-center w-full h-full bg-black')}>
2007
+ {/* Visible from 0-70%, then exits */}
2008
+ <h1 style={tw('text-8xl font-bold text-white ease-in animate-fade-out-up/0.7/1')}>
2009
+ {title}
2010
+ </h1>
2011
+ </div>
2012
+ );
2013
+ }
2014
+ ```
2015
+
2016
+ ## Manual Animation with `progress` and `frame`
2017
+
2018
+ For complete control beyond animation classes, use `progress` and `frame` directly.
2019
+
2020
+ ### Available Props
2021
+
2022
+ | Prop | Type | Description |
2023
+ |------|------|-------------|
2024
+ | `progress` | `number` | 0 to 1 through the video (0% to 100%) |
2025
+ | `frame` | `number` | Current frame number (0, 1, 2, ... totalFrames-1) |
2026
+
2027
+ These are **only available in video templates**. Use them when animation classes aren't flexible enough.
2028
+
2029
+ ### Using `progress`
2030
+
2031
+ ```tsx
2032
+ export default function ProgressAnimation({ tw, progress, title }) {
2033
+ // Custom fade based on progress
2034
+ const opacity = progress < 0.3 ? progress / 0.3 : 1;
2035
+
2036
+ // Custom scale based on progress
2037
+ const scale = 0.8 + progress * 0.2; // 0.8 to 1.0
2038
+
2039
+ return (
2040
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
2041
+ <h1 style={{
2042
+ ...tw('text-8xl font-bold text-white'),
2043
+ opacity,
2044
+ transform: `scale(${scale})`
2045
+ }}>
2046
+ {title}
2047
+ </h1>
2048
+ </div>
2049
+ );
2050
+ }
2051
+ ```
2052
+
2053
+ ### Using `frame`
2054
+
2055
+ ```tsx
2056
+ export default function FrameAnimation({ tw, frame, title }) {
2057
+ // Color cycling using frame number
2058
+ const hue = (frame * 5) % 360; // Cycle through colors
2059
+
2060
+ // Pulsing based on frame
2061
+ const fps = 30;
2062
+ const pulse = Math.sin(frame / fps * Math.PI * 2) * 0.2 + 0.8; // 0.6 to 1.0
2063
+
2064
+ return (
2065
+ <div style={tw('flex items-center justify-center w-full h-full bg-black')}>
2066
+ <h1 style={{
2067
+ ...tw('text-8xl font-bold'),
2068
+ color: `hsl(${hue}, 70%, 60%)`,
2069
+ transform: `scale(${pulse})`
2070
+ }}>
2071
+ {title}
2072
+ </h1>
2073
+ </div>
2074
+ );
2075
+ }
2076
+ ```
2077
+
2078
+ ### Custom Easing
2079
+
2080
+ ```tsx
2081
+ export default function CustomEasing({ tw, progress, title }) {
2082
+ // Smoothstep easing
2083
+ const eased = progress * progress * (3 - 2 * progress);
2084
+
2085
+ // Elastic easing
2086
+ const elastic = Math.pow(2, -10 * progress) * Math.sin((progress - 0.075) * (2 * Math.PI) / 0.3) + 1;
2087
+
2088
+ return (
2089
+ <div style={tw('flex items-center justify-center w-full h-full')}>
2090
+ <h1 style={{
2091
+ ...tw('text-8xl font-bold'),
2092
+ opacity: eased,
2093
+ transform: `translateY(${(1 - elastic) * 100}px)`
2094
+ }}>
2095
+ {title}
2096
+ </h1>
2097
+ </div>
2098
+ );
2099
+ }
2100
+ ```
2101
+
2102
+ ### When to Use Manual Animation
2103
+
2104
+ Use `progress`/`frame` instead of animation classes when you need:
2105
+ - **Custom easing functions** (elastic, spring, bounce with specific curves)
2106
+ - **Color cycling or gradients** based on time
2107
+ - **Mathematical animations** (sine waves, spirals, etc.)
2108
+ - **Complex multi-property animations** that need precise coordination
2109
+ - **Conditional logic** based on specific frame numbers
2110
+
2111
+ For everything else, prefer animation classes - they're simpler and more maintainable.
2112
+
2113
+ ## Performance Tips
2114
+
2115
+ 1. **Use Tailwind classes** when possible - they're optimized for the renderer
2116
+ 2. **Avoid too many nested animations** - each adds computation per frame
2117
+ 3. **Use loop animations sparingly** - they're computed every frame
2118
+ 4. **Prefer opacity and transform** - they're the most performant properties
2119
+
2120
+ ## Next Steps
2121
+
2122
+ - [Video Templates](/video) - Creating video templates
2123
+ - [SDK](/sdk) - Programmatic rendering with animations
2124
+ - [Helpers](/helpers) - QR codes, images, and more
2125
+
2126
+
2127
+
2128
+
1578
2129
  ================================================================================
1579
2130
  FILE: helpers.mdx
1580
2131
  ================================================================================
@@ -1585,7 +2136,7 @@ Additional helpers for creating powerful, composable templates.
1585
2136
 
1586
2137
  ## Overview
1587
2138
 
1588
- Beyond the basics, dsgn provides:
2139
+ Beyond the basics, loopwind provides:
1589
2140
  - `template()` - Compose templates together
1590
2141
  - `qr()` - Generate QR codes on the fly
1591
2142
  - `config` - Access user configuration
@@ -1710,11 +2261,11 @@ You can customize QR code appearance:
1710
2261
 
1711
2262
  ## User Configuration
1712
2263
 
1713
- Access user settings from `dsgn.json` using the `config` prop:
2264
+ Access user settings from `loopwind.json` using the `config` prop:
1714
2265
 
1715
2266
  ```tsx
1716
2267
  export default function BrandedTemplate({ tw, config, title }) {
1717
- // Access custom colors from dsgn.json
2268
+ // Access custom colors from loopwind.json
1718
2269
  const primaryColor = config?.colors?.brand || '#6366f1';
1719
2270
 
1720
2271
  return (
@@ -1730,7 +2281,7 @@ export default function BrandedTemplate({ tw, config, title }) {
1730
2281
  }
1731
2282
  ```
1732
2283
 
1733
- **User's dsgn.json:**
2284
+ **User's loopwind.json:**
1734
2285
  ```json
1735
2286
  {
1736
2287
  "colors": {
@@ -1754,7 +2305,7 @@ export default function MyTemplate({
1754
2305
  tw, // Tailwind class converter
1755
2306
  qr, // QR code generator (this page)
1756
2307
  template, // Template composer (this page)
1757
- config, // User config from dsgn.json (this page)
2308
+ config, // User config from loopwind.json (this page)
1758
2309
 
1759
2310
  // Media helpers (see dedicated pages)
1760
2311
  image, // Image embedder → see /images
@@ -1860,7 +2411,7 @@ export default function CustomGradient({ title, tw }) {
1860
2411
 
1861
2412
  ## shadcn/ui Design System
1862
2413
 
1863
- dsgn uses **shadcn/ui's design system** by default, providing semantic color tokens for beautiful, consistent designs.
2414
+ loopwind uses **shadcn/ui's design system** by default, providing semantic color tokens for beautiful, consistent designs.
1864
2415
 
1865
2416
  ### Default Color Palette
1866
2417
 
@@ -2099,7 +2650,7 @@ export default function GradientCard({ title, tw }) {
2099
2650
 
2100
2651
  ## Custom Theme Colors
2101
2652
 
2102
- Override default colors in your `dsgn.json`:
2653
+ Override default colors in your `loopwind.json`:
2103
2654
 
2104
2655
  ```json
2105
2656
  {
@@ -2123,13 +2674,13 @@ tw('bg-primary') // Uses your custom primary color
2123
2674
 
2124
2675
  ## Auto-Detection from tailwind.config.js
2125
2676
 
2126
- dsgn automatically detects and loads your project's Tailwind configuration:
2677
+ loopwind automatically detects and loads your project's Tailwind configuration:
2127
2678
 
2128
2679
  ```
2129
2680
  your-project/
2130
2681
  ├── tailwind.config.js ← Automatically detected
2131
- ├── dsgn.json
2132
- └── _dsgn/templates/
2682
+ ├── loopwind.json
2683
+ └── _loopwind/templates/
2133
2684
  ```
2134
2685
 
2135
2686
  This includes:
@@ -2218,15 +2769,15 @@ export default function ModernCard({
2218
2769
  FILE: fonts.mdx
2219
2770
  ================================================================================
2220
2771
 
2221
- # Font Handling in dsgn
2772
+ # Font Handling in loopwind
2222
2773
 
2223
- The recommended way to use fonts is through `dsgn.json` - configure fonts once, use everywhere.
2774
+ The recommended way to use fonts is through `loopwind.json` - configure fonts once, use everywhere.
2224
2775
 
2225
- ## Using Fonts from dsgn.json (Recommended)
2776
+ ## Using Fonts from loopwind.json (Recommended)
2226
2777
 
2227
- Configure fonts in your `dsgn.json` and use Tailwind classes in templates.
2778
+ Configure fonts in your `loopwind.json` and use Tailwind classes in templates.
2228
2779
 
2229
- ### Simple Setup (CSS Only)
2780
+ ### Simple Setup
2230
2781
 
2231
2782
  Define font families without loading custom fonts (uses system fonts):
2232
2783
 
@@ -2245,12 +2796,12 @@ Define font families without loading custom fonts (uses system fonts):
2245
2796
  export default function({ title, tw }) {
2246
2797
  return (
2247
2798
  <div style={tw('w-full h-full')}>
2248
- {/* Uses fonts.sans from dsgn.json */}
2799
+ {/* Uses fonts.sans from loopwind.json */}
2249
2800
  <h1 style={tw('font-sans text-6xl font-bold')}>
2250
2801
  {title}
2251
2802
  </h1>
2252
2803
 
2253
- {/* Uses fonts.mono from dsgn.json */}
2804
+ {/* Uses fonts.mono from loopwind.json */}
2254
2805
  <code style={tw('font-mono text-sm')}>
2255
2806
  {code}
2256
2807
  </code>
@@ -2288,27 +2839,27 @@ Load custom font files for brand-specific typography:
2288
2839
  **Project structure:**
2289
2840
  ```
2290
2841
  your-project/
2291
- ├── dsgn.json
2842
+ ├── loopwind.json
2292
2843
  ├── fonts/
2293
2844
  │ ├── Inter-Regular.woff
2294
2845
  │ ├── Inter-Bold.woff
2295
2846
  │ └── JetBrainsMono-Regular.woff
2296
- └── _dsgn/
2847
+ └── _loopwind/
2297
2848
  └── templates/
2298
2849
  ```
2299
2850
 
2300
2851
  **Template usage (same as before):**
2301
2852
  ```tsx
2302
2853
  <h1 style={tw('font-sans font-bold')}>
2303
- {/* Uses Inter Bold from dsgn.json */}
2854
+ {/* Uses Inter Bold from loopwind.json */}
2304
2855
  {title}
2305
2856
  </h1>
2306
2857
  ```
2307
2858
 
2308
2859
  **Available classes:**
2309
- - `font-sans` - Uses `fonts.sans` from dsgn.json
2310
- - `font-serif` - Uses `fonts.serif` from dsgn.json
2311
- - `font-mono` - Uses `fonts.mono` from dsgn.json
2860
+ - `font-sans` - Uses `fonts.sans` from loopwind.json
2861
+ - `font-serif` - Uses `fonts.serif` from loopwind.json
2862
+ - `font-mono` - Uses `fonts.mono` from loopwind.json
2312
2863
 
2313
2864
  **Supported formats:**
2314
2865
  - ✅ **WOFF** (`.woff`) - Recommended
@@ -2322,59 +2873,60 @@ For templates that need unique fonts not shared across the project:
2322
2873
 
2323
2874
  **Template structure:**
2324
2875
  ```
2325
- _dsgn/templates/my-template/
2326
- ├── my-template.tsx
2327
- ├── meta.json
2876
+ _loopwind/templates/my-template/
2877
+ ├── template.tsx
2328
2878
  └── fonts/
2329
2879
  └── SpecialFont.woff
2330
2880
  ```
2331
2881
 
2332
- **meta.json:**
2333
- ```json
2334
- {
2335
- "name": "my-template",
2336
- "type": "image",
2337
- "size": { "width": 1200, "height": 630 },
2338
- "fonts": [
2882
+ **template.tsx:**
2883
+ ```tsx
2884
+ export const meta = {
2885
+ name: "my-template",
2886
+ type: "image",
2887
+ size: { width: 1200, height: 630 },
2888
+ props: { title: "string" },
2889
+ fonts: [
2339
2890
  {
2340
- "name": "Special Font",
2341
- "path": "fonts/SpecialFont.woff",
2342
- "weight": 400,
2343
- "style": "normal"
2891
+ name: "Special Font",
2892
+ path: "fonts/SpecialFont.woff",
2893
+ weight: 400,
2894
+ style: "normal"
2344
2895
  }
2345
2896
  ]
2346
- }
2347
- ```
2897
+ };
2348
2898
 
2349
- **Template usage:**
2350
- ```tsx
2351
- <h1 style={{ fontFamily: 'Special Font', fontWeight: 400 }}>
2352
- {title}
2353
- </h1>
2899
+ export default function Template({ title, tw }) {
2900
+ return (
2901
+ <h1 style={{ fontFamily: 'Special Font', fontWeight: 400 }}>
2902
+ {title}
2903
+ </h1>
2904
+ );
2905
+ }
2354
2906
  ```
2355
2907
 
2356
2908
  ## Font Loading Priority
2357
2909
 
2358
- dsgn loads fonts in this order:
2910
+ loopwind loads fonts in this order:
2359
2911
 
2360
- 1. **dsgn.json fonts** (if configured with `files`)
2361
- 2. **Template meta.json fonts** (if specified)
2912
+ 1. **loopwind.json fonts** (if configured with `files`)
2913
+ 2. **Template meta fonts** (if specified in `export const meta`)
2362
2914
  3. **Default Noto Sans** (from CDN)
2363
2915
 
2364
- This means dsgn.json fonts override template fonts, ensuring consistency.
2916
+ This means loopwind.json fonts override template fonts, ensuring consistency.
2365
2917
 
2366
2918
  ## Default Fonts
2367
2919
 
2368
- If no fonts are configured, dsgn automatically fetches **Noto Sans** from jsDelivr CDN.
2920
+ If no fonts are configured, loopwind automatically fetches **Noto Sans** from jsDelivr CDN.
2369
2921
 
2370
2922
  ## Best Practices
2371
2923
 
2372
- 1. ✅ **Use dsgn.json for project-wide fonts** - Configure once, use everywhere
2924
+ 1. ✅ **Use loopwind.json for project-wide fonts** - Configure once, use everywhere
2373
2925
  2. ✅ **Use font classes** - `tw('font-sans')` instead of `fontFamily: 'Inter'`
2374
2926
  3. ✅ **Include fallbacks** - Always add system fonts: `["Inter", "system-ui", "sans-serif"]`
2375
2927
  4. ✅ **Match names** - First font in `family` array is used as the loaded font name
2376
- 5. ✅ **Relative paths** - Font paths are relative to `dsgn.json` location
2377
- 6. ⚠️ **Template fonts for special cases** - Only use meta.json fonts for template-specific typography
2928
+ 5. ✅ **Relative paths** - Font paths are relative to `loopwind.json` location
2929
+ 6. ⚠️ **Template fonts for special cases** - Only use template meta fonts for template-specific typography
2378
2930
 
2379
2931
  ## Examples
2380
2932
 
@@ -2446,3 +2998,83 @@ Loads different fonts for each style class.
2446
2998
  - [Video Rendering](/video)
2447
2999
 
2448
3000
 
3001
+
3002
+
3003
+ ================================================================================
3004
+ FILE: agents.mdx
3005
+ ================================================================================
3006
+
3007
+ # AI Agents
3008
+
3009
+ loopwind is designed to work with AI coding assistants. Simply add the `_loopwind` folder to context.
3010
+
3011
+ ## Using with AI Code Agents
3012
+
3013
+ In Cursor or Claude Code (Cline), type `@_loopwind` to add the folder to context, then ask:
3014
+
3015
+ ```
3016
+ Generate an Open Graph image for my blog post about React hooks
3017
+ ```
3018
+
3019
+ The AI will read the templates and generate the appropriate command.
3020
+
3021
+ ## The AGENTS.md File
3022
+
3023
+ When you run `loopwind init`, a `_loopwind/AGENTS.md` file is created with:
3024
+ - Essential commands
3025
+ - Template helpers reference
3026
+ - Common workflows
3027
+
3028
+ This gives AI agents everything they need to use loopwind effectively.
3029
+
3030
+ ## Example Workflows
3031
+
3032
+ ### Simple Image Generation
3033
+
3034
+ **Prompt:**
3035
+ ```
3036
+ Create a social media card using the og-image template:
3037
+ - Title: "10 React Tips"
3038
+ - Description: "Learn advanced patterns"
3039
+ ```
3040
+
3041
+ **AI generates:**
3042
+ ```bash
3043
+ loopwind render og-image '{"title":"10 React Tips","description":"Learn advanced patterns"}'
3044
+ ```
3045
+
3046
+ **Output:** `_loopwind/outputs/og-image.png`
3047
+
3048
+ ### Changelog Image
3049
+
3050
+ **Prompt:**
3051
+ ```
3052
+ Create a changelog image for 3 recent changes:
3053
+ - Added video rendering support
3054
+ - Improved template validation
3055
+ - Fixed font loading issues
3056
+ ```
3057
+
3058
+ **AI generates:**
3059
+ ```bash
3060
+ loopwind render changelog-card '{
3061
+ "title":"Version 1.2.0",
3062
+ "changes":[
3063
+ "Added video rendering support",
3064
+ "Improved template validation",
3065
+ "Fixed font loading issues"
3066
+ ]
3067
+ }'
3068
+ ```
3069
+
3070
+ **Output:** `_loopwind/outputs/changelog-card.png`
3071
+
3072
+ ## Next Steps
3073
+
3074
+ - [Learn about Templates](/templates)
3075
+ - [Image Rendering](/images)
3076
+ - [Video Rendering](/video)
3077
+ - [Built-in Helpers](/helpers)
3078
+
3079
+
3080
+