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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
export const meta = {
|
|
3
|
+
name: "image",
|
|
4
|
+
description: "Simple image starter template",
|
|
5
|
+
type: "image",
|
|
6
|
+
size: { width: 1200, height: 630 },
|
|
7
|
+
props: {
|
|
8
|
+
title: "string",
|
|
9
|
+
description: "string?"
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default function Template({ title, description, tw }) {
|
|
14
|
+
return (
|
|
15
|
+
<div style={tw('w-full h-full flex flex-col justify-center items-center bg-gradient-to-br from-gray-900 to-gray-950 p-16')}>
|
|
16
|
+
<div style={tw('bg-white border rounded-xl p-12 flex flex-col max-w-4xl')}>
|
|
17
|
+
<h1 style={tw('text-7xl font-bold text-gray-900 mb-4')}>
|
|
18
|
+
{title}
|
|
19
|
+
</h1>
|
|
20
|
+
{description && (
|
|
21
|
+
<p style={tw('text-3xl text-gray-600')}>
|
|
22
|
+
{description}
|
|
23
|
+
</p>
|
|
24
|
+
)}
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
export const meta = {
|
|
3
|
+
name: "kitchen-sink",
|
|
4
|
+
description: "Comprehensive example showcasing all supported Tailwind features",
|
|
5
|
+
type: "image",
|
|
6
|
+
size: { width: 1200, height: 630 },
|
|
7
|
+
props: {
|
|
8
|
+
title: "string",
|
|
9
|
+
subtitle: "string?"
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default function Template({ title, subtitle, tw }) {
|
|
14
|
+
return (
|
|
15
|
+
<div style={tw('w-full h-full flex flex-col bg-gradient-to-br from-indigo-500 via-purple-500 to-pink-500 p-8')}>
|
|
16
|
+
{/* Header Card with Shadow */}
|
|
17
|
+
<div style={tw('bg-white rounded-2xl shadow-2xl p-8 mb-4 max-w-5xl flex flex-col')}>
|
|
18
|
+
<h1 style={tw('text-6xl font-extrabold text-indigo-600 mb-3 uppercase tracking-wide')}>
|
|
19
|
+
{title}
|
|
20
|
+
</h1>
|
|
21
|
+
{subtitle && (
|
|
22
|
+
<p style={tw('text-2xl text-gray-600 italic leading-relaxed')}>
|
|
23
|
+
{subtitle}
|
|
24
|
+
</p>
|
|
25
|
+
)}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
{/* Feature Cards Grid */}
|
|
29
|
+
<div style={tw('flex flex-wrap gap-4 max-w-6xl flex-1')}>
|
|
30
|
+
{/* Card 1: Gradients & Shadows */}
|
|
31
|
+
<div style={tw('bg-gradient-to-br from-cyan-400 to-blue-500 rounded-xl shadow-lg p-6 flex-1 min-w-0 flex flex-col')}>
|
|
32
|
+
<h2 style={tw('text-2xl font-bold text-white mb-2 tracking-wider')}>
|
|
33
|
+
Gradients
|
|
34
|
+
</h2>
|
|
35
|
+
<p style={tw('text-sm text-white text-opacity-90 leading-normal')}>
|
|
36
|
+
Full gradient support
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{/* Card 2: Borders & Transforms */}
|
|
41
|
+
<div style={tw('bg-white rounded-lg border-4 border-emerald-500 p-6 flex-1 min-w-0 flex flex-col shadow-md rotate-1')}>
|
|
42
|
+
<h2 style={tw('text-2xl font-semibold text-emerald-700 mb-2')}>
|
|
43
|
+
Transforms
|
|
44
|
+
</h2>
|
|
45
|
+
<p style={tw('text-sm text-gray-600 leading-tight')}>
|
|
46
|
+
Rotation supported!
|
|
47
|
+
</p>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{/* Card 3: Typography */}
|
|
51
|
+
<div style={tw('bg-gray-900 rounded-xl shadow-xl p-6 flex-1 min-w-0 flex flex-col')}>
|
|
52
|
+
<h2 style={tw('text-2xl font-black text-yellow-400 mb-2 uppercase letter-spacing-wide')}>
|
|
53
|
+
TYPOGRAPHY
|
|
54
|
+
</h2>
|
|
55
|
+
<p style={tw('text-xs text-gray-300 tracking-tight leading-loose')}>
|
|
56
|
+
All text styles work
|
|
57
|
+
</p>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{/* Bottom Info Bar */}
|
|
62
|
+
<div style={tw('mt-4 bg-white bg-opacity-20 rounded-lg px-6 py-3 max-w-5xl flex flex-row justify-between items-center')}>
|
|
63
|
+
<p style={tw('text-sm font-medium text-white')}>
|
|
64
|
+
Kitchen Sink Template
|
|
65
|
+
</p>
|
|
66
|
+
<p style={tw('text-xs text-white text-opacity-75 tracking-wide')}>
|
|
67
|
+
All features demonstrated
|
|
68
|
+
</p>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
// Template metadata is defined in meta.json
|
|
3
|
+
|
|
4
|
+
export default function Template({ title, url, subtitle, qr, tw }) {
|
|
5
|
+
return (
|
|
6
|
+
<div style={tw('w-full h-full flex flex-col items-center justify-center bg-gradient-to-br from-indigo-600 to-purple-600 p-16')}>
|
|
7
|
+
<div style={tw('bg-white rounded-3xl p-12 flex flex-col items-center shadow-2xl max-w-2xl')}>
|
|
8
|
+
{/* Title */}
|
|
9
|
+
<h1 style={tw('text-5xl font-bold text-gray-900 mb-4 text-center')}>
|
|
10
|
+
{title}
|
|
11
|
+
</h1>
|
|
12
|
+
|
|
13
|
+
{/* Subtitle */}
|
|
14
|
+
{subtitle && (
|
|
15
|
+
<p style={tw('text-xl text-gray-600 mb-8 text-center')}>
|
|
16
|
+
{subtitle}
|
|
17
|
+
</p>
|
|
18
|
+
)}
|
|
19
|
+
|
|
20
|
+
{/* QR Code - automatically generated from the url prop */}
|
|
21
|
+
<div style={tw('bg-white p-6 rounded-2xl border-4 border-gray-200 mb-8 flex')}>
|
|
22
|
+
<img
|
|
23
|
+
src={qr(url)}
|
|
24
|
+
width={300}
|
|
25
|
+
height={300}
|
|
26
|
+
alt="QR Code"
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
{/* URL Display */}
|
|
31
|
+
<div style={tw('bg-gray-100 rounded-xl px-6 py-4 flex')}>
|
|
32
|
+
<p style={tw('text-lg text-gray-700 font-mono')}>
|
|
33
|
+
{url}
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
interface ChildProps {
|
|
3
|
+
text: string;
|
|
4
|
+
tw: (classes: string) => any;
|
|
5
|
+
template: (name: string, props: any) => any;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function Child({ text, tw, template }: ChildProps) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
style={{
|
|
12
|
+
...tw('bg-blue-500 text-white p-4 rounded-lg'),
|
|
13
|
+
display: 'flex',
|
|
14
|
+
flexDirection: 'column',
|
|
15
|
+
alignItems: 'center',
|
|
16
|
+
justifyContent: 'center',
|
|
17
|
+
gap: '10px',
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<div style={tw('text-2xl font-bold')}>Child Template</div>
|
|
21
|
+
<div style={tw('text-lg')}>{text}</div>
|
|
22
|
+
|
|
23
|
+
{/* Use parent-relative path to load sibling template */}
|
|
24
|
+
{template('../test-sibling', { message: 'Loaded via ../ path!' })}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
interface ParentProps {
|
|
3
|
+
title: string;
|
|
4
|
+
childText: string;
|
|
5
|
+
tw: (classes: string) => any;
|
|
6
|
+
template: (name: string, props: any) => any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function Parent({ title, childText, tw, template }: ParentProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
style={{
|
|
13
|
+
...tw('bg-gradient-to-br from-purple-500 to-pink-500 p-8'),
|
|
14
|
+
display: 'flex',
|
|
15
|
+
flexDirection: 'column',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
width: '100%',
|
|
19
|
+
height: '100%',
|
|
20
|
+
gap: '20px',
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
<div style={tw('text-4xl font-bold text-white')}>{title}</div>
|
|
24
|
+
<div style={tw('text-lg text-white opacity-80')}>Testing relative template paths</div>
|
|
25
|
+
|
|
26
|
+
{/* Use relative path to load child template */}
|
|
27
|
+
{template('./child', { text: childText })}
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
interface SiblingProps {
|
|
3
|
+
message: string;
|
|
4
|
+
tw: (classes: string) => any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default function Sibling({ message, tw }: SiblingProps) {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
style={{
|
|
11
|
+
...tw('bg-green-500 text-white p-3 rounded'),
|
|
12
|
+
display: 'flex',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
justifyContent: 'center',
|
|
15
|
+
}}
|
|
16
|
+
>
|
|
17
|
+
<div style={tw('text-sm font-semibold')}>Sibling: {message}</div>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "file:///Users/tommyvedvik/Dev/dsgn/node_modules/react/index.js";
|
|
2
|
+
const meta = {
|
|
3
|
+
name: "video",
|
|
4
|
+
description: "Animated video starter template",
|
|
5
|
+
type: "video",
|
|
6
|
+
size: { width: 1200, height: 630 },
|
|
7
|
+
props: {
|
|
8
|
+
title: "string",
|
|
9
|
+
description: "string?"
|
|
10
|
+
},
|
|
11
|
+
video: {
|
|
12
|
+
fps: 30,
|
|
13
|
+
duration: 3
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function Template({ title, description, frame, progress, tw }) {
|
|
17
|
+
const opacity = Math.min(1, progress * 2);
|
|
18
|
+
const translateY = 20 - progress * 20;
|
|
19
|
+
return /* @__PURE__ */ React.createElement("div", { style: tw("w-full h-full flex flex-col justify-center items-center bg-background p-16") }, /* @__PURE__ */ React.createElement("div", { style: tw("bg-card border rounded-xl p-12 flex flex-col max-w-4xl") }, /* @__PURE__ */ React.createElement(
|
|
20
|
+
"h1",
|
|
21
|
+
{
|
|
22
|
+
style: {
|
|
23
|
+
...tw("text-7xl font-bold text-foreground mb-4"),
|
|
24
|
+
opacity,
|
|
25
|
+
transform: `translateY(${translateY}px)`
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
title
|
|
29
|
+
), description && /* @__PURE__ */ React.createElement(
|
|
30
|
+
"p",
|
|
31
|
+
{
|
|
32
|
+
style: {
|
|
33
|
+
...tw("text-3xl text-muted-foreground"),
|
|
34
|
+
opacity: Math.min(1, (progress - 0.3) * 2)
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
description
|
|
38
|
+
)));
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
Template as default,
|
|
42
|
+
meta
|
|
43
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "file:///Users/tommyvedvik/Dev/dsgn/node_modules/react/index.js";
|
|
2
|
+
const meta = {
|
|
3
|
+
name: "video",
|
|
4
|
+
description: "Animated video starter template",
|
|
5
|
+
type: "video",
|
|
6
|
+
size: { width: 1200, height: 630 },
|
|
7
|
+
props: {
|
|
8
|
+
title: "string",
|
|
9
|
+
description: "string?"
|
|
10
|
+
},
|
|
11
|
+
video: {
|
|
12
|
+
fps: 30,
|
|
13
|
+
duration: 3
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function Template({ title, description, frame, progress, tw }) {
|
|
17
|
+
const opacity = Math.min(1, progress * 2);
|
|
18
|
+
const translateY = 20 - progress * 20;
|
|
19
|
+
return /* @__PURE__ */ React.createElement("div", { style: tw("w-full h-full flex flex-col justify-center items-center bg-background p-16") }, /* @__PURE__ */ React.createElement("div", { style: tw("bg-card border rounded-xl p-12 flex flex-col max-w-4xl") }, /* @__PURE__ */ React.createElement(
|
|
20
|
+
"h1",
|
|
21
|
+
{
|
|
22
|
+
style: {
|
|
23
|
+
...tw("text-7xl font-bold text-foreground mb-4"),
|
|
24
|
+
opacity,
|
|
25
|
+
transform: `translateY(${translateY}px)`
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
title
|
|
29
|
+
), description && /* @__PURE__ */ React.createElement(
|
|
30
|
+
"p",
|
|
31
|
+
{
|
|
32
|
+
style: {
|
|
33
|
+
...tw("text-3xl text-muted-foreground"),
|
|
34
|
+
opacity: Math.min(1, (progress - 0.3) * 2)
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
description
|
|
38
|
+
)));
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
Template as default,
|
|
42
|
+
meta
|
|
43
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "file:///Users/tommyvedvik/Dev/dsgn/node_modules/react/index.js";
|
|
2
|
+
const meta = {
|
|
3
|
+
name: "video",
|
|
4
|
+
description: "Animated video starter template",
|
|
5
|
+
type: "video",
|
|
6
|
+
size: { width: 1200, height: 630 },
|
|
7
|
+
props: {
|
|
8
|
+
title: "string",
|
|
9
|
+
description: "string?"
|
|
10
|
+
},
|
|
11
|
+
video: {
|
|
12
|
+
fps: 30,
|
|
13
|
+
duration: 3
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function Template({ title, description, frame, progress, tw }) {
|
|
17
|
+
const opacity = Math.min(1, progress * 2);
|
|
18
|
+
const translateY = 20 - progress * 20;
|
|
19
|
+
return /* @__PURE__ */ React.createElement("div", { style: tw("w-full h-full flex flex-col justify-center items-center bg-background p-16") }, /* @__PURE__ */ React.createElement("div", { style: tw("bg-card border rounded-xl p-12 flex flex-col max-w-4xl") }, /* @__PURE__ */ React.createElement(
|
|
20
|
+
"h1",
|
|
21
|
+
{
|
|
22
|
+
style: {
|
|
23
|
+
...tw("text-7xl font-bold text-foreground mb-4"),
|
|
24
|
+
opacity,
|
|
25
|
+
transform: `translateY(${translateY}px)`
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
title
|
|
29
|
+
), description && /* @__PURE__ */ React.createElement(
|
|
30
|
+
"p",
|
|
31
|
+
{
|
|
32
|
+
style: {
|
|
33
|
+
...tw("text-3xl text-muted-foreground"),
|
|
34
|
+
opacity: Math.min(1, (progress - 0.3) * 2)
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
description
|
|
38
|
+
)));
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
Template as default,
|
|
42
|
+
meta
|
|
43
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "video",
|
|
3
|
+
"description": "Animated video starter template",
|
|
4
|
+
"type": "video",
|
|
5
|
+
"size": {
|
|
6
|
+
"width": 1200,
|
|
7
|
+
"height": 630
|
|
8
|
+
},
|
|
9
|
+
"props": {
|
|
10
|
+
"title": "string",
|
|
11
|
+
"description": "string?"
|
|
12
|
+
},
|
|
13
|
+
"video": {
|
|
14
|
+
"fps": 30,
|
|
15
|
+
"duration": 3
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: "video",
|
|
3
|
+
description: "Animated video starter template",
|
|
4
|
+
type: "video",
|
|
5
|
+
size: { width: 1200, height: 630 },
|
|
6
|
+
props: {
|
|
7
|
+
title: "string",
|
|
8
|
+
description: "string?"
|
|
9
|
+
},
|
|
10
|
+
video: {
|
|
11
|
+
fps: 30,
|
|
12
|
+
duration: 3
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function Template({ title, description, frame, progress, tw }) {
|
|
17
|
+
// Fade in animation
|
|
18
|
+
const opacity = Math.min(1, progress * 2);
|
|
19
|
+
|
|
20
|
+
// Slide up animation
|
|
21
|
+
const translateY = 20 - (progress * 20);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div style={tw('w-full h-full flex flex-col justify-center items-center bg-background p-16')}>
|
|
25
|
+
<div style={tw('bg-card border rounded-xl p-12 flex flex-col max-w-4xl')}>
|
|
26
|
+
<h1
|
|
27
|
+
style={{
|
|
28
|
+
...tw('text-7xl font-bold text-foreground mb-4'),
|
|
29
|
+
opacity,
|
|
30
|
+
transform: `translateY(${translateY}px)`
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
{title}
|
|
34
|
+
</h1>
|
|
35
|
+
{description && (
|
|
36
|
+
<p
|
|
37
|
+
style={{
|
|
38
|
+
...tw('text-3xl text-muted-foreground'),
|
|
39
|
+
opacity: Math.min(1, (progress - 0.3) * 2)
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
{description}
|
|
43
|
+
</p>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { addCommand } from './commands/add.js';
|
|
4
|
+
import { listCommand } from './commands/list.js';
|
|
5
|
+
import { renderCommand } from './commands/render.js';
|
|
6
|
+
import { validateCommand } from './commands/validate.js';
|
|
7
|
+
import { initCommand } from './commands/init.js';
|
|
8
|
+
import { defaultCommand } from './commands/default.js';
|
|
9
|
+
import { previewCommand } from './commands/preview.js';
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { dirname, join } from 'path';
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program
|
|
18
|
+
.name('loopwind')
|
|
19
|
+
.description('A template-based CLI tool for generating images and videos using Tailwind CSS + Satori')
|
|
20
|
+
.version(packageJson.version)
|
|
21
|
+
.action(defaultCommand);
|
|
22
|
+
// design add <template>
|
|
23
|
+
program
|
|
24
|
+
.command('add <template>')
|
|
25
|
+
.description('Install a template from the registry')
|
|
26
|
+
.option('-r, --registry <url>', 'Custom registry URL', 'https://loopwind.dev/r')
|
|
27
|
+
.action(addCommand);
|
|
28
|
+
// design list
|
|
29
|
+
program
|
|
30
|
+
.command('list')
|
|
31
|
+
.description('List all installed templates')
|
|
32
|
+
.action(listCommand);
|
|
33
|
+
// design render <template> [props]
|
|
34
|
+
program
|
|
35
|
+
.command('render <template> [props]')
|
|
36
|
+
.description('Render a template to an image or video')
|
|
37
|
+
.option('-p, --props <file>', 'Props file (JSON) - deprecated, use positional argument instead')
|
|
38
|
+
.option('-o, --out <file>', 'Output file path')
|
|
39
|
+
.option('--format <format>', 'Output format (png, svg, webp, jpg, jpeg)', 'png')
|
|
40
|
+
.option('--frames-only', 'Render video frames only (no encoding)')
|
|
41
|
+
.option('--crf <number>', 'Video quality (0-51, lower = better quality)', '23')
|
|
42
|
+
.addHelpText('after', `
|
|
43
|
+
Examples:
|
|
44
|
+
Images:
|
|
45
|
+
$ loopwind render banner-hero '{"title":"Hello World"}'
|
|
46
|
+
$ loopwind render banner-hero props.json
|
|
47
|
+
$ loopwind render banner-hero '{"title":"Test"}' --format svg
|
|
48
|
+
$ loopwind render banner-hero props.json --format webp --out banner.webp
|
|
49
|
+
|
|
50
|
+
Videos (serverless-compatible, no ffmpeg required):
|
|
51
|
+
$ loopwind render my-video '{"title":"Video Title"}'
|
|
52
|
+
$ loopwind render my-video props.json --out video.mp4
|
|
53
|
+
$ loopwind render my-video '{"title":"Test"}' --crf 20 # Higher quality
|
|
54
|
+
$ loopwind render my-video props.json --frames-only # Just export frames
|
|
55
|
+
`)
|
|
56
|
+
.action(renderCommand);
|
|
57
|
+
// design validate
|
|
58
|
+
program
|
|
59
|
+
.command('validate [template]')
|
|
60
|
+
.description('Validate template metadata')
|
|
61
|
+
.action(validateCommand);
|
|
62
|
+
// design init
|
|
63
|
+
program
|
|
64
|
+
.command('init')
|
|
65
|
+
.description('Initialize a loopwind.json config file')
|
|
66
|
+
.action(initCommand);
|
|
67
|
+
// design preview <template> [props]
|
|
68
|
+
program.addCommand(previewCommand);
|
|
69
|
+
program.parse();
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAE1F,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,wFAAwF,CAAC;KACrG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,MAAM,CAAC,cAAc,CAAC,CAAC;AAE1B,wBAAwB;AACxB,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,EAAE,wBAAwB,CAAC;KAC/E,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,cAAc;AACd,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,8BAA8B,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,mCAAmC;AACnC,OAAO;KACJ,OAAO,CAAC,2BAA2B,CAAC;KACpC,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,oBAAoB,EAAE,iEAAiE,CAAC;KAC/F,MAAM,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;KAC9C,MAAM,CAAC,mBAAmB,EAAE,2CAA2C,EAAE,KAAK,CAAC;KAC/E,MAAM,CAAC,eAAe,EAAE,wCAAwC,CAAC;KACjE,MAAM,CAAC,gBAAgB,EAAE,8CAA8C,EAAE,IAAI,CAAC;KAC9E,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;;;;CAavB,CAAC;KACC,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,kBAAkB;AAClB,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,eAAe,CAAC,CAAC;AAE3B,cAAc;AACd,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,oCAAoC;AACpC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAOA,UAAU,UAAU;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,UAAU,CAC9B,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CA4Ff"}
|