loopwind 0.9.2 → 0.10.0
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.
- package/FONTS.md +13 -13
- package/HELPERS_DEMO.md +2 -2
- package/PROJECT_STRUCTURE.md +38 -38
- package/PUBLISHING.md +13 -13
- package/README.md +40 -48
- package/REGISTRY_SETUP.md +18 -18
- package/SHADCN_INTEGRATION.md +7 -7
- package/TAILWIND.md +4 -4
- package/TEMPLATE_SOURCES.md +30 -30
- package/dist/commands/render.d.ts +1 -1
- package/dist/commands/render.d.ts.map +1 -1
- package/dist/commands/render.js +53 -26
- package/dist/commands/render.js.map +1 -1
- package/dist/default-templates/AGENTS.md +29 -29
- package/dist/default-templates/image-template/template.tsx +15 -0
- package/dist/default-templates/video-template/template.tsx +19 -0
- package/dist/default-templates/website-template/template.tsx +18 -0
- package/dist/lib/renderer.js +15 -15
- package/dist/lib/renderer.js.map +1 -1
- package/dist/lib/tailwind-detector.js +1 -1
- package/dist/lib/tailwind-detector.js.map +1 -1
- package/dist/lib/tailwind.d.ts +1 -1
- package/dist/lib/tailwind.d.ts.map +1 -1
- package/dist/lib/tailwind.js +19 -19
- package/dist/lib/tailwind.js.map +1 -1
- package/dist/lib/template-validator.js +1 -1
- package/dist/lib/template-validator.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +8 -7
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/video-renderer.d.ts +6 -0
- package/dist/lib/video-renderer.d.ts.map +1 -1
- package/dist/lib/video-renderer.js +69 -0
- package/dist/lib/video-renderer.js.map +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +8 -8
- package/dist/sdk/index.js.map +1 -1
- package/examples/nextjs-api/README.md +6 -6
- package/examples/nextjs-api/pages/api/intro-video.ts +1 -1
- package/examples/nextjs-api/pages/api/og-image.ts +2 -2
- package/package.json +2 -1
- package/test-templates/TESTS.md +1 -1
- package/test-templates/test-sdk.mjs +2 -2
- package/website/README.md +2 -2
- package/website/package-lock.json +186 -2480
- package/_dsgn/templates/banner-hero/banner-hero.tsx +0 -57
- package/_dsgn/templates/banner-hero/meta.json +0 -14
- package/_dsgn/templates/composite-card/meta.json +0 -16
- package/_dsgn/templates/composite-card/template.tsx +0 -44
- package/_dsgn/templates/image/meta.json +0 -13
- package/_dsgn/templates/image/template.tsx +0 -28
- package/_dsgn/templates/kitchen-sink/meta.json +0 -13
- package/_dsgn/templates/kitchen-sink/template.tsx +0 -72
- package/_dsgn/templates/qr-card/meta.json +0 -14
- package/_dsgn/templates/qr-card/template.tsx +0 -39
- package/_dsgn/templates/test-parent/child/meta.json +0 -11
- package/_dsgn/templates/test-parent/child/template.tsx +0 -27
- package/_dsgn/templates/test-parent/meta.json +0 -12
- package/_dsgn/templates/test-parent/template.tsx +0 -30
- package/_dsgn/templates/test-sibling/meta.json +0 -11
- package/_dsgn/templates/test-sibling/template.tsx +0 -20
- package/_dsgn/templates/video/.tmp/template-1763421345296.mjs +0 -43
- package/_dsgn/templates/video/.tmp/template-1763421362228.mjs +0 -43
- package/_dsgn/templates/video/.tmp/template-1763421377706.mjs +0 -43
- package/_dsgn/templates/video/meta.json +0 -17
- package/_dsgn/templates/video/template.tsx +0 -48
- package/dist/default-templates/image/meta.json +0 -13
- package/dist/default-templates/image-template/meta.json +0 -13
- package/dist/default-templates/kitchen-sink/meta.json +0 -13
- package/dist/default-templates/page/meta.json +0 -17
- package/dist/default-templates/video/meta.json +0 -17
- package/dist/default-templates/video-template/meta.json +0 -17
- package/dist/default-templates/website/meta.json +0 -16
- package/dist/default-templates/website-template/meta.json +0 -16
- package/test-templates/_dsgn/templates/absolute-spin/meta.json +0 -7
- package/test-templates/_dsgn/templates/absolute-spin/template.tsx +0 -16
- package/test-templates/_dsgn/templates/animated-intro/.tmp/template-1763468771640.mjs +0 -7
- package/test-templates/_dsgn/templates/animated-intro/meta.json +0 -10
- package/test-templates/_dsgn/templates/animated-intro/template.tsx +0 -23
- package/test-templates/_dsgn/templates/centered-spin/.tmp/template-1763468525386.mjs +0 -7
- package/test-templates/_dsgn/templates/centered-spin/meta.json +0 -7
- package/test-templates/_dsgn/templates/centered-spin/template.tsx +0 -11
- package/test-templates/_dsgn/templates/composite/.tmp/template-1763468815645.mjs +0 -7
- package/test-templates/_dsgn/templates/composite/meta.json +0 -9
- package/test-templates/_dsgn/templates/composite/template.tsx +0 -23
- package/test-templates/_dsgn/templates/easing-test/.tmp/template-1763468824501.mjs +0 -7
- package/test-templates/_dsgn/templates/easing-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/easing-test/template.tsx +0 -47
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466364336.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466584319.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466667797.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466746504.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466930225.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467004552.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467060334.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467124493.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467174690.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467359134.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467451928.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467758275.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467985201.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468020563.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468090428.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468211036.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468394057.mjs +0 -10
- package/test-templates/_dsgn/templates/minimal-spin/meta.json +0 -7
- package/test-templates/_dsgn/templates/minimal-spin/template.tsx +0 -13
- package/test-templates/_dsgn/templates/no-origin-spin/meta.json +0 -7
- package/test-templates/_dsgn/templates/no-origin-spin/template.tsx +0 -10
- package/test-templates/_dsgn/templates/opacity-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/opacity-test/template.tsx +0 -9
- package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468758954.mjs +0 -17
- package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468815672.mjs +0 -17
- package/test-templates/_dsgn/templates/qr-code/meta.json +0 -9
- package/test-templates/_dsgn/templates/qr-code/template.tsx +0 -20
- package/test-templates/_dsgn/templates/rotation-abs-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/rotation-abs-test/template.tsx +0 -15
- package/test-templates/_dsgn/templates/rotation-corner/meta.json +0 -7
- package/test-templates/_dsgn/templates/rotation-corner/template.tsx +0 -12
- package/test-templates/_dsgn/templates/rotation-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/rotation-test/template.tsx +0 -12
- package/test-templates/_dsgn/templates/shake-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/shake-test/template.tsx +0 -12
- package/test-templates/_dsgn/templates/static-image/.tmp/template-1763468746271.mjs +0 -7
- package/test-templates/_dsgn/templates/static-image/meta.json +0 -9
- package/test-templates/_dsgn/templates/static-image/template.tsx +0 -19
- package/test-templates/_dsgn/templates/translate-test/meta.json +0 -7
- package/test-templates/_dsgn/templates/translate-test/template.tsx +0 -9
- package/test-templates/_dsgn/templates/video-loops/.tmp/template-1763468793192.mjs +0 -15
- package/test-templates/_dsgn/templates/video-loops/meta.json +0 -9
- package/test-templates/_dsgn/templates/video-loops/template.tsx +0 -39
- package/test-templates/_dsgn/templates/wrapped-spin/meta.json +0 -7
- package/test-templates/_dsgn/templates/wrapped-spin/template.tsx +0 -17
- package/test-templates/compare-svgs.mjs +0 -30
- package/test-templates/convert-frames.mjs +0 -15
- package/test-templates/debug-rotation.mjs +0 -25
package/FONTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Font Handling in
|
|
1
|
+
# Font Handling in loopwind
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
loopwind has a two-part font system:
|
|
4
4
|
1. **Font Data** (template-specific) - Actual font files loaded by Satori
|
|
5
5
|
2. **Font Classes** (project-wide) - CSS font-family applied via `tw()`
|
|
6
6
|
|
|
@@ -62,11 +62,11 @@ my-template/
|
|
|
62
62
|
- ✅ **TTF** (`.ttf`) - Also supported
|
|
63
63
|
- ✅ **OTF** (`.otf`) - Also supported
|
|
64
64
|
|
|
65
|
-
## Font Classes (from
|
|
65
|
+
## Font Classes (from loopwind.json)
|
|
66
66
|
|
|
67
|
-
Use Tailwind font-family classes in templates. These reference the font stacks in `
|
|
67
|
+
Use Tailwind font-family classes in templates. These reference the font stacks in `loopwind.json`:
|
|
68
68
|
|
|
69
|
-
**
|
|
69
|
+
**loopwind.json:**
|
|
70
70
|
```json
|
|
71
71
|
{
|
|
72
72
|
"fonts": {
|
|
@@ -82,12 +82,12 @@ Use Tailwind font-family classes in templates. These reference the font stacks i
|
|
|
82
82
|
export default function({ title, tw }) {
|
|
83
83
|
return (
|
|
84
84
|
<div style={tw('w-full h-full')}>
|
|
85
|
-
{/* Uses fonts.sans from
|
|
85
|
+
{/* Uses fonts.sans from loopwind.json */}
|
|
86
86
|
<h1 style={tw('font-sans text-6xl font-bold')}>
|
|
87
87
|
{title}
|
|
88
88
|
</h1>
|
|
89
89
|
|
|
90
|
-
{/* Uses fonts.mono from
|
|
90
|
+
{/* Uses fonts.mono from loopwind.json */}
|
|
91
91
|
<code style={tw('font-mono text-sm')}>
|
|
92
92
|
Hello World
|
|
93
93
|
</code>
|
|
@@ -97,14 +97,14 @@ export default function({ title, tw }) {
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
**Available classes:**
|
|
100
|
-
- `font-sans` - Uses `fonts.sans` from
|
|
101
|
-
- `font-serif` - Uses `fonts.serif` from
|
|
102
|
-
- `font-mono` - Uses `fonts.mono` from
|
|
100
|
+
- `font-sans` - Uses `fonts.sans` from loopwind.json (default: system-ui, -apple-system, sans-serif)
|
|
101
|
+
- `font-serif` - Uses `fonts.serif` from loopwind.json (default: Georgia, serif)
|
|
102
|
+
- `font-mono` - Uses `fonts.mono` from loopwind.json (default: monospace)
|
|
103
103
|
|
|
104
104
|
## How It Works Together
|
|
105
105
|
|
|
106
106
|
1. **Font data** is loaded from template's `meta.json` (or default Noto Sans)
|
|
107
|
-
2. **Font classes** (`font-sans`) apply CSS `fontFamily` from `
|
|
107
|
+
2. **Font classes** (`font-sans`) apply CSS `fontFamily` from `loopwind.json`
|
|
108
108
|
3. The font name in CSS must match a loaded font for Satori to use it
|
|
109
109
|
|
|
110
110
|
**Example:**
|
|
@@ -120,7 +120,7 @@ export default function({ title, tw }) {
|
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```json
|
|
123
|
-
//
|
|
123
|
+
// loopwind.json - Defines font stacks for CSS
|
|
124
124
|
{
|
|
125
125
|
"fonts": {
|
|
126
126
|
"sans": ["Inter", "system-ui", "sans-serif"]
|
|
@@ -152,5 +152,5 @@ export default function({ title, tw }) {
|
|
|
152
152
|
1. **For most templates:** Use default Noto Sans, no font setup needed
|
|
153
153
|
2. **For branded templates:** Bundle custom fonts in template's `fonts/` folder
|
|
154
154
|
3. **Use font classes:** `tw('font-sans')` instead of raw `fontFamily: 'Inter'`
|
|
155
|
-
4. **Match names:** Ensure `
|
|
155
|
+
4. **Match names:** Ensure `loopwind.json` font names match template's loaded fonts
|
|
156
156
|
5. **Include fallbacks:** Always include system fallbacks in font stacks
|
package/HELPERS_DEMO.md
CHANGED
|
@@ -70,7 +70,7 @@ Then use the `video()` helper with the prop value.
|
|
|
70
70
|
## Example: Video with Text Overlay
|
|
71
71
|
|
|
72
72
|
```tsx
|
|
73
|
-
// Template:
|
|
73
|
+
// Template: _loopwind/templates/video-overlay/index.tsx
|
|
74
74
|
export default function VideoOverlay({ tw, video, frame, progress, title }) {
|
|
75
75
|
// Animate title opacity
|
|
76
76
|
const opacity = progress < 0.2 ? progress / 0.2 : 1;
|
|
@@ -123,7 +123,7 @@ export default function VideoOverlay({ tw, video, frame, progress, title }) {
|
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
125
|
# Render
|
|
126
|
-
|
|
126
|
+
loopwind render video-overlay props.json --out output.mp4
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
This will:
|
package/PROJECT_STRUCTURE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**loopwind** is a global CLI tool that operates on project-local templates and outputs.
|
|
6
6
|
|
|
7
7
|
Think of it like:
|
|
8
8
|
- **Global CLI**: Like `npm` or `git` - installed once, used everywhere
|
|
@@ -13,11 +13,11 @@ Think of it like:
|
|
|
13
13
|
|
|
14
14
|
### Your Project
|
|
15
15
|
|
|
16
|
-
When you use `
|
|
16
|
+
When you use `loopwind` in your project, this is the structure:
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
my-project/
|
|
20
|
-
├──
|
|
20
|
+
├── loopwind/
|
|
21
21
|
│ ├── templates/ # Installed templates (like node_modules)
|
|
22
22
|
│ │ ├── banner-hero/
|
|
23
23
|
│ │ │ ├── banner-hero.tsx
|
|
@@ -28,14 +28,14 @@ my-project/
|
|
|
28
28
|
│ └── outputs/ # Generated images/videos
|
|
29
29
|
│ ├── banner-hero-1234567890.png
|
|
30
30
|
│ └── product-card-1234567891.png
|
|
31
|
-
├──
|
|
31
|
+
├── loopwind.json # Your project's design tokens (optional)
|
|
32
32
|
└── package.json
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
### The CLI Package (this repo)
|
|
36
36
|
|
|
37
37
|
```
|
|
38
|
-
|
|
38
|
+
loopwind/
|
|
39
39
|
├── src/
|
|
40
40
|
│ ├── cli.ts # Main CLI entry point
|
|
41
41
|
│ ├── commands/ # Command implementations
|
|
@@ -64,34 +64,34 @@ dsgn/
|
|
|
64
64
|
### 1. Global Installation
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
npm install -g
|
|
67
|
+
npm install -g loopwind
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
This installs the CLI globally, making the `
|
|
70
|
+
This installs the CLI globally, making the `loopwind` command available anywhere.
|
|
71
71
|
|
|
72
72
|
### 2. Project Usage
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
cd ~/my-project
|
|
76
|
-
|
|
76
|
+
loopwind add banner-hero
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
This:
|
|
80
80
|
1. Fetches template from registry: `https://design.unpeel.dev/r/banner-hero`
|
|
81
|
-
2. Installs to: `~/my-project/
|
|
81
|
+
2. Installs to: `~/my-project/loopwind/templates/banner-hero/`
|
|
82
82
|
3. Creates structure if it doesn't exist
|
|
83
83
|
|
|
84
84
|
### 3. Rendering
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
-
|
|
87
|
+
loopwind render banner-hero --props '{"title":"Hello"}'
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
This:
|
|
91
|
-
1. Loads template from `
|
|
92
|
-
2. Loads config from `
|
|
91
|
+
1. Loads template from `loopwind/templates/banner-hero/`
|
|
92
|
+
2. Loads config from `loopwind.json` (if exists)
|
|
93
93
|
3. Renders with Satori
|
|
94
|
-
4. Saves to `
|
|
94
|
+
4. Saves to `loopwind/outputs/banner-hero-{timestamp}.png`
|
|
95
95
|
|
|
96
96
|
## Why This Architecture?
|
|
97
97
|
|
|
@@ -155,9 +155,9 @@ Returns:
|
|
|
155
155
|
}
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
When you run `
|
|
158
|
+
When you run `loopwind add banner-hero`, it:
|
|
159
159
|
1. Fetches this JSON
|
|
160
|
-
2. Writes files to `
|
|
160
|
+
2. Writes files to `loopwind/templates/banner-hero/`
|
|
161
161
|
3. Templates are now local and ready to use
|
|
162
162
|
|
|
163
163
|
## Git Workflow
|
|
@@ -165,20 +165,20 @@ When you run `dsgn add banner-hero`, it:
|
|
|
165
165
|
### What to commit?
|
|
166
166
|
|
|
167
167
|
**DO commit:**
|
|
168
|
-
- `
|
|
169
|
-
- `
|
|
168
|
+
- `loopwind/templates/` - Your templates (like `node_modules` in some projects)
|
|
169
|
+
- `loopwind.json` - Your design configuration
|
|
170
170
|
|
|
171
171
|
**DON'T commit:**
|
|
172
|
-
- `
|
|
172
|
+
- `loopwind/outputs/` - Generated files (usually)
|
|
173
173
|
|
|
174
174
|
Example `.gitignore`:
|
|
175
175
|
|
|
176
176
|
```gitignore
|
|
177
177
|
# Ignore generated outputs
|
|
178
|
-
|
|
178
|
+
loopwind/outputs/
|
|
179
179
|
|
|
180
180
|
# Keep templates (optional - depends on your workflow)
|
|
181
|
-
#
|
|
181
|
+
# loopwind/templates/
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
Some teams prefer to commit templates (reproducibility), others prefer to install them (like npm packages).
|
|
@@ -215,46 +215,46 @@ mkdir my-project
|
|
|
215
215
|
cd my-project
|
|
216
216
|
|
|
217
217
|
# Initialize config
|
|
218
|
-
|
|
218
|
+
loopwind init
|
|
219
219
|
|
|
220
220
|
# Install templates
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
loopwind add banner-hero
|
|
222
|
+
loopwind add product-card
|
|
223
223
|
|
|
224
224
|
# Render images
|
|
225
|
-
|
|
225
|
+
loopwind render banner-hero --props props.json
|
|
226
226
|
```
|
|
227
227
|
|
|
228
228
|
### Sharing with Team
|
|
229
229
|
|
|
230
230
|
```bash
|
|
231
231
|
# Developer 1
|
|
232
|
-
git add
|
|
232
|
+
git add loopwind/templates/
|
|
233
233
|
git commit -m "Add banner template"
|
|
234
234
|
git push
|
|
235
235
|
|
|
236
236
|
# Developer 2
|
|
237
237
|
git pull
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
loopwind list # See all templates
|
|
239
|
+
loopwind render banner-hero --props '{"title":"Team Banner"}'
|
|
240
240
|
```
|
|
241
241
|
|
|
242
242
|
### CI/CD Pipeline
|
|
243
243
|
|
|
244
244
|
```yaml
|
|
245
245
|
# .github/workflows/generate-images.yml
|
|
246
|
-
- name: Install
|
|
247
|
-
run: npm install -g
|
|
246
|
+
- name: Install loopwind
|
|
247
|
+
run: npm install -g loopwind
|
|
248
248
|
|
|
249
249
|
- name: Generate images
|
|
250
250
|
run: |
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
loopwind render banner-hero --props props/hero.json
|
|
252
|
+
loopwind render product-card --props props/product.json
|
|
253
253
|
|
|
254
254
|
- name: Upload artifacts
|
|
255
255
|
uses: actions/upload-artifact@v3
|
|
256
256
|
with:
|
|
257
|
-
path:
|
|
257
|
+
path: loopwind/outputs/
|
|
258
258
|
```
|
|
259
259
|
|
|
260
260
|
## Future Enhancements
|
|
@@ -262,25 +262,25 @@ dsgn render banner-hero --props '{"title":"Team Banner"}'
|
|
|
262
262
|
### Template Versions
|
|
263
263
|
|
|
264
264
|
```bash
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
loopwind add banner-hero@2.0.0
|
|
266
|
+
loopwind update banner-hero
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
### Template Marketplace
|
|
270
270
|
|
|
271
271
|
```bash
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
loopwind search "hero"
|
|
273
|
+
loopwind add @company/custom-banner
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
### Global vs Local
|
|
277
277
|
|
|
278
278
|
```bash
|
|
279
279
|
# Install globally (like npm -g)
|
|
280
|
-
|
|
280
|
+
loopwind add banner-hero --global
|
|
281
281
|
|
|
282
282
|
# Install locally (default, like npm install)
|
|
283
|
-
|
|
283
|
+
loopwind add banner-hero
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
This is the **Shadcn for design and marketing** - same philosophy of owning your code, but for design assets!
|
package/PUBLISHING.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Publishing Guide
|
|
2
2
|
|
|
3
|
-
This guide explains how to publish `
|
|
3
|
+
This guide explains how to publish `loopwind` to npm.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
1. npm account (create at https://www.npmjs.com/signup)
|
|
8
8
|
2. npm CLI logged in: `npm login`
|
|
9
|
-
3. Package name availability check: `npm search
|
|
9
|
+
3. Package name availability check: `npm search loopwind`
|
|
10
10
|
|
|
11
11
|
## Pre-publish Checklist
|
|
12
12
|
|
|
@@ -37,8 +37,8 @@ You can test the package locally before publishing:
|
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
npm pack
|
|
40
|
-
npm install -g ./
|
|
41
|
-
|
|
40
|
+
npm install -g ./loopwind-0.1.0.tgz
|
|
41
|
+
loopwind --help
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
### 3. Publish to npm
|
|
@@ -58,13 +58,13 @@ npm publish --access public
|
|
|
58
58
|
Check that it's published:
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
npm view
|
|
61
|
+
npm view loopwind
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Test installation:
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
npx
|
|
67
|
+
npx loopwind@latest --help
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
## Post-publish
|
|
@@ -92,13 +92,13 @@ npm version major # 0.1.0 -> 1.0.0
|
|
|
92
92
|
|
|
93
93
|
## Package Name Alternatives
|
|
94
94
|
|
|
95
|
-
If `
|
|
95
|
+
If `loopwind` is taken, consider:
|
|
96
96
|
|
|
97
|
-
- `@yourusername/
|
|
97
|
+
- `@yourusername/loopwind` (scoped package)
|
|
98
98
|
- `design-cli`
|
|
99
99
|
- `designkit-cli`
|
|
100
|
-
- `
|
|
101
|
-
- `template-
|
|
100
|
+
- `loopwind-cli`
|
|
101
|
+
- `template-loopwind`
|
|
102
102
|
|
|
103
103
|
Check availability:
|
|
104
104
|
|
|
@@ -111,13 +111,13 @@ npm search <package-name>
|
|
|
111
111
|
If you need to unpublish (within 72 hours):
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
npm unpublish
|
|
114
|
+
npm unpublish loopwind@0.1.0
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
Note: Unpublishing is discouraged. Use `npm deprecate` instead for older versions:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
npm deprecate
|
|
120
|
+
npm deprecate loopwind@0.1.0 "Please upgrade to 0.2.0"
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
## CI/CD Publishing (GitHub Actions)
|
|
@@ -161,7 +161,7 @@ npm publish --tag beta
|
|
|
161
161
|
Install beta:
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
|
-
npm install
|
|
164
|
+
npm install loopwind@beta
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
## Resources
|
package/README.md
CHANGED
|
@@ -451,33 +451,34 @@ Templates can bundle their own fonts (WOFF, WOFF2, TTF, OTF):
|
|
|
451
451
|
|
|
452
452
|
```
|
|
453
453
|
my-template/
|
|
454
|
-
├──
|
|
455
|
-
├── meta.json
|
|
454
|
+
├── template.tsx
|
|
456
455
|
└── fonts/
|
|
457
456
|
├── CustomFont-Regular.woff
|
|
458
457
|
└── CustomFont-Bold.woff
|
|
459
458
|
```
|
|
460
459
|
|
|
461
|
-
**
|
|
462
|
-
```
|
|
463
|
-
{
|
|
464
|
-
|
|
465
|
-
|
|
460
|
+
**template.tsx:**
|
|
461
|
+
```tsx
|
|
462
|
+
export const meta = {
|
|
463
|
+
name: "my-template",
|
|
464
|
+
// ...
|
|
465
|
+
fonts: [
|
|
466
466
|
{
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
467
|
+
name: "Custom Font",
|
|
468
|
+
path: "fonts/CustomFont-Bold.woff",
|
|
469
|
+
weight: 700,
|
|
470
|
+
style: "normal"
|
|
471
471
|
}
|
|
472
472
|
]
|
|
473
|
-
}
|
|
474
|
-
```
|
|
473
|
+
};
|
|
475
474
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
<h1 style={{ fontFamily: 'Custom Font', fontWeight: 700 }}>
|
|
479
|
-
|
|
480
|
-
</h1>
|
|
475
|
+
export default function Template({ title, tw }) {
|
|
476
|
+
return (
|
|
477
|
+
<h1 style={{ fontFamily: 'Custom Font', fontWeight: 700 }}>
|
|
478
|
+
{title}
|
|
479
|
+
</h1>
|
|
480
|
+
);
|
|
481
|
+
}
|
|
481
482
|
```
|
|
482
483
|
|
|
483
484
|
**Use cases:**
|
|
@@ -681,7 +682,7 @@ loopwind render composite-card '{
|
|
|
681
682
|
- First render pass detects which templates are needed
|
|
682
683
|
- All templates load in parallel automatically
|
|
683
684
|
- Second render pass completes with loaded templates
|
|
684
|
-
- Each template uses its own
|
|
685
|
+
- Each template uses its own meta for sizing
|
|
685
686
|
- Returns JSX directly (not a data URI)
|
|
686
687
|
- Satori renders everything as a single SVG tree
|
|
687
688
|
|
|
@@ -854,43 +855,27 @@ Templates are stored in your project's `_loopwind/templates/` directory. You can
|
|
|
854
855
|
mkdir -p _loopwind/templates/my-template
|
|
855
856
|
```
|
|
856
857
|
|
|
857
|
-
2. Create `meta
|
|
858
|
-
|
|
859
|
-
```json
|
|
860
|
-
{
|
|
861
|
-
"name": "my-template",
|
|
862
|
-
"description": "My custom template",
|
|
863
|
-
"type": "image",
|
|
864
|
-
"size": { "width": 1200, "height": 630 },
|
|
865
|
-
"props": {
|
|
866
|
-
"title": "string"
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
```
|
|
870
|
-
|
|
871
|
-
3. Create `my-template.tsx`:
|
|
858
|
+
2. Create `template.tsx` with exported meta:
|
|
872
859
|
|
|
873
860
|
```tsx
|
|
874
|
-
export
|
|
861
|
+
export const meta = {
|
|
862
|
+
name: "my-template",
|
|
863
|
+
description: "My custom template",
|
|
864
|
+
type: "image",
|
|
865
|
+
size: { width: 1200, height: 630 },
|
|
866
|
+
props: { title: "string" }
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
export default function MyTemplate({ title, tw }) {
|
|
875
870
|
return (
|
|
876
|
-
<div style={
|
|
877
|
-
display: 'flex',
|
|
878
|
-
width: '100%',
|
|
879
|
-
height: '100%',
|
|
880
|
-
background: '#000',
|
|
881
|
-
color: '#fff',
|
|
882
|
-
justifyContent: 'center',
|
|
883
|
-
alignItems: 'center',
|
|
884
|
-
fontSize: '48px',
|
|
885
|
-
fontFamily: 'sans-serif',
|
|
886
|
-
}}>
|
|
871
|
+
<div style={tw('flex items-center justify-center w-full h-full bg-black text-white text-5xl')}>
|
|
887
872
|
{title}
|
|
888
873
|
</div>
|
|
889
874
|
);
|
|
890
875
|
}
|
|
891
876
|
```
|
|
892
877
|
|
|
893
|
-
|
|
878
|
+
3. Validate and render:
|
|
894
879
|
|
|
895
880
|
```bash
|
|
896
881
|
loopwind validate my-template
|
|
@@ -955,9 +940,12 @@ export default function Template({ title, frame, progress, tw, qr, template }) {
|
|
|
955
940
|
### Rendering Videos
|
|
956
941
|
|
|
957
942
|
```bash
|
|
958
|
-
# Render to MP4
|
|
943
|
+
# Render to MP4 (default)
|
|
959
944
|
loopwind render my-video '{"title":"Animated Title"}' -o output.mp4
|
|
960
945
|
|
|
946
|
+
# Render to GIF (great for emails, GitHub, Slack)
|
|
947
|
+
loopwind render my-video '{"title":"Animated Title"}' --format gif -o output.gif
|
|
948
|
+
|
|
961
949
|
# With custom quality settings
|
|
962
950
|
loopwind render my-video props.json --crf 18 # Higher quality (lower CRF = better quality)
|
|
963
951
|
|
|
@@ -965,6 +953,10 @@ loopwind render my-video props.json --crf 18 # Higher quality (lower CRF = bet
|
|
|
965
953
|
loopwind render my-video props.json --frames-only -o frames/
|
|
966
954
|
```
|
|
967
955
|
|
|
956
|
+
**Output formats:**
|
|
957
|
+
- **MP4** - H.264 codec, smaller files, best quality (default)
|
|
958
|
+
- **GIF** - Animated, works everywhere (emails, GitHub READMEs, Slack)
|
|
959
|
+
|
|
968
960
|
**How it works:**
|
|
969
961
|
1. **SVG Generation**: All frames generated in parallel (~0.8s for 90 frames)
|
|
970
962
|
2. **WASM Encoding**: Frames encoded to H.264 MP4 using pure JavaScript (~1.2s for 90 frames)
|
package/REGISTRY_SETUP.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The registry is a simple HTTP endpoint that serves template JSON files. Users run `
|
|
5
|
+
The registry is a simple HTTP endpoint that serves template JSON files. Users run `loopwind add template-name` and it fetches from `https://loopwind.dev/r/template-name`.
|
|
6
6
|
|
|
7
7
|
## Quick Solutions
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ Host static JSON files on any static hosting:
|
|
|
13
13
|
**1. Create template JSON files:**
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
|
|
16
|
+
loopwind.dev/
|
|
17
17
|
└── r/
|
|
18
18
|
├── banner-hero.json
|
|
19
19
|
├── product-card.json
|
|
@@ -119,7 +119,7 @@ Until you set up a real registry, use GitHub:
|
|
|
119
119
|
**1. Create a templates repo:**
|
|
120
120
|
|
|
121
121
|
```
|
|
122
|
-
github.com/yourusername/
|
|
122
|
+
github.com/yourusername/loopwind-templates/
|
|
123
123
|
├── banner-hero/
|
|
124
124
|
│ ├── template.json
|
|
125
125
|
│ ├── banner-hero.tsx
|
|
@@ -132,20 +132,20 @@ github.com/yourusername/dsgn-templates/
|
|
|
132
132
|
**2. Users install with:**
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
|
-
|
|
135
|
+
loopwind add github:yourusername/loopwind-templates/banner-hero
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
**3. Update CLI default:**
|
|
139
139
|
|
|
140
140
|
```typescript
|
|
141
141
|
// src/lib/constants.ts
|
|
142
|
-
export const DEFAULT_REGISTRY = 'github:yourusername/
|
|
142
|
+
export const DEFAULT_REGISTRY = 'github:yourusername/loopwind-templates';
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
Then users can:
|
|
146
146
|
|
|
147
147
|
```bash
|
|
148
|
-
|
|
148
|
+
loopwind add banner-hero # Uses GitHub as registry
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
## Creating Template JSON Files
|
|
@@ -209,7 +209,7 @@ registry/
|
|
|
209
209
|
└── social-og.json
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
Upload these to `
|
|
212
|
+
Upload these to `loopwind.dev/r/`
|
|
213
213
|
|
|
214
214
|
## Example Hosting Setups
|
|
215
215
|
|
|
@@ -218,8 +218,8 @@ Upload these to `dsgncli.com/r/`
|
|
|
218
218
|
**1. Create Next.js project:**
|
|
219
219
|
|
|
220
220
|
```bash
|
|
221
|
-
npx create-next-app@latest
|
|
222
|
-
cd
|
|
221
|
+
npx create-next-app@latest loopwind-registry
|
|
222
|
+
cd loopwind-registry
|
|
223
223
|
```
|
|
224
224
|
|
|
225
225
|
**2. Create API route:**
|
|
@@ -250,7 +250,7 @@ vercel
|
|
|
250
250
|
|
|
251
251
|
**4. Configure domain:**
|
|
252
252
|
|
|
253
|
-
Set `
|
|
253
|
+
Set `loopwind.dev` to point to your Vercel project.
|
|
254
254
|
|
|
255
255
|
### Cloudflare Workers
|
|
256
256
|
|
|
@@ -333,7 +333,7 @@ app.get('/r/:name', async (req, res) => {
|
|
|
333
333
|
});
|
|
334
334
|
|
|
335
335
|
// Users can install specific versions
|
|
336
|
-
//
|
|
336
|
+
// loopwind add banner-hero@1.2.0
|
|
337
337
|
```
|
|
338
338
|
|
|
339
339
|
## Testing Your Registry
|
|
@@ -342,7 +342,7 @@ Once deployed, test it:
|
|
|
342
342
|
|
|
343
343
|
```bash
|
|
344
344
|
# Test the endpoint
|
|
345
|
-
curl https://
|
|
345
|
+
curl https://loopwind.dev/r/banner-hero
|
|
346
346
|
|
|
347
347
|
# Should return JSON like:
|
|
348
348
|
{
|
|
@@ -352,7 +352,7 @@ curl https://dsgncli.com/r/banner-hero
|
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
# Test with CLI
|
|
355
|
-
|
|
355
|
+
loopwind add banner-hero
|
|
356
356
|
```
|
|
357
357
|
|
|
358
358
|
## Until Registry is Ready
|
|
@@ -360,7 +360,7 @@ dsgn add banner-hero
|
|
|
360
360
|
**Option 1:** Tell users to use GitHub:
|
|
361
361
|
|
|
362
362
|
```bash
|
|
363
|
-
|
|
363
|
+
loopwind add github:yourusername/loopwind-templates/banner-hero
|
|
364
364
|
```
|
|
365
365
|
|
|
366
366
|
**Option 2:** Update README with temporary instructions:
|
|
@@ -371,7 +371,7 @@ dsgn add github:yourusername/dsgn-templates/banner-hero
|
|
|
371
371
|
Templates are currently hosted on GitHub. Install with:
|
|
372
372
|
|
|
373
373
|
\`\`\`bash
|
|
374
|
-
|
|
374
|
+
loopwind add github:loopwindcli/templates/banner-hero
|
|
375
375
|
\`\`\`
|
|
376
376
|
|
|
377
377
|
Official registry coming soon!
|
|
@@ -386,7 +386,7 @@ Include templates directly in the npm package:
|
|
|
386
386
|
**1. Create templates folder:**
|
|
387
387
|
|
|
388
388
|
```
|
|
389
|
-
|
|
389
|
+
loopwind/
|
|
390
390
|
├── dist/
|
|
391
391
|
└── bundled-templates/
|
|
392
392
|
├── banner-hero.json
|
|
@@ -414,8 +414,8 @@ export async function fetchTemplate(name: string) {
|
|
|
414
414
|
**3. Users get core templates immediately:**
|
|
415
415
|
|
|
416
416
|
```bash
|
|
417
|
-
npm install -g
|
|
418
|
-
|
|
417
|
+
npm install -g loopwind
|
|
418
|
+
loopwind add banner-hero # Works offline!
|
|
419
419
|
```
|
|
420
420
|
|
|
421
421
|
## Recommended Approach
|