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
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Define a template programmatically for use in serverless environments
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const ogImage = defineTemplate({
7
+ * name: 'og-image',
8
+ * type: 'image',
9
+ * size: { width: 1200, height: 630 },
10
+ * render: ({ tw, title, description }) => (
11
+ * <div style={tw('flex flex-col w-full h-full bg-white p-12')}>
12
+ * <h1 style={tw('text-6xl font-bold')}>{title}</h1>
13
+ * <p style={tw('text-2xl text-gray-600')}>{description}</p>
14
+ * </div>
15
+ * )
16
+ * });
17
+ * ```
18
+ */
19
+ export function defineTemplate(definition) {
20
+ // Validate definition
21
+ if (!definition.name) {
22
+ throw new Error('Template definition must have a name');
23
+ }
24
+ if (!definition.size || !definition.size.width || !definition.size.height) {
25
+ throw new Error('Template definition must have a size with width and height');
26
+ }
27
+ if (!definition.render || typeof definition.render !== 'function') {
28
+ throw new Error('Template definition must have a render function');
29
+ }
30
+ // Set defaults
31
+ const type = definition.type || 'image';
32
+ if (type === 'video' && !definition.video) {
33
+ throw new Error('Video templates must have video metadata (fps, duration)');
34
+ }
35
+ return {
36
+ ...definition,
37
+ type,
38
+ };
39
+ }
40
+ /**
41
+ * Convert a template definition to template metadata
42
+ * @internal
43
+ */
44
+ export function templateToMeta(template) {
45
+ return {
46
+ name: template.name,
47
+ description: template.name, // Use name as description for SDK templates
48
+ type: template.type || 'image',
49
+ size: template.size,
50
+ video: template.video,
51
+ props: {}, // SDK templates don't need props metadata
52
+ fonts: template.fonts?.map(fontName => ({
53
+ name: fontName,
54
+ path: `fonts/${fontName}.woff`,
55
+ weight: 400,
56
+ style: 'normal',
57
+ })),
58
+ };
59
+ }
60
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/sdk/template.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAC5B,UAAsC;IAEtC,sBAAsB;IACtB,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,eAAe;IACf,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,IAAI,OAAO,CAAC;IAExC,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,GAAG,UAAU;QACb,IAAI;KACL,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAA4B;IACzD,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE,4CAA4C;QACxE,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,OAAO;QAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,KAAK,EAAE,EAAE,EAAE,0CAA0C;QACrD,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,SAAS,QAAQ,OAAO;YAC9B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,QAAiB;SACzB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,62 @@
1
+ export interface DesignConfig {
2
+ colors?: {
3
+ [key: string]: string | {
4
+ [shade: string]: string;
5
+ };
6
+ };
7
+ fonts?: {
8
+ sans?: string[] | {
9
+ family: string[];
10
+ files?: Array<{
11
+ path: string;
12
+ weight?: number;
13
+ style?: string;
14
+ }>;
15
+ };
16
+ serif?: string[] | {
17
+ family: string[];
18
+ files?: Array<{
19
+ path: string;
20
+ weight?: number;
21
+ style?: string;
22
+ }>;
23
+ };
24
+ mono?: string[] | {
25
+ family: string[];
26
+ files?: Array<{
27
+ path: string;
28
+ weight?: number;
29
+ style?: string;
30
+ }>;
31
+ };
32
+ [key: string]: string[] | {
33
+ family: string[];
34
+ files?: Array<{
35
+ path: string;
36
+ weight?: number;
37
+ style?: string;
38
+ }>;
39
+ } | undefined;
40
+ };
41
+ tokens?: {
42
+ spacing?: {
43
+ [key: string]: string;
44
+ };
45
+ borderRadius?: {
46
+ [key: string]: string;
47
+ };
48
+ [key: string]: any;
49
+ };
50
+ defaults?: {
51
+ width?: number;
52
+ height?: number;
53
+ [key: string]: any;
54
+ };
55
+ paths?: {
56
+ root?: string;
57
+ templates?: string;
58
+ outputs?: string;
59
+ };
60
+ }
61
+ export declare const DEFAULT_CONFIG: DesignConfig;
62
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAE3B,MAAM,CAAC,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG;YAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;KACrD,CAAC;IAGF,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG;YAChB,MAAM,EAAE,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;SAClE,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG;YACjB,MAAM,EAAE,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;SAClE,CAAC;QACF,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG;YAChB,MAAM,EAAE,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;SAClE,CAAC;QACF,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG;YAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAAC,KAAK,CAAC,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GAAG,SAAS,CAAC;KAC9H,CAAC;IAGF,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACpC,YAAY,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACzC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IAGF,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IAGF,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAGD,eAAO,MAAM,cAAc,EAAE,YAoD5B,CAAC"}
@@ -0,0 +1,47 @@
1
+ // shadcn/ui design system defaults (zinc theme)
2
+ export const DEFAULT_CONFIG = {
3
+ colors: {
4
+ // Primary colors
5
+ primary: '#18181b',
6
+ 'primary-foreground': '#fafafa',
7
+ // Secondary colors
8
+ secondary: '#f4f4f5',
9
+ 'secondary-foreground': '#18181b',
10
+ // Background colors
11
+ background: '#ffffff',
12
+ foreground: '#09090b',
13
+ // Muted colors
14
+ muted: '#f4f4f5',
15
+ 'muted-foreground': '#71717a',
16
+ // Accent colors
17
+ accent: '#f4f4f5',
18
+ 'accent-foreground': '#18181b',
19
+ // Destructive
20
+ destructive: '#ef4444',
21
+ 'destructive-foreground': '#fafafa',
22
+ // Border and input
23
+ border: '#e4e4e7',
24
+ input: '#e4e4e7',
25
+ ring: '#18181b',
26
+ // Card
27
+ card: '#ffffff',
28
+ 'card-foreground': '#09090b',
29
+ // Popover
30
+ popover: '#ffffff',
31
+ 'popover-foreground': '#09090b',
32
+ },
33
+ fonts: {
34
+ sans: ['Noto Sans', 'system-ui', '-apple-system', 'sans-serif'],
35
+ serif: ['Georgia', 'serif'],
36
+ mono: ['Courier New', 'monospace'],
37
+ },
38
+ tokens: {
39
+ borderRadius: {
40
+ sm: '0.25rem',
41
+ md: '0.375rem',
42
+ lg: '0.5rem',
43
+ xl: '0.75rem',
44
+ },
45
+ },
46
+ };
47
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AA6CA,gDAAgD;AAChD,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,MAAM,EAAE;QACN,iBAAiB;QACjB,OAAO,EAAE,SAAS;QAClB,oBAAoB,EAAE,SAAS;QAE/B,mBAAmB;QACnB,SAAS,EAAE,SAAS;QACpB,sBAAsB,EAAE,SAAS;QAEjC,oBAAoB;QACpB,UAAU,EAAE,SAAS;QACrB,UAAU,EAAE,SAAS;QAErB,eAAe;QACf,KAAK,EAAE,SAAS;QAChB,kBAAkB,EAAE,SAAS;QAE7B,gBAAgB;QAChB,MAAM,EAAE,SAAS;QACjB,mBAAmB,EAAE,SAAS;QAE9B,cAAc;QACd,WAAW,EAAE,SAAS;QACtB,wBAAwB,EAAE,SAAS;QAEnC,mBAAmB;QACnB,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;QAEf,OAAO;QACP,IAAI,EAAE,SAAS;QACf,iBAAiB,EAAE,SAAS;QAE5B,UAAU;QACV,OAAO,EAAE,SAAS;QAClB,oBAAoB,EAAE,SAAS;KAChC;IACD,KAAK,EAAE;QACL,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,CAAC;QAC/D,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;QAC3B,IAAI,EAAE,CAAC,aAAa,EAAE,WAAW,CAAC;KACnC;IACD,MAAM,EAAE;QACN,YAAY,EAAE;YACZ,EAAE,EAAE,SAAS;YACb,EAAE,EAAE,UAAU;YACd,EAAE,EAAE,QAAQ;YACZ,EAAE,EAAE,SAAS;SACd;KACF;CACF,CAAC"}
@@ -0,0 +1,79 @@
1
+ import type { DesignConfig } from './config.js';
2
+ export type TemplateType = "image" | "video" | "presentation" | "website";
3
+ export interface TemplateMeta {
4
+ name: string;
5
+ description: string;
6
+ type?: TemplateType;
7
+ size: {
8
+ width: number;
9
+ height: number;
10
+ scale?: number;
11
+ };
12
+ props: Record<string, string>;
13
+ fonts?: Array<{
14
+ name: string;
15
+ path: string;
16
+ weight: number;
17
+ style: "normal" | "italic";
18
+ }>;
19
+ templates?: string[] | Record<string, {
20
+ name: string;
21
+ size?: {
22
+ width: number;
23
+ height: number;
24
+ };
25
+ scale?: number;
26
+ }>;
27
+ video?: {
28
+ fps: number;
29
+ duration: number;
30
+ };
31
+ presentation?: {
32
+ slides: Array<{
33
+ name: string;
34
+ size?: {
35
+ width: number;
36
+ height: number;
37
+ };
38
+ }>;
39
+ transition?: "fade" | "slide" | "none";
40
+ };
41
+ website?: {
42
+ pages: Array<{
43
+ route: string;
44
+ component: string;
45
+ }>;
46
+ output?: "static" | "spa";
47
+ };
48
+ }
49
+ export interface TemplateProps {
50
+ [key: string]: any;
51
+ frame?: number;
52
+ progress?: number;
53
+ config?: DesignConfig;
54
+ tw?: (classes: string) => any;
55
+ qr?: (text: string, options?: {
56
+ width?: number;
57
+ margin?: number;
58
+ errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
59
+ color?: {
60
+ dark?: string;
61
+ light?: string;
62
+ };
63
+ }) => string;
64
+ template?: (name: string, props?: Record<string, any>) => string;
65
+ }
66
+ export interface Template {
67
+ meta: TemplateMeta;
68
+ default: (props: TemplateProps) => JSX.Element;
69
+ }
70
+ export interface RegistryTemplate {
71
+ name: string;
72
+ version: string;
73
+ description: string;
74
+ files: Array<{
75
+ path: string;
76
+ content: string;
77
+ }>;
78
+ }
79
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/types/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/types/template.ts"],"names":[],"mappings":""}
@@ -0,0 +1,180 @@
1
+ # dsgn Next.js API Example
2
+
3
+ This example demonstrates how to use the **dsgn SDK** in Next.js API routes to generate images and videos programmatically.
4
+
5
+ ## Features
6
+
7
+ - ✅ Serverless image generation (OG images, social cards)
8
+ - ✅ Serverless video generation (intro videos, animations)
9
+ - ✅ No file system dependencies - templates defined in code
10
+ - ✅ Works on Vercel, Netlify, and other serverless platforms
11
+ - ✅ Edge Runtime compatible
12
+
13
+ ## Setup
14
+
15
+ 1. Install dependencies:
16
+ ```bash
17
+ npm install
18
+ ```
19
+
20
+ 2. Run the development server:
21
+ ```bash
22
+ npm run dev
23
+ ```
24
+
25
+ 3. Test the API routes:
26
+ - Image: `http://localhost:3000/api/og-image?title=Hello&description=World`
27
+ - Video: `http://localhost:3000/api/intro-video?title=Welcome`
28
+
29
+ ## API Routes
30
+
31
+ ### `/api/og-image` - Generate OG Images
32
+
33
+ Generate Open Graph images dynamically:
34
+
35
+ ```typescript
36
+ import { defineTemplate, renderImage } from 'dsgn/sdk';
37
+
38
+ const ogTemplate = defineTemplate({
39
+ name: 'og-image',
40
+ size: { width: 1200, height: 630 },
41
+ render: ({ tw, title, description }) => (
42
+ <div style={tw('flex flex-col w-full h-full bg-gradient-to-br from-blue-600 to-purple-700 p-12')}>
43
+ <h1 style={tw('text-6xl font-bold text-white')}>{title}</h1>
44
+ <p style={tw('text-2xl text-white/80')}>{description}</p>
45
+ </div>
46
+ ),
47
+ });
48
+
49
+ export default async function handler(req, res) {
50
+ const png = await renderImage(ogTemplate, {
51
+ title: req.query.title,
52
+ description: req.query.description,
53
+ });
54
+
55
+ res.setHeader('Content-Type', 'image/png');
56
+ res.send(png);
57
+ }
58
+ ```
59
+
60
+ **Usage:**
61
+ ```bash
62
+ curl http://localhost:3000/api/og-image?title=Hello&description=World > image.png
63
+ ```
64
+
65
+ ### `/api/intro-video` - Generate Videos
66
+
67
+ Generate MP4 videos dynamically:
68
+
69
+ ```typescript
70
+ import { defineTemplate, renderVideo } from 'dsgn/sdk';
71
+
72
+ const introTemplate = defineTemplate({
73
+ name: 'intro-video',
74
+ type: 'video',
75
+ size: { width: 1920, height: 1080 },
76
+ video: { fps: 30, duration: 3 },
77
+ render: ({ tw, progress, title }) => (
78
+ <div style={tw('flex items-center justify-center w-full h-full bg-black')}>
79
+ <h1 style={{ ...tw('text-8xl font-bold text-white'), opacity: progress }}>
80
+ {title}
81
+ </h1>
82
+ </div>
83
+ ),
84
+ });
85
+
86
+ export default async function handler(req, res) {
87
+ const mp4 = await renderVideo(introTemplate, {
88
+ title: req.query.title,
89
+ });
90
+
91
+ res.setHeader('Content-Type', 'video/mp4');
92
+ res.send(mp4);
93
+ }
94
+ ```
95
+
96
+ **Usage:**
97
+ ```bash
98
+ curl http://localhost:3000/api/intro-video?title=Welcome > video.mp4
99
+ ```
100
+
101
+ ## Deploy to Vercel
102
+
103
+ [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/tomtev/dsgn/tree/main/examples/nextjs-api)
104
+
105
+ ```bash
106
+ npm install -g vercel
107
+ vercel
108
+ ```
109
+
110
+ ## Key Concepts
111
+
112
+ ### 1. **Define Templates Programmatically**
113
+
114
+ No file system needed - define templates directly in code:
115
+
116
+ ```typescript
117
+ const template = defineTemplate({
118
+ name: 'my-template',
119
+ size: { width: 1200, height: 630 },
120
+ render: ({ tw, title }) => (
121
+ <div style={tw('flex items-center justify-center w-full h-full bg-white')}>
122
+ <h1 style={tw('text-4xl font-bold')}>{title}</h1>
123
+ </div>
124
+ ),
125
+ });
126
+ ```
127
+
128
+ ### 2. **Render to Buffer**
129
+
130
+ Get image/video as Buffer for maximum flexibility:
131
+
132
+ ```typescript
133
+ const png = await renderImage(template, { title: 'Hello' });
134
+ const mp4 = await renderVideo(videoTemplate, { title: 'Intro' });
135
+
136
+ // Can save to file, return in API, upload to S3, etc.
137
+ ```
138
+
139
+ ### 3. **Tailwind Styling**
140
+
141
+ Use Tailwind utility classes with the `tw` helper:
142
+
143
+ ```typescript
144
+ render: ({ tw, title }) => (
145
+ <div style={tw('flex flex-col gap-4 p-8 bg-gradient-to-br from-blue-600 to-purple-700')}>
146
+ <h1 style={tw('text-6xl font-bold text-white')}>{title}</h1>
147
+ </div>
148
+ )
149
+ ```
150
+
151
+ ### 4. **Video Animations**
152
+
153
+ Use `progress` and `frame` props for animations:
154
+
155
+ ```typescript
156
+ render: ({ tw, progress, title }) => {
157
+ const opacity = progress; // 0 to 1
158
+ const scale = 0.5 + progress * 0.5; // 0.5 to 1
159
+
160
+ return (
161
+ <div style={tw('flex items-center justify-center w-full h-full')}>
162
+ <h1 style={{ ...tw('text-8xl font-bold'), opacity, transform: `scale(${scale})` }}>
163
+ {title}
164
+ </h1>
165
+ </div>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ## Performance
171
+
172
+ - **Images**: ~50-100ms per image (PNG/JPEG/WebP)
173
+ - **Videos**: ~7s for 3-second Full HD video (1920×1080 @ 30fps)
174
+ - **Edge Runtime**: Compatible with Vercel Edge Functions for global distribution
175
+
176
+ ## Learn More
177
+
178
+ - [dsgn Documentation](https://dsgncli.com)
179
+ - [Next.js API Routes](https://nextjs.org/docs/api-routes/introduction)
180
+ - [Vercel Deployment](https://vercel.com/docs)
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "loopwind-nextjs-example",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start"
9
+ },
10
+ "dependencies": {
11
+ "loopwind": "latest",
12
+ "next": "^14.0.0",
13
+ "react": "^18.2.0",
14
+ "react-dom": "^18.2.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^20.0.0",
18
+ "@types/react": "^18.2.0",
19
+ "typescript": "^5.0.0"
20
+ }
21
+ }
@@ -0,0 +1,53 @@
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
+ import { defineTemplate, renderVideo } from 'dsgn/sdk';
3
+
4
+ // Define video template programmatically
5
+ const introTemplate = defineTemplate({
6
+ name: 'intro-video',
7
+ type: 'video',
8
+ size: { width: 1920, height: 1080 },
9
+ video: { fps: 30, duration: 3 },
10
+ render: ({ tw, progress, title }) => {
11
+ // Fade in animation
12
+ const opacity = progress < 0.5 ? progress / 0.5 : 1;
13
+
14
+ return (
15
+ <div
16
+ style={tw(
17
+ 'flex items-center justify-center w-full h-full bg-gradient-to-br from-black to-gray-900'
18
+ )}
19
+ >
20
+ <h1
21
+ style={{
22
+ ...tw('text-8xl font-bold text-white'),
23
+ opacity,
24
+ }}
25
+ >
26
+ {title}
27
+ </h1>
28
+ </div>
29
+ );
30
+ },
31
+ });
32
+
33
+ export default async function handler(
34
+ req: NextApiRequest,
35
+ res: NextApiResponse
36
+ ) {
37
+ const { title = 'Welcome!' } = req.query;
38
+
39
+ try {
40
+ // Render video as MP4 buffer
41
+ const mp4 = await renderVideo(introTemplate, {
42
+ title: String(title),
43
+ });
44
+
45
+ // Return video
46
+ res.setHeader('Content-Type', 'video/mp4');
47
+ res.setHeader('Cache-Control', 's-maxage=3600');
48
+ res.send(mp4);
49
+ } catch (error) {
50
+ console.error('Error rendering video:', error);
51
+ res.status(500).json({ error: 'Failed to render video' });
52
+ }
53
+ }
@@ -0,0 +1,50 @@
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
+ import { defineTemplate, renderImage } from 'dsgn/sdk';
3
+
4
+ // Define template programmatically
5
+ const ogTemplate = defineTemplate({
6
+ name: 'og-image',
7
+ type: 'image',
8
+ size: { width: 1200, height: 630 },
9
+ render: ({ tw, title, description }) => (
10
+ <div
11
+ style={tw(
12
+ 'flex flex-col w-full h-full bg-gradient-to-br from-blue-600 to-purple-700 p-12 justify-between'
13
+ )}
14
+ >
15
+ <div style={tw('flex items-center gap-4')}>
16
+ <div style={tw('w-12 h-12 rounded-full bg-white/20')} />
17
+ <span style={tw('text-white/80 text-2xl')}>yoursite.com</span>
18
+ </div>
19
+
20
+ <div>
21
+ <h1 style={tw('text-6xl font-bold text-white mb-4')}>{title}</h1>
22
+ <p style={tw('text-2xl text-white/80')}>{description}</p>
23
+ </div>
24
+ </div>
25
+ ),
26
+ });
27
+
28
+ export default async function handler(
29
+ req: NextApiRequest,
30
+ res: NextApiResponse
31
+ ) {
32
+ const { title = 'Welcome', description = 'Generated with dsgn SDK' } =
33
+ req.query;
34
+
35
+ try {
36
+ // Render image as PNG buffer
37
+ const png = await renderImage(ogTemplate, {
38
+ title: String(title),
39
+ description: String(description),
40
+ });
41
+
42
+ // Return image
43
+ res.setHeader('Content-Type', 'image/png');
44
+ res.setHeader('Cache-Control', 's-maxage=86400, stale-while-revalidate');
45
+ res.send(png);
46
+ } catch (error) {
47
+ console.error('Error rendering OG image:', error);
48
+ res.status(500).json({ error: 'Failed to render image' });
49
+ }
50
+ }
package/netlify.toml ADDED
@@ -0,0 +1,13 @@
1
+ [build]
2
+ base = "website"
3
+ command = "npm run build"
4
+ publish = "dist"
5
+
6
+ [build.environment]
7
+ NODE_VERSION = "18"
8
+
9
+ [[redirects]]
10
+ from = "/*"
11
+ to = "/index.html"
12
+ status = 200
13
+
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "loopwind",
3
+ "version": "0.9.1",
4
+ "description": "A CLI tool for AI code agents and developers for generating images and videos.",
5
+ "type": "module",
6
+ "bin": {
7
+ "loopwind": "./dist/cli.js",
8
+ "lw": "./dist/cli.js"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/cli.d.ts",
13
+ "default": "./dist/cli.js"
14
+ },
15
+ "./sdk": {
16
+ "types": "./dist/sdk/index.d.ts",
17
+ "default": "./dist/sdk/index.js"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsc && npm run copy-templates",
22
+ "copy-templates": "cp -r src/default-templates dist/",
23
+ "dev": "tsc --watch",
24
+ "prepublishOnly": "npm run build",
25
+ "postinstall": "patch-package"
26
+ },
27
+ "keywords": [
28
+ "design",
29
+ "cli",
30
+ "templates",
31
+ "satori",
32
+ "tailwind",
33
+ "image-generation",
34
+ "og-image",
35
+ "social-media",
36
+ "marketing"
37
+ ],
38
+ "author": "Tommy Vedvik",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/tomtev/loopwind.git"
43
+ },
44
+ "homepage": "https://loopwind.dev",
45
+ "bugs": {
46
+ "url": "https://github.com/tomtev/loopwind/issues"
47
+ },
48
+ "dependencies": {
49
+ "@resvg/resvg-js": "^2.6.0",
50
+ "boxen": "^7.1.1",
51
+ "chalk": "^5.3.0",
52
+ "chalk-animation": "^2.0.3",
53
+ "chokidar": "^4.0.3",
54
+ "clsx": "^2.1.1",
55
+ "commander": "^12.0.0",
56
+ "esbuild": "^0.27.0",
57
+ "express": "^5.1.0",
58
+ "gradient-string": "^3.0.0",
59
+ "h264-mp4-encoder": "^1.0.12",
60
+ "mediabunny": "^1.25.0",
61
+ "open": "^11.0.0",
62
+ "ora": "^8.0.1",
63
+ "pngjs": "^7.0.0",
64
+ "qrcode": "^1.5.4",
65
+ "react": "^18.2.0",
66
+ "satori": "^0.18.3",
67
+ "sharp": "^0.34.5",
68
+ "tailwind-merge": "^3.4.0",
69
+ "tailwindcss": "^3.4.1"
70
+ },
71
+ "devDependencies": {
72
+ "@types/chalk-animation": "^1.6.3",
73
+ "@types/express": "^5.0.5",
74
+ "@types/gradient-string": "^1.1.6",
75
+ "@types/node": "^20.11.0",
76
+ "@types/qrcode": "^1.5.6",
77
+ "@types/react": "^18.2.48",
78
+ "patch-package": "^8.0.1",
79
+ "typescript": "^5.3.3"
80
+ },
81
+ "engines": {
82
+ "node": ">=18.0.0"
83
+ }
84
+ }