loopwind 0.12.1 → 0.12.3

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 DELETED
@@ -1,160 +0,0 @@
1
- # Font Handling in loopwind
2
-
3
- loopwind has a two-part font system:
4
- 1. **Font Data** (template-specific) - Actual font files loaded by Satori
5
- 2. **Font Classes** (project-wide) - CSS font-family applied via `tw()`
6
-
7
- ## Font Data (Loaded by Satori)
8
-
9
- Templates can bundle custom fonts or use the default font.
10
-
11
- ### Default Font (No Setup Required)
12
-
13
- If a template doesn't specify fonts, **Noto Sans** is automatically fetched from jsDelivr CDN.
14
-
15
- ### Custom Fonts (Template-Bundled)
16
-
17
- Templates can bundle their own fonts for:
18
- - **Brand-specific fonts** (e.g., company brand guidelines)
19
- - **Offline rendering** (no CDN dependency)
20
- - **Custom typography** (special display fonts)
21
-
22
- **Template Structure with Fonts:**
23
-
24
- ```
25
- my-template/
26
- ├── template.tsx
27
- └── fonts/
28
- ├── Inter-Regular.woff
29
- ├── Inter-Bold.woff
30
- └── Playfair-Bold.woff
31
- ```
32
-
33
- **Template with Custom Fonts:**
34
-
35
- ```tsx
36
- export const meta = {
37
- name: "my-template",
38
- type: "image",
39
- size: { width: 1200, height: 630 },
40
- props: { title: "string" },
41
- fonts: [
42
- {
43
- name: "Inter",
44
- path: "fonts/Inter-Regular.woff",
45
- weight: 400,
46
- style: "normal"
47
- },
48
- {
49
- name: "Inter",
50
- path: "fonts/Inter-Bold.woff",
51
- weight: 700,
52
- style: "normal"
53
- }
54
- ]
55
- };
56
-
57
- export default function Template({ title, tw }) {
58
- return (
59
- <h1 style={tw('font-sans font-bold text-6xl')}>{title}</h1>
60
- );
61
- }
62
- ```
63
-
64
- **Supported Formats:**
65
- - ✅ **WOFF** (`.woff`) - Recommended
66
- - ✅ **WOFF2** (`.woff2`) - Best compression
67
- - ✅ **TTF** (`.ttf`) - Also supported
68
- - ✅ **OTF** (`.otf`) - Also supported
69
-
70
- ## Font Classes (from loopwind.json)
71
-
72
- Use Tailwind font-family classes in templates. These reference the font stacks in `loopwind.json`:
73
-
74
- **loopwind.json:**
75
- ```json
76
- {
77
- "fonts": {
78
- "sans": ["Inter", "system-ui", "-apple-system", "sans-serif"],
79
- "serif": ["Georgia", "serif"],
80
- "mono": ["JetBrains Mono", "Courier New", "monospace"]
81
- }
82
- }
83
- ```
84
-
85
- **Template usage:**
86
- ```tsx
87
- export default function({ title, tw }) {
88
- return (
89
- <div style={tw('w-full h-full')}>
90
- {/* Uses fonts.sans from loopwind.json */}
91
- <h1 style={tw('font-sans text-6xl font-bold')}>
92
- {title}
93
- </h1>
94
-
95
- {/* Uses fonts.mono from loopwind.json */}
96
- <code style={tw('font-mono text-sm')}>
97
- Hello World
98
- </code>
99
- </div>
100
- );
101
- }
102
- ```
103
-
104
- **Available classes:**
105
- - `font-sans` - Uses `fonts.sans` from loopwind.json (default: system-ui, -apple-system, sans-serif)
106
- - `font-serif` - Uses `fonts.serif` from loopwind.json (default: Georgia, serif)
107
- - `font-mono` - Uses `fonts.mono` from loopwind.json (default: monospace)
108
-
109
- ## How It Works Together
110
-
111
- 1. **Font data** is loaded from template's exported `meta` (or default Noto Sans)
112
- 2. **Font classes** (`font-sans`) apply CSS `fontFamily` from `loopwind.json`
113
- 3. The font name in CSS must match a loaded font for Satori to use it
114
-
115
- **Example:**
116
-
117
- ```tsx
118
- // template.tsx - Loads the actual font files
119
- export const meta = {
120
- name: "my-template",
121
- // ...
122
- fonts: [
123
- { name: "Inter", path: "fonts/Inter-Regular.woff", weight: 400, style: "normal" },
124
- { name: "Inter", path: "fonts/Inter-Bold.woff", weight: 700, style: "normal" }
125
- ]
126
- };
127
-
128
- export default function Template({ title, tw }) {
129
- return (
130
- <h1 style={tw('font-sans font-bold')}>
131
- {/* font-sans → fontFamily: "Inter, system-ui, sans-serif" */}
132
- {/* Satori uses loaded "Inter" font from meta */}
133
- {title}
134
- </h1>
135
- );
136
- }
137
- ```
138
-
139
- ```json
140
- // loopwind.json - Defines font stacks for CSS
141
- {
142
- "fonts": {
143
- "sans": ["Inter", "system-ui", "sans-serif"]
144
- }
145
- }
146
- ```
147
-
148
- ## Fallback Behavior
149
-
150
- - If template fonts fail to load → falls back to Noto Sans from CDN
151
- - If `font-sans` used but no fonts defined → uses system font stack
152
- - If CSS font-family doesn't match loaded fonts → Satori uses fallback
153
-
154
- ## Best Practices
155
-
156
- 1. **For most templates:** Use default Noto Sans, no font setup needed
157
- 2. **For branded templates:** Bundle custom fonts in template's `fonts/` folder
158
- 3. **Use font classes:** `tw('font-sans')` instead of raw `fontFamily: 'Inter'`
159
- 4. **Match names:** Ensure `loopwind.json` font names match template's loaded fonts
160
- 5. **Include fallbacks:** Always include system fallbacks in font stacks
package/HELPERS_DEMO.md DELETED
@@ -1,126 +0,0 @@
1
- # Image and Video Helpers - Simple Demo
2
-
3
- ## ✅ What We Added
4
-
5
- Two new helpers for templates:
6
- - `image()` - Embed images (jpg, png, gif, webp, svg)
7
- - `video()` - Embed videos (mp4, mov, etc.) - auto-syncs to current frame
8
-
9
- ## Usage
10
-
11
- ### Images
12
-
13
- ```tsx
14
- export default function Banner({ tw, image }) {
15
- return (
16
- <div style={tw('relative w-full h-full')}>
17
- <img src={image('background.jpg')} />
18
- <h1 style={tw('absolute top-10 left-10')}>Hello World</h1>
19
- </div>
20
- );
21
- }
22
- ```
23
-
24
- **Props format:**
25
- ```json
26
- {
27
- "background": "./path/to/background.jpg"
28
- }
29
- ```
30
-
31
- The renderer automatically detects props that end in image extensions and pre-loads them.
32
-
33
- ### Videos (for video templates)
34
-
35
- ```tsx
36
- export default function VideoOverlay({ tw, video, frame, title }) {
37
- return (
38
- <div style={tw('relative w-full h-full')}>
39
- <img src={video('background.mp4')} />
40
- <h1 style={tw('absolute top-10 left-10 text-white')}>{title}</h1>
41
- </div>
42
- );
43
- }
44
- ```
45
-
46
- **How it works:**
47
- 1. First render pass: Template calls `video('background.mp4')` → marks video as needed
48
- 2. Pre-generation: Extracts all frames from video at template's FPS
49
- 3. Actual render: Returns frame matching current template frame number
50
- 4. Frames are cached in memory for fast access
51
-
52
- **Props format:**
53
- ```json
54
- {
55
- "title": "My Video",
56
- "background": "./path/to/background.mp4"
57
- }
58
- ```
59
-
60
- Then use the `video()` helper with the prop value.
61
-
62
- ## Why This Is Simple
63
-
64
- - **No complex API** - Just `image('path')` and `video('path')`
65
- - **Auto-syncing** - Videos automatically match template frame
66
- - **Caching** - Frames extracted once, reused for all renders
67
- - **Works like QR codes** - Same discovery + pre-generation pattern
68
- - **No timeline controls** - Keep it simple, just background videos
69
-
70
- ## Example: Video with Text Overlay
71
-
72
- ```tsx
73
- // Template: _loopwind/templates/video-overlay/template.tsx
74
- export const meta = {
75
- name: "video-overlay",
76
- type: "video",
77
- size: { width: 1920, height: 1080 },
78
- video: { fps: 30, duration: 3 },
79
- props: { title: "string", background: "string" }
80
- };
81
-
82
- export default function VideoOverlay({ tw, video, frame, progress, title }) {
83
- // Animate title opacity
84
- const opacity = progress < 0.2 ? progress / 0.2 : 1;
85
-
86
- return (
87
- <div style={tw('relative w-full h-full flex items-center justify-center')}>
88
- {/* Background video - auto-syncs to current frame */}
89
- <img
90
- src={video('background')}
91
- style={tw('absolute inset-0 w-full h-full object-cover')}
92
- />
93
-
94
- {/* Animated title */}
95
- <h1
96
- style={{
97
- ...tw('text-6xl font-bold text-white'),
98
- opacity
99
- }}
100
- >
101
- {title}
102
- </h1>
103
- </div>
104
- );
105
- }
106
- ```
107
-
108
- ```json
109
- // props.json
110
- {
111
- "title": "Hello World",
112
- "background": "./my-video.mp4"
113
- }
114
- ```
115
-
116
- ```bash
117
- # Render
118
- loopwind render video-overlay props.json --out output.mp4
119
- ```
120
-
121
- This will:
122
- 1. Extract frames from `my-video.mp4` at 30fps
123
- 2. Render 90 frames (3s × 30fps) with animated title overlay
124
- 3. Encode to MP4
125
-
126
- **Super fast and simple!** 🚀
@@ -1,284 +0,0 @@
1
- # Project Structure
2
-
3
- ## Overview
4
-
5
- **loopwind** is a global CLI tool that operates on project-local templates and outputs.
6
-
7
- Think of it like:
8
- - **Global CLI**: Like `npm` or `git` - installed once, used everywhere
9
- - **Local templates**: Like `node_modules` - each project has its own
10
- - **Local outputs**: Generated assets stay with the project
11
-
12
- ## Directory Structure
13
-
14
- ### Your Project
15
-
16
- When you use `loopwind` in your project, this is the structure:
17
-
18
- ```
19
- my-project/
20
- ├── _loopwind/
21
- │ ├── templates/ # Installed templates (like node_modules)
22
- │ │ ├── banner-hero/
23
- │ │ │ └── template.tsx # Contains export const meta + component
24
- │ │ └── product-card/
25
- │ │ └── template.tsx
26
- │ └── outputs/ # Generated images/videos
27
- │ ├── banner-hero.png
28
- │ └── product-card.png
29
- ├── loopwind.json # Your project's design tokens (optional)
30
- └── package.json
31
- ```
32
-
33
- ### The CLI Package (this repo)
34
-
35
- ```
36
- loopwind/
37
- ├── src/
38
- │ ├── cli.ts # Main CLI entry point
39
- │ ├── commands/ # Command implementations
40
- │ │ ├── add.ts # Install templates
41
- │ │ ├── list.ts # List templates
42
- │ │ ├── render.ts # Render images
43
- │ │ ├── validate.ts # Validate templates
44
- │ │ └── init.ts # Initialize config
45
- │ ├── lib/
46
- │ │ ├── constants.ts # Paths and constants
47
- │ │ ├── utils.ts # Utility functions
48
- │ │ ├── installer.ts # Registry fetching
49
- │ │ ├── renderer.ts # Satori rendering
50
- │ │ └── config.ts # Config handling
51
- │ └── types/
52
- │ ├── template.ts # Template types
53
- │ └── config.ts # Config types
54
- ├── dist/ # Compiled output
55
- ├── package.json
56
- ├── tsconfig.json
57
- └── README.md
58
- ```
59
-
60
- ## How It Works
61
-
62
- ### 1. Global Installation
63
-
64
- ```bash
65
- npm install -g loopwind
66
- ```
67
-
68
- This installs the CLI globally, making the `loopwind` command available anywhere.
69
-
70
- ### 2. Project Usage
71
-
72
- ```bash
73
- cd ~/my-project
74
- loopwind add banner-hero
75
- ```
76
-
77
- This:
78
- 1. Fetches template from registry: `https://design.unpeel.dev/r/banner-hero`
79
- 2. Installs to: `~/my-project/loopwind/templates/banner-hero/`
80
- 3. Creates structure if it doesn't exist
81
-
82
- ### 3. Rendering
83
-
84
- ```bash
85
- loopwind render banner-hero --props '{"title":"Hello"}'
86
- ```
87
-
88
- This:
89
- 1. Loads template from `loopwind/templates/banner-hero/`
90
- 2. Loads config from `loopwind.json` (if exists)
91
- 3. Renders with Satori
92
- 4. Saves to `loopwind/outputs/banner-hero-{timestamp}.png`
93
-
94
- ## Why This Architecture?
95
-
96
- ### Global CLI
97
-
98
- **Benefits:**
99
- - Install once, use everywhere
100
- - Always up to date
101
- - Consistent tooling across projects
102
-
103
- **Like:**
104
- - `npm` - global tool, local packages
105
- - `git` - global tool, local repos
106
- - `tsc` - global TypeScript compiler
107
-
108
- ### Local Templates
109
-
110
- **Benefits:**
111
- - Version controlled with your project
112
- - Different projects can use different template versions
113
- - Team members get the same templates
114
- - No dependency on external registry at runtime
115
-
116
- **Like:**
117
- - `node_modules` - dependencies live with the project
118
- - `.next` - build artifacts live with the project
119
-
120
- ### Local Outputs
121
-
122
- **Benefits:**
123
- - Generated assets stay with the project
124
- - Easy to commit to git (if desired)
125
- - No confusion about where files are
126
- - Works well with build processes
127
-
128
- ## Template Registry
129
-
130
- Templates live online (like npm registry):
131
-
132
- ```
133
- https://design.unpeel.dev/r/banner-hero
134
- ```
135
-
136
- Returns:
137
-
138
- ```json
139
- {
140
- "name": "banner-hero",
141
- "version": "1.0.0",
142
- "description": "A hero banner",
143
- "files": [
144
- {
145
- "path": "banner-hero.tsx",
146
- "content": "..."
147
- },
148
- {
149
- "path": "meta.json",
150
- "content": "..."
151
- }
152
- ]
153
- }
154
- ```
155
-
156
- When you run `loopwind add banner-hero`, it:
157
- 1. Fetches this JSON
158
- 2. Writes files to `loopwind/templates/banner-hero/`
159
- 3. Templates are now local and ready to use
160
-
161
- ## Git Workflow
162
-
163
- ### What to commit?
164
-
165
- **DO commit:**
166
- - `loopwind/templates/` - Your templates (like `node_modules` in some projects)
167
- - `loopwind.json` - Your design configuration
168
-
169
- **DON'T commit:**
170
- - `loopwind/outputs/` - Generated files (usually)
171
-
172
- Example `.gitignore`:
173
-
174
- ```gitignore
175
- # Ignore generated outputs
176
- loopwind/outputs/
177
-
178
- # Keep templates (optional - depends on your workflow)
179
- # loopwind/templates/
180
- ```
181
-
182
- Some teams prefer to commit templates (reproducibility), others prefer to install them (like npm packages).
183
-
184
- ## Comparison to Other Tools
185
-
186
- ### Like Shadcn
187
-
188
- - Registry-based templates
189
- - Install to your project
190
- - You own the code
191
- - Customize freely
192
-
193
- ### Like npm
194
-
195
- - Global CLI tool
196
- - Project-local dependencies (templates)
197
- - Registry for discovery
198
- - Semantic versioning
199
-
200
- ### Like Tailwind
201
-
202
- - Config file for customization
203
- - Design tokens approach
204
- - Build-time generation
205
- - Framework agnostic
206
-
207
- ## Common Workflows
208
-
209
- ### Starting a New Project
210
-
211
- ```bash
212
- mkdir my-project
213
- cd my-project
214
-
215
- # Initialize config
216
- loopwind init
217
-
218
- # Install templates
219
- loopwind add banner-hero
220
- loopwind add product-card
221
-
222
- # Render images
223
- loopwind render banner-hero --props props.json
224
- ```
225
-
226
- ### Sharing with Team
227
-
228
- ```bash
229
- # Developer 1
230
- git add loopwind/templates/
231
- git commit -m "Add banner template"
232
- git push
233
-
234
- # Developer 2
235
- git pull
236
- loopwind list # See all templates
237
- loopwind render banner-hero --props '{"title":"Team Banner"}'
238
- ```
239
-
240
- ### CI/CD Pipeline
241
-
242
- ```yaml
243
- # .github/workflows/generate-images.yml
244
- - name: Install loopwind
245
- run: npm install -g loopwind
246
-
247
- - name: Generate images
248
- run: |
249
- loopwind render banner-hero --props props/hero.json
250
- loopwind render product-card --props props/product.json
251
-
252
- - name: Upload artifacts
253
- uses: actions/upload-artifact@v3
254
- with:
255
- path: loopwind/outputs/
256
- ```
257
-
258
- ## Future Enhancements
259
-
260
- ### Template Versions
261
-
262
- ```bash
263
- loopwind add banner-hero@2.0.0
264
- loopwind update banner-hero
265
- ```
266
-
267
- ### Template Marketplace
268
-
269
- ```bash
270
- loopwind search "hero"
271
- loopwind add @company/custom-banner
272
- ```
273
-
274
- ### Global vs Local
275
-
276
- ```bash
277
- # Install globally (like npm -g)
278
- loopwind add banner-hero --global
279
-
280
- # Install locally (default, like npm install)
281
- loopwind add banner-hero
282
- ```
283
-
284
- This is the **Shadcn for design and marketing** - same philosophy of owning your code, but for design assets!