loopwind 0.9.1
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 +156 -0
- package/HELPERS_DEMO.md +134 -0
- package/PROJECT_STRUCTURE.md +286 -0
- package/PUBLISHING.md +171 -0
- package/README.md +1020 -0
- package/REGISTRY_SETUP.md +427 -0
- package/SHADCN_INTEGRATION.md +269 -0
- package/TAILWIND.md +228 -0
- package/TEMPLATE_SOURCES.md +363 -0
- package/_dsgn/templates/banner-hero/banner-hero.tsx +57 -0
- package/_dsgn/templates/banner-hero/meta.json +14 -0
- package/_dsgn/templates/composite-card/meta.json +16 -0
- package/_dsgn/templates/composite-card/template.tsx +44 -0
- package/_dsgn/templates/image/meta.json +13 -0
- package/_dsgn/templates/image/template.tsx +28 -0
- package/_dsgn/templates/kitchen-sink/meta.json +13 -0
- package/_dsgn/templates/kitchen-sink/template.tsx +72 -0
- package/_dsgn/templates/qr-card/meta.json +14 -0
- package/_dsgn/templates/qr-card/template.tsx +39 -0
- package/_dsgn/templates/test-parent/child/meta.json +11 -0
- package/_dsgn/templates/test-parent/child/template.tsx +27 -0
- package/_dsgn/templates/test-parent/meta.json +12 -0
- package/_dsgn/templates/test-parent/template.tsx +30 -0
- package/_dsgn/templates/test-sibling/meta.json +11 -0
- package/_dsgn/templates/test-sibling/template.tsx +20 -0
- package/_dsgn/templates/video/.tmp/template-1763421345296.mjs +43 -0
- package/_dsgn/templates/video/.tmp/template-1763421362228.mjs +43 -0
- package/_dsgn/templates/video/.tmp/template-1763421377706.mjs +43 -0
- package/_dsgn/templates/video/meta.json +17 -0
- package/_dsgn/templates/video/template.tsx +48 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +6 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +86 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/default.d.ts +2 -0
- package/dist/commands/default.d.ts.map +1 -0
- package/dist/commands/default.js +69 -0
- package/dist/commands/default.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +75 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +83 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/preview.d.ts +3 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +296 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/render.d.ts +10 -0
- package/dist/commands/render.d.ts.map +1 -0
- package/dist/commands/render.js +204 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +107 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/default-templates/AGENTS.md +229 -0
- package/dist/default-templates/image/meta.json +13 -0
- package/dist/default-templates/image/template.d.ts +20 -0
- package/dist/default-templates/image/template.d.ts.map +1 -0
- package/dist/default-templates/image/template.js +18 -0
- package/dist/default-templates/image/template.js.map +1 -0
- package/dist/default-templates/image/template.tsx +20 -0
- package/dist/default-templates/image-template/meta.json +13 -0
- package/dist/default-templates/image-template/template.tsx +19 -0
- package/dist/default-templates/kitchen-sink/meta.json +13 -0
- package/dist/default-templates/kitchen-sink/template.tsx +64 -0
- package/dist/default-templates/page/meta.json +17 -0
- package/dist/default-templates/page/template.tsx +37 -0
- package/dist/default-templates/video/meta.json +17 -0
- package/dist/default-templates/video/template.d.ts +26 -0
- package/dist/default-templates/video/template.d.ts.map +1 -0
- package/dist/default-templates/video/template.js +33 -0
- package/dist/default-templates/video/template.js.map +1 -0
- package/dist/default-templates/video/template.tsx +37 -0
- package/dist/default-templates/video-template/meta.json +17 -0
- package/dist/default-templates/video-template/template.tsx +36 -0
- package/dist/default-templates/website/meta.json +16 -0
- package/dist/default-templates/website/pages/home.tsx +17 -0
- package/dist/default-templates/website/parts/footer.tsx +17 -0
- package/dist/default-templates/website/parts/header.tsx +17 -0
- package/dist/default-templates/website/template.tsx +17 -0
- package/dist/default-templates/website-template/meta.json +16 -0
- package/dist/default-templates/website-template/pages/home.tsx +16 -0
- package/dist/default-templates/website-template/parts/footer.tsx +16 -0
- package/dist/default-templates/website-template/parts/header.tsx +16 -0
- package/dist/default-templates/website-template/template.tsx +16 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +248 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +7 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +12 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/helpers.d.ts +29 -0
- package/dist/lib/helpers.d.ts.map +1 -0
- package/dist/lib/helpers.js +159 -0
- package/dist/lib/helpers.js.map +1 -0
- package/dist/lib/installer.d.ts +51 -0
- package/dist/lib/installer.d.ts.map +1 -0
- package/dist/lib/installer.js +215 -0
- package/dist/lib/installer.js.map +1 -0
- package/dist/lib/renderer.d.ts +51 -0
- package/dist/lib/renderer.d.ts.map +1 -0
- package/dist/lib/renderer.js +524 -0
- package/dist/lib/renderer.js.map +1 -0
- package/dist/lib/tailwind-config-loader.d.ts +47 -0
- package/dist/lib/tailwind-config-loader.d.ts.map +1 -0
- package/dist/lib/tailwind-config-loader.js +432 -0
- package/dist/lib/tailwind-config-loader.js.map +1 -0
- package/dist/lib/tailwind-detector.d.ts +36 -0
- package/dist/lib/tailwind-detector.d.ts.map +1 -0
- package/dist/lib/tailwind-detector.js +156 -0
- package/dist/lib/tailwind-detector.js.map +1 -0
- package/dist/lib/tailwind.d.ts +8 -0
- package/dist/lib/tailwind.d.ts.map +1 -0
- package/dist/lib/tailwind.js +994 -0
- package/dist/lib/tailwind.js.map +1 -0
- package/dist/lib/template-validator.d.ts +22 -0
- package/dist/lib/template-validator.d.ts.map +1 -0
- package/dist/lib/template-validator.js +174 -0
- package/dist/lib/template-validator.js.map +1 -0
- package/dist/lib/utils.d.ts +44 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +207 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/version-check.d.ts +16 -0
- package/dist/lib/version-check.d.ts.map +1 -0
- package/dist/lib/version-check.js +88 -0
- package/dist/lib/version-check.js.map +1 -0
- package/dist/lib/video-renderer.d.ts +32 -0
- package/dist/lib/video-renderer.d.ts.map +1 -0
- package/dist/lib/video-renderer.js +226 -0
- package/dist/lib/video-renderer.js.map +1 -0
- package/dist/sdk/index.d.ts +58 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +119 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/template.d.ts +40 -0
- package/dist/sdk/template.d.ts.map +1 -0
- package/dist/sdk/template.js +60 -0
- package/dist/sdk/template.js.map +1 -0
- package/dist/types/config.d.ts +62 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +47 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/template.d.ts +79 -0
- package/dist/types/template.d.ts.map +1 -0
- package/dist/types/template.js +2 -0
- package/dist/types/template.js.map +1 -0
- package/examples/nextjs-api/README.md +180 -0
- package/examples/nextjs-api/package.json +21 -0
- package/examples/nextjs-api/pages/api/intro-video.ts +53 -0
- package/examples/nextjs-api/pages/api/og-image.ts +50 -0
- package/netlify.toml +13 -0
- package/package.json +84 -0
- package/patches/satori+0.18.3.patch +13 -0
- package/test-templates/TESTS.md +63 -0
- package/test-templates/_dsgn/templates/absolute-spin/meta.json +7 -0
- package/test-templates/_dsgn/templates/absolute-spin/template.tsx +16 -0
- package/test-templates/_dsgn/templates/animated-intro/.tmp/template-1763468771640.mjs +7 -0
- package/test-templates/_dsgn/templates/animated-intro/meta.json +10 -0
- package/test-templates/_dsgn/templates/animated-intro/template.tsx +23 -0
- package/test-templates/_dsgn/templates/centered-spin/.tmp/template-1763468525386.mjs +7 -0
- package/test-templates/_dsgn/templates/centered-spin/meta.json +7 -0
- package/test-templates/_dsgn/templates/centered-spin/template.tsx +11 -0
- package/test-templates/_dsgn/templates/composite/.tmp/template-1763468815645.mjs +7 -0
- package/test-templates/_dsgn/templates/composite/meta.json +9 -0
- package/test-templates/_dsgn/templates/composite/template.tsx +23 -0
- package/test-templates/_dsgn/templates/easing-test/.tmp/template-1763468824501.mjs +7 -0
- package/test-templates/_dsgn/templates/easing-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/easing-test/template.tsx +47 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466364336.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466584319.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466667797.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466746504.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466930225.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467004552.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467060334.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467124493.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467174690.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467359134.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467451928.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467758275.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467985201.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468020563.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468090428.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468211036.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468394057.mjs +10 -0
- package/test-templates/_dsgn/templates/minimal-spin/meta.json +7 -0
- package/test-templates/_dsgn/templates/minimal-spin/template.tsx +13 -0
- package/test-templates/_dsgn/templates/no-origin-spin/meta.json +7 -0
- package/test-templates/_dsgn/templates/no-origin-spin/template.tsx +10 -0
- package/test-templates/_dsgn/templates/opacity-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/opacity-test/template.tsx +9 -0
- package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468758954.mjs +17 -0
- package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468815672.mjs +17 -0
- package/test-templates/_dsgn/templates/qr-code/meta.json +9 -0
- package/test-templates/_dsgn/templates/qr-code/template.tsx +20 -0
- package/test-templates/_dsgn/templates/rotation-abs-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/rotation-abs-test/template.tsx +15 -0
- package/test-templates/_dsgn/templates/rotation-corner/meta.json +7 -0
- package/test-templates/_dsgn/templates/rotation-corner/template.tsx +12 -0
- package/test-templates/_dsgn/templates/rotation-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/rotation-test/template.tsx +12 -0
- package/test-templates/_dsgn/templates/shake-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/shake-test/template.tsx +12 -0
- package/test-templates/_dsgn/templates/static-image/.tmp/template-1763468746271.mjs +7 -0
- package/test-templates/_dsgn/templates/static-image/meta.json +9 -0
- package/test-templates/_dsgn/templates/static-image/template.tsx +19 -0
- package/test-templates/_dsgn/templates/translate-test/meta.json +7 -0
- package/test-templates/_dsgn/templates/translate-test/template.tsx +9 -0
- package/test-templates/_dsgn/templates/video-loops/.tmp/template-1763468793192.mjs +15 -0
- package/test-templates/_dsgn/templates/video-loops/meta.json +9 -0
- package/test-templates/_dsgn/templates/video-loops/template.tsx +39 -0
- package/test-templates/_dsgn/templates/wrapped-spin/meta.json +7 -0
- package/test-templates/_dsgn/templates/wrapped-spin/template.tsx +17 -0
- package/test-templates/compare-svgs.mjs +30 -0
- package/test-templates/convert-frames.mjs +15 -0
- package/test-templates/debug-rotation.mjs +25 -0
- package/test-templates/run-tests.sh +39 -0
- package/test-templates/test-sdk.mjs +115 -0
- package/website/.astro/settings.json +5 -0
- package/website/.astro/types.d.ts +1 -0
- package/website/README.md +112 -0
- package/website/astro.config.mjs +18 -0
- package/website/dist/_astro/fonts.DHdiHGBO.css +1 -0
- package/website/dist/fonts/index.html +193 -0
- package/website/dist/helpers/index.html +166 -0
- package/website/dist/images/index.html +314 -0
- package/website/dist/index.html +219 -0
- package/website/dist/llm.txt +2448 -0
- package/website/dist/styling/index.html +365 -0
- package/website/dist/templates/index.html +124 -0
- package/website/dist/video/index.html +636 -0
- package/website/package-lock.json +7606 -0
- package/website/package.json +23 -0
- package/website/public/robots.txt +5 -0
package/FONTS.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Font Handling in dsgn
|
|
2
|
+
|
|
3
|
+
dsgn 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
|
+
├── my-template.tsx
|
|
27
|
+
├── meta.json
|
|
28
|
+
└── fonts/
|
|
29
|
+
├── Inter-Regular.woff
|
|
30
|
+
├── Inter-Bold.woff
|
|
31
|
+
└── Playfair-Bold.woff
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Metadata with Custom Fonts:**
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"name": "my-template",
|
|
39
|
+
"type": "image",
|
|
40
|
+
"size": { "width": 1200, "height": 630 },
|
|
41
|
+
"props": { "title": "string" },
|
|
42
|
+
"fonts": [
|
|
43
|
+
{
|
|
44
|
+
"name": "Inter",
|
|
45
|
+
"path": "fonts/Inter-Regular.woff",
|
|
46
|
+
"weight": 400,
|
|
47
|
+
"style": "normal"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "Inter",
|
|
51
|
+
"path": "fonts/Inter-Bold.woff",
|
|
52
|
+
"weight": 700,
|
|
53
|
+
"style": "normal"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Supported Formats:**
|
|
60
|
+
- ✅ **WOFF** (`.woff`) - Recommended
|
|
61
|
+
- ✅ **WOFF2** (`.woff2`) - Best compression
|
|
62
|
+
- ✅ **TTF** (`.ttf`) - Also supported
|
|
63
|
+
- ✅ **OTF** (`.otf`) - Also supported
|
|
64
|
+
|
|
65
|
+
## Font Classes (from dsgn.json)
|
|
66
|
+
|
|
67
|
+
Use Tailwind font-family classes in templates. These reference the font stacks in `dsgn.json`:
|
|
68
|
+
|
|
69
|
+
**dsgn.json:**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"fonts": {
|
|
73
|
+
"sans": ["Inter", "system-ui", "-apple-system", "sans-serif"],
|
|
74
|
+
"serif": ["Georgia", "serif"],
|
|
75
|
+
"mono": ["JetBrains Mono", "Courier New", "monospace"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Template usage:**
|
|
81
|
+
```tsx
|
|
82
|
+
export default function({ title, tw }) {
|
|
83
|
+
return (
|
|
84
|
+
<div style={tw('w-full h-full')}>
|
|
85
|
+
{/* Uses fonts.sans from dsgn.json */}
|
|
86
|
+
<h1 style={tw('font-sans text-6xl font-bold')}>
|
|
87
|
+
{title}
|
|
88
|
+
</h1>
|
|
89
|
+
|
|
90
|
+
{/* Uses fonts.mono from dsgn.json */}
|
|
91
|
+
<code style={tw('font-mono text-sm')}>
|
|
92
|
+
Hello World
|
|
93
|
+
</code>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Available classes:**
|
|
100
|
+
- `font-sans` - Uses `fonts.sans` from dsgn.json (default: system-ui, -apple-system, sans-serif)
|
|
101
|
+
- `font-serif` - Uses `fonts.serif` from dsgn.json (default: Georgia, serif)
|
|
102
|
+
- `font-mono` - Uses `fonts.mono` from dsgn.json (default: monospace)
|
|
103
|
+
|
|
104
|
+
## How It Works Together
|
|
105
|
+
|
|
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 `dsgn.json`
|
|
108
|
+
3. The font name in CSS must match a loaded font for Satori to use it
|
|
109
|
+
|
|
110
|
+
**Example:**
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
// Template meta.json - Loads the actual font files
|
|
114
|
+
{
|
|
115
|
+
"fonts": [
|
|
116
|
+
{ "name": "Inter", "path": "fonts/Inter-Regular.woff", "weight": 400 },
|
|
117
|
+
{ "name": "Inter", "path": "fonts/Inter-Bold.woff", "weight": 700 }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
// dsgn.json - Defines font stacks for CSS
|
|
124
|
+
{
|
|
125
|
+
"fonts": {
|
|
126
|
+
"sans": ["Inter", "system-ui", "sans-serif"]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// Template - Uses both
|
|
133
|
+
export default function({ title, tw }) {
|
|
134
|
+
return (
|
|
135
|
+
<h1 style={tw('font-sans font-bold')}>
|
|
136
|
+
{/* font-sans → fontFamily: "Inter, system-ui, sans-serif" */}
|
|
137
|
+
{/* Satori uses loaded "Inter" font from meta.json */}
|
|
138
|
+
{title}
|
|
139
|
+
</h1>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Fallback Behavior
|
|
145
|
+
|
|
146
|
+
- If template fonts fail to load → falls back to Noto Sans from CDN
|
|
147
|
+
- If `font-sans` used but no fonts defined → uses system font stack
|
|
148
|
+
- If CSS font-family doesn't match loaded fonts → Satori uses fallback
|
|
149
|
+
|
|
150
|
+
## Best Practices
|
|
151
|
+
|
|
152
|
+
1. **For most templates:** Use default Noto Sans, no font setup needed
|
|
153
|
+
2. **For branded templates:** Bundle custom fonts in template's `fonts/` folder
|
|
154
|
+
3. **Use font classes:** `tw('font-sans')` instead of raw `fontFamily: 'Inter'`
|
|
155
|
+
4. **Match names:** Ensure `dsgn.json` font names match template's loaded fonts
|
|
156
|
+
5. **Include fallbacks:** Always include system fallbacks in font stacks
|
package/HELPERS_DEMO.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
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: _dsgn/templates/video-overlay/index.tsx
|
|
74
|
+
export default function VideoOverlay({ tw, video, frame, progress, title }) {
|
|
75
|
+
// Animate title opacity
|
|
76
|
+
const opacity = progress < 0.2 ? progress / 0.2 : 1;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div style={tw('relative w-full h-full flex items-center justify-center')}>
|
|
80
|
+
{/* Background video - auto-syncs to current frame */}
|
|
81
|
+
<img
|
|
82
|
+
src={video('background.mp4')}
|
|
83
|
+
style={tw('absolute inset-0 w-full h-full object-cover')}
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
{/* Animated title */}
|
|
87
|
+
<h1
|
|
88
|
+
style={{
|
|
89
|
+
...tw('text-6xl font-bold text-white'),
|
|
90
|
+
opacity
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{title}
|
|
94
|
+
</h1>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
// meta.json
|
|
102
|
+
{
|
|
103
|
+
"name": "video-overlay",
|
|
104
|
+
"type": "video",
|
|
105
|
+
"size": {
|
|
106
|
+
"width": 1920,
|
|
107
|
+
"height": 1080
|
|
108
|
+
},
|
|
109
|
+
"video": {
|
|
110
|
+
"fps": 30,
|
|
111
|
+
"duration": 3
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
// props.json
|
|
118
|
+
{
|
|
119
|
+
"title": "Hello World",
|
|
120
|
+
"background": "./my-video.mp4"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Render
|
|
126
|
+
dsgn render video-overlay props.json --out output.mp4
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This will:
|
|
130
|
+
1. Extract frames from `my-video.mp4` at 30fps
|
|
131
|
+
2. Render 90 frames (3s × 30fps) with animated title overlay
|
|
132
|
+
3. Encode to MP4
|
|
133
|
+
|
|
134
|
+
**Super fast and simple!** 🚀
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
**dsgn** 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 `dsgn` in your project, this is the structure:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
my-project/
|
|
20
|
+
├── dsgn/
|
|
21
|
+
│ ├── templates/ # Installed templates (like node_modules)
|
|
22
|
+
│ │ ├── banner-hero/
|
|
23
|
+
│ │ │ ├── banner-hero.tsx
|
|
24
|
+
│ │ │ └── meta.json
|
|
25
|
+
│ │ └── product-card/
|
|
26
|
+
│ │ ├── product-card.tsx
|
|
27
|
+
│ │ └── meta.json
|
|
28
|
+
│ └── outputs/ # Generated images/videos
|
|
29
|
+
│ ├── banner-hero-1234567890.png
|
|
30
|
+
│ └── product-card-1234567891.png
|
|
31
|
+
├── dsgn.json # Your project's design tokens (optional)
|
|
32
|
+
└── package.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### The CLI Package (this repo)
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
dsgn/
|
|
39
|
+
├── src/
|
|
40
|
+
│ ├── cli.ts # Main CLI entry point
|
|
41
|
+
│ ├── commands/ # Command implementations
|
|
42
|
+
│ │ ├── add.ts # Install templates
|
|
43
|
+
│ │ ├── list.ts # List templates
|
|
44
|
+
│ │ ├── render.ts # Render images
|
|
45
|
+
│ │ ├── validate.ts # Validate templates
|
|
46
|
+
│ │ └── init.ts # Initialize config
|
|
47
|
+
│ ├── lib/
|
|
48
|
+
│ │ ├── constants.ts # Paths and constants
|
|
49
|
+
│ │ ├── utils.ts # Utility functions
|
|
50
|
+
│ │ ├── installer.ts # Registry fetching
|
|
51
|
+
│ │ ├── renderer.ts # Satori rendering
|
|
52
|
+
│ │ └── config.ts # Config handling
|
|
53
|
+
│ └── types/
|
|
54
|
+
│ ├── template.ts # Template types
|
|
55
|
+
│ └── config.ts # Config types
|
|
56
|
+
├── dist/ # Compiled output
|
|
57
|
+
├── package.json
|
|
58
|
+
├── tsconfig.json
|
|
59
|
+
└── README.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## How It Works
|
|
63
|
+
|
|
64
|
+
### 1. Global Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install -g dsgn
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This installs the CLI globally, making the `dsgn` command available anywhere.
|
|
71
|
+
|
|
72
|
+
### 2. Project Usage
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cd ~/my-project
|
|
76
|
+
dsgn add banner-hero
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This:
|
|
80
|
+
1. Fetches template from registry: `https://design.unpeel.dev/r/banner-hero`
|
|
81
|
+
2. Installs to: `~/my-project/dsgn/templates/banner-hero/`
|
|
82
|
+
3. Creates structure if it doesn't exist
|
|
83
|
+
|
|
84
|
+
### 3. Rendering
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
dsgn render banner-hero --props '{"title":"Hello"}'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This:
|
|
91
|
+
1. Loads template from `dsgn/templates/banner-hero/`
|
|
92
|
+
2. Loads config from `dsgn.json` (if exists)
|
|
93
|
+
3. Renders with Satori
|
|
94
|
+
4. Saves to `dsgn/outputs/banner-hero-{timestamp}.png`
|
|
95
|
+
|
|
96
|
+
## Why This Architecture?
|
|
97
|
+
|
|
98
|
+
### Global CLI
|
|
99
|
+
|
|
100
|
+
**Benefits:**
|
|
101
|
+
- Install once, use everywhere
|
|
102
|
+
- Always up to date
|
|
103
|
+
- Consistent tooling across projects
|
|
104
|
+
|
|
105
|
+
**Like:**
|
|
106
|
+
- `npm` - global tool, local packages
|
|
107
|
+
- `git` - global tool, local repos
|
|
108
|
+
- `tsc` - global TypeScript compiler
|
|
109
|
+
|
|
110
|
+
### Local Templates
|
|
111
|
+
|
|
112
|
+
**Benefits:**
|
|
113
|
+
- Version controlled with your project
|
|
114
|
+
- Different projects can use different template versions
|
|
115
|
+
- Team members get the same templates
|
|
116
|
+
- No dependency on external registry at runtime
|
|
117
|
+
|
|
118
|
+
**Like:**
|
|
119
|
+
- `node_modules` - dependencies live with the project
|
|
120
|
+
- `.next` - build artifacts live with the project
|
|
121
|
+
|
|
122
|
+
### Local Outputs
|
|
123
|
+
|
|
124
|
+
**Benefits:**
|
|
125
|
+
- Generated assets stay with the project
|
|
126
|
+
- Easy to commit to git (if desired)
|
|
127
|
+
- No confusion about where files are
|
|
128
|
+
- Works well with build processes
|
|
129
|
+
|
|
130
|
+
## Template Registry
|
|
131
|
+
|
|
132
|
+
Templates live online (like npm registry):
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
https://design.unpeel.dev/r/banner-hero
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"name": "banner-hero",
|
|
143
|
+
"version": "1.0.0",
|
|
144
|
+
"description": "A hero banner",
|
|
145
|
+
"files": [
|
|
146
|
+
{
|
|
147
|
+
"path": "banner-hero.tsx",
|
|
148
|
+
"content": "..."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"path": "meta.json",
|
|
152
|
+
"content": "..."
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
When you run `dsgn add banner-hero`, it:
|
|
159
|
+
1. Fetches this JSON
|
|
160
|
+
2. Writes files to `dsgn/templates/banner-hero/`
|
|
161
|
+
3. Templates are now local and ready to use
|
|
162
|
+
|
|
163
|
+
## Git Workflow
|
|
164
|
+
|
|
165
|
+
### What to commit?
|
|
166
|
+
|
|
167
|
+
**DO commit:**
|
|
168
|
+
- `dsgn/templates/` - Your templates (like `node_modules` in some projects)
|
|
169
|
+
- `dsgn.json` - Your design configuration
|
|
170
|
+
|
|
171
|
+
**DON'T commit:**
|
|
172
|
+
- `dsgn/outputs/` - Generated files (usually)
|
|
173
|
+
|
|
174
|
+
Example `.gitignore`:
|
|
175
|
+
|
|
176
|
+
```gitignore
|
|
177
|
+
# Ignore generated outputs
|
|
178
|
+
dsgn/outputs/
|
|
179
|
+
|
|
180
|
+
# Keep templates (optional - depends on your workflow)
|
|
181
|
+
# dsgn/templates/
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Some teams prefer to commit templates (reproducibility), others prefer to install them (like npm packages).
|
|
185
|
+
|
|
186
|
+
## Comparison to Other Tools
|
|
187
|
+
|
|
188
|
+
### Like Shadcn
|
|
189
|
+
|
|
190
|
+
- Registry-based templates
|
|
191
|
+
- Install to your project
|
|
192
|
+
- You own the code
|
|
193
|
+
- Customize freely
|
|
194
|
+
|
|
195
|
+
### Like npm
|
|
196
|
+
|
|
197
|
+
- Global CLI tool
|
|
198
|
+
- Project-local dependencies (templates)
|
|
199
|
+
- Registry for discovery
|
|
200
|
+
- Semantic versioning
|
|
201
|
+
|
|
202
|
+
### Like Tailwind
|
|
203
|
+
|
|
204
|
+
- Config file for customization
|
|
205
|
+
- Design tokens approach
|
|
206
|
+
- Build-time generation
|
|
207
|
+
- Framework agnostic
|
|
208
|
+
|
|
209
|
+
## Common Workflows
|
|
210
|
+
|
|
211
|
+
### Starting a New Project
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
mkdir my-project
|
|
215
|
+
cd my-project
|
|
216
|
+
|
|
217
|
+
# Initialize config
|
|
218
|
+
dsgn init
|
|
219
|
+
|
|
220
|
+
# Install templates
|
|
221
|
+
dsgn add banner-hero
|
|
222
|
+
dsgn add product-card
|
|
223
|
+
|
|
224
|
+
# Render images
|
|
225
|
+
dsgn render banner-hero --props props.json
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Sharing with Team
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Developer 1
|
|
232
|
+
git add dsgn/templates/
|
|
233
|
+
git commit -m "Add banner template"
|
|
234
|
+
git push
|
|
235
|
+
|
|
236
|
+
# Developer 2
|
|
237
|
+
git pull
|
|
238
|
+
dsgn list # See all templates
|
|
239
|
+
dsgn render banner-hero --props '{"title":"Team Banner"}'
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### CI/CD Pipeline
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
# .github/workflows/generate-images.yml
|
|
246
|
+
- name: Install dsgn
|
|
247
|
+
run: npm install -g dsgn
|
|
248
|
+
|
|
249
|
+
- name: Generate images
|
|
250
|
+
run: |
|
|
251
|
+
dsgn render banner-hero --props props/hero.json
|
|
252
|
+
dsgn render product-card --props props/product.json
|
|
253
|
+
|
|
254
|
+
- name: Upload artifacts
|
|
255
|
+
uses: actions/upload-artifact@v3
|
|
256
|
+
with:
|
|
257
|
+
path: dsgn/outputs/
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Future Enhancements
|
|
261
|
+
|
|
262
|
+
### Template Versions
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
dsgn add banner-hero@2.0.0
|
|
266
|
+
dsgn update banner-hero
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Template Marketplace
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
dsgn search "hero"
|
|
273
|
+
dsgn add @company/custom-banner
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Global vs Local
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Install globally (like npm -g)
|
|
280
|
+
dsgn add banner-hero --global
|
|
281
|
+
|
|
282
|
+
# Install locally (default, like npm install)
|
|
283
|
+
dsgn add banner-hero
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This is the **Shadcn for design and marketing** - same philosophy of owning your code, but for design assets!
|