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.
Files changed (245) hide show
  1. package/FONTS.md +156 -0
  2. package/HELPERS_DEMO.md +134 -0
  3. package/PROJECT_STRUCTURE.md +286 -0
  4. package/PUBLISHING.md +171 -0
  5. package/README.md +1020 -0
  6. package/REGISTRY_SETUP.md +427 -0
  7. package/SHADCN_INTEGRATION.md +269 -0
  8. package/TAILWIND.md +228 -0
  9. package/TEMPLATE_SOURCES.md +363 -0
  10. package/_dsgn/templates/banner-hero/banner-hero.tsx +57 -0
  11. package/_dsgn/templates/banner-hero/meta.json +14 -0
  12. package/_dsgn/templates/composite-card/meta.json +16 -0
  13. package/_dsgn/templates/composite-card/template.tsx +44 -0
  14. package/_dsgn/templates/image/meta.json +13 -0
  15. package/_dsgn/templates/image/template.tsx +28 -0
  16. package/_dsgn/templates/kitchen-sink/meta.json +13 -0
  17. package/_dsgn/templates/kitchen-sink/template.tsx +72 -0
  18. package/_dsgn/templates/qr-card/meta.json +14 -0
  19. package/_dsgn/templates/qr-card/template.tsx +39 -0
  20. package/_dsgn/templates/test-parent/child/meta.json +11 -0
  21. package/_dsgn/templates/test-parent/child/template.tsx +27 -0
  22. package/_dsgn/templates/test-parent/meta.json +12 -0
  23. package/_dsgn/templates/test-parent/template.tsx +30 -0
  24. package/_dsgn/templates/test-sibling/meta.json +11 -0
  25. package/_dsgn/templates/test-sibling/template.tsx +20 -0
  26. package/_dsgn/templates/video/.tmp/template-1763421345296.mjs +43 -0
  27. package/_dsgn/templates/video/.tmp/template-1763421362228.mjs +43 -0
  28. package/_dsgn/templates/video/.tmp/template-1763421377706.mjs +43 -0
  29. package/_dsgn/templates/video/meta.json +17 -0
  30. package/_dsgn/templates/video/template.tsx +48 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +70 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/commands/add.d.ts +6 -0
  36. package/dist/commands/add.d.ts.map +1 -0
  37. package/dist/commands/add.js +86 -0
  38. package/dist/commands/add.js.map +1 -0
  39. package/dist/commands/default.d.ts +2 -0
  40. package/dist/commands/default.d.ts.map +1 -0
  41. package/dist/commands/default.js +69 -0
  42. package/dist/commands/default.js.map +1 -0
  43. package/dist/commands/init.d.ts +2 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +75 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/list.d.ts +2 -0
  48. package/dist/commands/list.d.ts.map +1 -0
  49. package/dist/commands/list.js +83 -0
  50. package/dist/commands/list.js.map +1 -0
  51. package/dist/commands/preview.d.ts +3 -0
  52. package/dist/commands/preview.d.ts.map +1 -0
  53. package/dist/commands/preview.js +296 -0
  54. package/dist/commands/preview.js.map +1 -0
  55. package/dist/commands/render.d.ts +10 -0
  56. package/dist/commands/render.d.ts.map +1 -0
  57. package/dist/commands/render.js +204 -0
  58. package/dist/commands/render.js.map +1 -0
  59. package/dist/commands/validate.d.ts +2 -0
  60. package/dist/commands/validate.d.ts.map +1 -0
  61. package/dist/commands/validate.js +107 -0
  62. package/dist/commands/validate.js.map +1 -0
  63. package/dist/default-templates/AGENTS.md +229 -0
  64. package/dist/default-templates/image/meta.json +13 -0
  65. package/dist/default-templates/image/template.d.ts +20 -0
  66. package/dist/default-templates/image/template.d.ts.map +1 -0
  67. package/dist/default-templates/image/template.js +18 -0
  68. package/dist/default-templates/image/template.js.map +1 -0
  69. package/dist/default-templates/image/template.tsx +20 -0
  70. package/dist/default-templates/image-template/meta.json +13 -0
  71. package/dist/default-templates/image-template/template.tsx +19 -0
  72. package/dist/default-templates/kitchen-sink/meta.json +13 -0
  73. package/dist/default-templates/kitchen-sink/template.tsx +64 -0
  74. package/dist/default-templates/page/meta.json +17 -0
  75. package/dist/default-templates/page/template.tsx +37 -0
  76. package/dist/default-templates/video/meta.json +17 -0
  77. package/dist/default-templates/video/template.d.ts +26 -0
  78. package/dist/default-templates/video/template.d.ts.map +1 -0
  79. package/dist/default-templates/video/template.js +33 -0
  80. package/dist/default-templates/video/template.js.map +1 -0
  81. package/dist/default-templates/video/template.tsx +37 -0
  82. package/dist/default-templates/video-template/meta.json +17 -0
  83. package/dist/default-templates/video-template/template.tsx +36 -0
  84. package/dist/default-templates/website/meta.json +16 -0
  85. package/dist/default-templates/website/pages/home.tsx +17 -0
  86. package/dist/default-templates/website/parts/footer.tsx +17 -0
  87. package/dist/default-templates/website/parts/header.tsx +17 -0
  88. package/dist/default-templates/website/template.tsx +17 -0
  89. package/dist/default-templates/website-template/meta.json +16 -0
  90. package/dist/default-templates/website-template/pages/home.tsx +16 -0
  91. package/dist/default-templates/website-template/parts/footer.tsx +16 -0
  92. package/dist/default-templates/website-template/parts/header.tsx +16 -0
  93. package/dist/default-templates/website-template/template.tsx +16 -0
  94. package/dist/lib/config.d.ts +34 -0
  95. package/dist/lib/config.d.ts.map +1 -0
  96. package/dist/lib/config.js +248 -0
  97. package/dist/lib/config.js.map +1 -0
  98. package/dist/lib/constants.d.ts +7 -0
  99. package/dist/lib/constants.d.ts.map +1 -0
  100. package/dist/lib/constants.js +12 -0
  101. package/dist/lib/constants.js.map +1 -0
  102. package/dist/lib/helpers.d.ts +29 -0
  103. package/dist/lib/helpers.d.ts.map +1 -0
  104. package/dist/lib/helpers.js +159 -0
  105. package/dist/lib/helpers.js.map +1 -0
  106. package/dist/lib/installer.d.ts +51 -0
  107. package/dist/lib/installer.d.ts.map +1 -0
  108. package/dist/lib/installer.js +215 -0
  109. package/dist/lib/installer.js.map +1 -0
  110. package/dist/lib/renderer.d.ts +51 -0
  111. package/dist/lib/renderer.d.ts.map +1 -0
  112. package/dist/lib/renderer.js +524 -0
  113. package/dist/lib/renderer.js.map +1 -0
  114. package/dist/lib/tailwind-config-loader.d.ts +47 -0
  115. package/dist/lib/tailwind-config-loader.d.ts.map +1 -0
  116. package/dist/lib/tailwind-config-loader.js +432 -0
  117. package/dist/lib/tailwind-config-loader.js.map +1 -0
  118. package/dist/lib/tailwind-detector.d.ts +36 -0
  119. package/dist/lib/tailwind-detector.d.ts.map +1 -0
  120. package/dist/lib/tailwind-detector.js +156 -0
  121. package/dist/lib/tailwind-detector.js.map +1 -0
  122. package/dist/lib/tailwind.d.ts +8 -0
  123. package/dist/lib/tailwind.d.ts.map +1 -0
  124. package/dist/lib/tailwind.js +994 -0
  125. package/dist/lib/tailwind.js.map +1 -0
  126. package/dist/lib/template-validator.d.ts +22 -0
  127. package/dist/lib/template-validator.d.ts.map +1 -0
  128. package/dist/lib/template-validator.js +174 -0
  129. package/dist/lib/template-validator.js.map +1 -0
  130. package/dist/lib/utils.d.ts +44 -0
  131. package/dist/lib/utils.d.ts.map +1 -0
  132. package/dist/lib/utils.js +207 -0
  133. package/dist/lib/utils.js.map +1 -0
  134. package/dist/lib/version-check.d.ts +16 -0
  135. package/dist/lib/version-check.d.ts.map +1 -0
  136. package/dist/lib/version-check.js +88 -0
  137. package/dist/lib/version-check.js.map +1 -0
  138. package/dist/lib/video-renderer.d.ts +32 -0
  139. package/dist/lib/video-renderer.d.ts.map +1 -0
  140. package/dist/lib/video-renderer.js +226 -0
  141. package/dist/lib/video-renderer.js.map +1 -0
  142. package/dist/sdk/index.d.ts +58 -0
  143. package/dist/sdk/index.d.ts.map +1 -0
  144. package/dist/sdk/index.js +119 -0
  145. package/dist/sdk/index.js.map +1 -0
  146. package/dist/sdk/template.d.ts +40 -0
  147. package/dist/sdk/template.d.ts.map +1 -0
  148. package/dist/sdk/template.js +60 -0
  149. package/dist/sdk/template.js.map +1 -0
  150. package/dist/types/config.d.ts +62 -0
  151. package/dist/types/config.d.ts.map +1 -0
  152. package/dist/types/config.js +47 -0
  153. package/dist/types/config.js.map +1 -0
  154. package/dist/types/template.d.ts +79 -0
  155. package/dist/types/template.d.ts.map +1 -0
  156. package/dist/types/template.js +2 -0
  157. package/dist/types/template.js.map +1 -0
  158. package/examples/nextjs-api/README.md +180 -0
  159. package/examples/nextjs-api/package.json +21 -0
  160. package/examples/nextjs-api/pages/api/intro-video.ts +53 -0
  161. package/examples/nextjs-api/pages/api/og-image.ts +50 -0
  162. package/netlify.toml +13 -0
  163. package/package.json +84 -0
  164. package/patches/satori+0.18.3.patch +13 -0
  165. package/test-templates/TESTS.md +63 -0
  166. package/test-templates/_dsgn/templates/absolute-spin/meta.json +7 -0
  167. package/test-templates/_dsgn/templates/absolute-spin/template.tsx +16 -0
  168. package/test-templates/_dsgn/templates/animated-intro/.tmp/template-1763468771640.mjs +7 -0
  169. package/test-templates/_dsgn/templates/animated-intro/meta.json +10 -0
  170. package/test-templates/_dsgn/templates/animated-intro/template.tsx +23 -0
  171. package/test-templates/_dsgn/templates/centered-spin/.tmp/template-1763468525386.mjs +7 -0
  172. package/test-templates/_dsgn/templates/centered-spin/meta.json +7 -0
  173. package/test-templates/_dsgn/templates/centered-spin/template.tsx +11 -0
  174. package/test-templates/_dsgn/templates/composite/.tmp/template-1763468815645.mjs +7 -0
  175. package/test-templates/_dsgn/templates/composite/meta.json +9 -0
  176. package/test-templates/_dsgn/templates/composite/template.tsx +23 -0
  177. package/test-templates/_dsgn/templates/easing-test/.tmp/template-1763468824501.mjs +7 -0
  178. package/test-templates/_dsgn/templates/easing-test/meta.json +7 -0
  179. package/test-templates/_dsgn/templates/easing-test/template.tsx +47 -0
  180. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466364336.mjs +10 -0
  181. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466584319.mjs +10 -0
  182. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466667797.mjs +10 -0
  183. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466746504.mjs +10 -0
  184. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466930225.mjs +10 -0
  185. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467004552.mjs +10 -0
  186. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467060334.mjs +10 -0
  187. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467124493.mjs +10 -0
  188. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467174690.mjs +10 -0
  189. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467359134.mjs +10 -0
  190. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467451928.mjs +10 -0
  191. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467758275.mjs +10 -0
  192. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467985201.mjs +10 -0
  193. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468020563.mjs +10 -0
  194. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468090428.mjs +10 -0
  195. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468211036.mjs +10 -0
  196. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468394057.mjs +10 -0
  197. package/test-templates/_dsgn/templates/minimal-spin/meta.json +7 -0
  198. package/test-templates/_dsgn/templates/minimal-spin/template.tsx +13 -0
  199. package/test-templates/_dsgn/templates/no-origin-spin/meta.json +7 -0
  200. package/test-templates/_dsgn/templates/no-origin-spin/template.tsx +10 -0
  201. package/test-templates/_dsgn/templates/opacity-test/meta.json +7 -0
  202. package/test-templates/_dsgn/templates/opacity-test/template.tsx +9 -0
  203. package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468758954.mjs +17 -0
  204. package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468815672.mjs +17 -0
  205. package/test-templates/_dsgn/templates/qr-code/meta.json +9 -0
  206. package/test-templates/_dsgn/templates/qr-code/template.tsx +20 -0
  207. package/test-templates/_dsgn/templates/rotation-abs-test/meta.json +7 -0
  208. package/test-templates/_dsgn/templates/rotation-abs-test/template.tsx +15 -0
  209. package/test-templates/_dsgn/templates/rotation-corner/meta.json +7 -0
  210. package/test-templates/_dsgn/templates/rotation-corner/template.tsx +12 -0
  211. package/test-templates/_dsgn/templates/rotation-test/meta.json +7 -0
  212. package/test-templates/_dsgn/templates/rotation-test/template.tsx +12 -0
  213. package/test-templates/_dsgn/templates/shake-test/meta.json +7 -0
  214. package/test-templates/_dsgn/templates/shake-test/template.tsx +12 -0
  215. package/test-templates/_dsgn/templates/static-image/.tmp/template-1763468746271.mjs +7 -0
  216. package/test-templates/_dsgn/templates/static-image/meta.json +9 -0
  217. package/test-templates/_dsgn/templates/static-image/template.tsx +19 -0
  218. package/test-templates/_dsgn/templates/translate-test/meta.json +7 -0
  219. package/test-templates/_dsgn/templates/translate-test/template.tsx +9 -0
  220. package/test-templates/_dsgn/templates/video-loops/.tmp/template-1763468793192.mjs +15 -0
  221. package/test-templates/_dsgn/templates/video-loops/meta.json +9 -0
  222. package/test-templates/_dsgn/templates/video-loops/template.tsx +39 -0
  223. package/test-templates/_dsgn/templates/wrapped-spin/meta.json +7 -0
  224. package/test-templates/_dsgn/templates/wrapped-spin/template.tsx +17 -0
  225. package/test-templates/compare-svgs.mjs +30 -0
  226. package/test-templates/convert-frames.mjs +15 -0
  227. package/test-templates/debug-rotation.mjs +25 -0
  228. package/test-templates/run-tests.sh +39 -0
  229. package/test-templates/test-sdk.mjs +115 -0
  230. package/website/.astro/settings.json +5 -0
  231. package/website/.astro/types.d.ts +1 -0
  232. package/website/README.md +112 -0
  233. package/website/astro.config.mjs +18 -0
  234. package/website/dist/_astro/fonts.DHdiHGBO.css +1 -0
  235. package/website/dist/fonts/index.html +193 -0
  236. package/website/dist/helpers/index.html +166 -0
  237. package/website/dist/images/index.html +314 -0
  238. package/website/dist/index.html +219 -0
  239. package/website/dist/llm.txt +2448 -0
  240. package/website/dist/styling/index.html +365 -0
  241. package/website/dist/templates/index.html +124 -0
  242. package/website/dist/video/index.html +636 -0
  243. package/website/package-lock.json +7606 -0
  244. package/website/package.json +23 -0
  245. 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
@@ -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!