loopwind 0.22.0 → 0.23.0

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 (120) hide show
  1. package/dist/lib/render-core.d.ts +63 -0
  2. package/dist/lib/render-core.d.ts.map +1 -0
  3. package/dist/lib/render-core.js +65 -0
  4. package/dist/lib/render-core.js.map +1 -0
  5. package/dist/lib/renderer.d.ts.map +1 -1
  6. package/dist/lib/renderer.js +10 -7
  7. package/dist/lib/renderer.js.map +1 -1
  8. package/dist/lib/resvg-init.d.ts +15 -0
  9. package/dist/lib/resvg-init.d.ts.map +1 -0
  10. package/dist/lib/resvg-init.js +55 -0
  11. package/dist/lib/resvg-init.js.map +1 -0
  12. package/dist/lib/tailwind/colors.d.ts +8 -0
  13. package/dist/lib/tailwind/colors.d.ts.map +1 -0
  14. package/dist/lib/tailwind/colors.js +102 -0
  15. package/dist/lib/tailwind/colors.js.map +1 -0
  16. package/dist/lib/tailwind/index.d.ts +10 -0
  17. package/dist/lib/tailwind/index.d.ts.map +1 -0
  18. package/dist/lib/tailwind/index.js +9 -0
  19. package/dist/lib/tailwind/index.js.map +1 -0
  20. package/dist/lib/tailwind/resolvers.d.ts +28 -0
  21. package/dist/lib/tailwind/resolvers.d.ts.map +1 -0
  22. package/dist/lib/tailwind/resolvers.js +94 -0
  23. package/dist/lib/tailwind/resolvers.js.map +1 -0
  24. package/dist/lib/tailwind/types.d.ts +29 -0
  25. package/dist/lib/tailwind/types.d.ts.map +1 -0
  26. package/dist/lib/tailwind/types.js +8 -0
  27. package/dist/lib/tailwind/types.js.map +1 -0
  28. package/dist/lib/tailwind-config-loader.d.ts +8 -45
  29. package/dist/lib/tailwind-config-loader.d.ts.map +1 -1
  30. package/dist/lib/tailwind-config-loader.js +6 -429
  31. package/dist/lib/tailwind-config-loader.js.map +1 -1
  32. package/dist/lib/tailwind.d.ts +1 -1
  33. package/dist/lib/tailwind.d.ts.map +1 -1
  34. package/dist/lib/tailwind.js +1 -1
  35. package/dist/lib/tailwind.js.map +1 -1
  36. package/dist/lib/video-renderer.d.ts.map +1 -1
  37. package/dist/lib/video-renderer.js +6 -5
  38. package/dist/lib/video-renderer.js.map +1 -1
  39. package/dist/sdk/edge/index.d.ts +91 -0
  40. package/dist/sdk/edge/index.d.ts.map +1 -0
  41. package/dist/sdk/edge/index.js +187 -0
  42. package/dist/sdk/edge/index.js.map +1 -0
  43. package/dist/sdk/workers/index.d.ts +135 -0
  44. package/dist/sdk/workers/index.d.ts.map +1 -0
  45. package/dist/sdk/workers/index.js +271 -0
  46. package/dist/sdk/workers/index.js.map +1 -0
  47. package/dist/sdk/workers/tailwind-config.d.ts +48 -0
  48. package/dist/sdk/workers/tailwind-config.d.ts.map +1 -0
  49. package/dist/sdk/workers/tailwind-config.js +187 -0
  50. package/dist/sdk/workers/tailwind-config.js.map +1 -0
  51. package/dist/sdk/workers/tailwind.d.ts +9 -0
  52. package/dist/sdk/workers/tailwind.d.ts.map +1 -0
  53. package/dist/sdk/workers/tailwind.js +8 -0
  54. package/dist/sdk/workers/tailwind.js.map +1 -0
  55. package/package.json +6 -2
  56. package/test-cloudflare-worker/README.md +64 -0
  57. package/test-cloudflare-worker/dist/README.md +1 -0
  58. package/test-cloudflare-worker/dist/index.js +23743 -0
  59. package/test-cloudflare-worker/dist/index.js.map +8 -0
  60. package/test-cloudflare-worker/package-lock.json +1773 -0
  61. package/test-cloudflare-worker/package.json +25 -0
  62. package/test-cloudflare-worker/test-sdk.mjs +75 -0
  63. package/test-cloudflare-worker/wrangler.toml +14 -0
  64. package/test-video-720p.mjs +96 -0
  65. package/test-video-breakdown.mjs +98 -0
  66. package/test-video-perf-1080.mjs +67 -0
  67. package/test-video-perf.mjs +56 -0
  68. package/test-worker-1080p.mjs +103 -0
  69. package/test-worker-viability.mjs +140 -0
  70. package/website/astro.config.mjs +4 -9
  71. package/website/dist/_astro/PlaygroundEditor.DzFavsm8.js +26 -0
  72. package/website/dist/_astro/VideoPreviewClient.BrajhYmh.js +1 -0
  73. package/website/dist/_astro/agents.CZXv4DCM.css +1 -0
  74. package/website/dist/_astro/client.BHSq4mdQ.js +33 -0
  75. package/website/dist/_astro/index.CTbGshLK.js +9 -0
  76. package/website/dist/_astro/jsx-runtime.BjG_zV1W.js +9 -0
  77. package/website/dist/_routes.json +1 -0
  78. package/website/dist/_worker.js/_@astrojs-ssr-adapter.mjs +4 -4
  79. package/website/dist/_worker.js/_astro-internal_middleware.mjs +2 -2
  80. package/website/dist/_worker.js/chunks/Logo_Cud5QvBJ.mjs +22 -0
  81. package/website/dist/_worker.js/chunks/_@astro-renderers_-YVK7NHa.mjs +15015 -0
  82. package/website/dist/_worker.js/chunks/astro/{server_Y5_QHO8v.mjs → server_CsUrSZgd.mjs} +113 -2
  83. package/website/dist/_worker.js/chunks/{astro-designed-error-pages_BNTLO-TA.mjs → astro-designed-error-pages_1ELXm5Tt.mjs} +1 -1
  84. package/website/dist/_worker.js/chunks/{index_C1UTDwYg.mjs → index_BDWR1Q-q.mjs} +2 -2
  85. package/website/dist/_worker.js/chunks/{noop-middleware_DlWGj5t5.mjs → noop-middleware_B8fH5jha.mjs} +1 -1
  86. package/website/dist/_worker.js/index.js +38 -30
  87. package/website/dist/_worker.js/manifest_Bk6136-u.mjs +98 -0
  88. package/website/dist/_worker.js/pages/_image.astro.mjs +1 -1
  89. package/website/dist/_worker.js/pages/api/playground/render.astro.mjs +25562 -0
  90. package/website/dist/_worker.js/pages/api/playground/templates.astro.mjs +92 -0
  91. package/website/dist/_worker.js/pages/api/raw-markdown/_---path_.astro.mjs +1 -1
  92. package/website/dist/_worker.js/pages/playground/_example_.astro.mjs +95 -0
  93. package/website/dist/_worker.js/pages/playground.astro.mjs +1 -0
  94. package/website/dist/_worker.js/renderers.mjs +1 -56
  95. package/website/dist/agents/index.html +4 -2
  96. package/website/dist/animation/index.html +629 -3
  97. package/website/dist/config/index.html +4 -2
  98. package/website/dist/fonts/index.html +4 -2
  99. package/website/dist/getting-started/index.html +4 -2
  100. package/website/dist/helpers/index.html +196 -10
  101. package/website/dist/images/index.html +4 -2
  102. package/website/dist/index.html +4 -3
  103. package/website/dist/llm.txt +870 -20
  104. package/website/dist/playground/index.html +6 -0
  105. package/website/dist/preview/index.html +4 -2
  106. package/website/dist/sdk/index.html +639 -127
  107. package/website/dist/sitemap.xml +12 -12
  108. package/website/dist/styling/index.html +4 -2
  109. package/website/dist/templates/index.html +4 -2
  110. package/website/dist/video/index.html +47 -12
  111. package/website/package-lock.json +11 -1
  112. package/website/package.json +3 -1
  113. package/website/wrangler.toml +9 -0
  114. package/_dsgn/templates/dashed-stroke-test/template.tsx +0 -73
  115. package/_dsgn/templates/path-follow-test/template.tsx +0 -176
  116. package/_dsgn/templates/path-simple-test/template.tsx +0 -98
  117. package/_dsgn/templates/stroke-dash-test/meta.json +0 -12
  118. package/_dsgn/templates/stroke-dash-test/template.tsx +0 -53
  119. package/website/dist/_astro/agents.Yx-L_igG.css +0 -1
  120. package/website/dist/_worker.js/manifest_CT_D-YDe.mjs +0 -98
@@ -1,5 +1,7 @@
1
- <!DOCTYPE html><html lang="en" data-astro-cid-mw7aashj> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v4.16.19"><link rel="canonical" href="https://loopwind.dev/helpers/"><!-- Primary Meta Tags --><title></title><meta name="title"><meta name="description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="keywords" content="loopwind, image generation, video generation, React, Tailwind CSS, Satori, CLI tool, templates, shadcn/ui, AI agents, Cursor, automation, serverless, WASM, Open Graph, social media, marketing automation"><meta name="author" content="loopwind"><!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://loopwind.dev/helpers/"><meta property="og:title"><meta property="og:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta property="og:image" content="https://loopwind.dev/api/og/helpers"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:alt"><meta property="og:site_name" content="loopwind"><meta property="og:locale" content="en_US"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://loopwind.dev/helpers/"><meta name="twitter:title"><meta name="twitter:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="twitter:image" content="https://loopwind.dev/api/og/helpers"><meta name="twitter:image:alt"><meta name="twitter:creator" content="@loopwind"><meta name="twitter:site" content="@loopwind"><!-- Theme Color --><meta name="theme-color" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#fafafa"><!-- Additional SEO --><meta name="robots" content="index, follow"><meta name="googlebot" content="index, follow"><meta name="language" content="English"><meta name="revisit-after" content="7 days"><meta name="rating" content="general"><!-- Mobile Web App --><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="loopwind"><!-- Structured Data (JSON-LD) --><script type="application/ld+json">{"@context":"https://schema.org","@type":"SoftwareApplication","name":"loopwind","applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","description":"CLI-based Image & Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates.","url":"https://loopwind.dev/","author":{"@type":"Organization","name":"loopwind","url":"https://loopwind.dev/"},"offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"softwareVersion":"0.11.0","releaseNotes":"https://github.com/loopwind/loopwind/releases","screenshot":"https://loopwind.dev/api/og/helpers","featureList":["Image generation from React templates","Video generation with animations","Tailwind CSS support","shadcn/ui design system","CLI-based workflow","Serverless rendering","TypeScript support","AI Agent friendly"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"loopwind","url":"https://loopwind.dev/","logo":"https://loopwind.dev/favicon.svg","sameAs":["https://github.com/loopwind/loopwind","https://www.npmjs.com/package/loopwind"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://loopwind.dev/"},{"@type":"ListItem","position":2,"name":"Helpers","item":"https://loopwind.dev/helpers"}]}</script><link rel="stylesheet" href="/_astro/agents.Yx-L_igG.css"><script type="module">const p=document.getElementById("mobile-menu-button"),l=document.getElementById("mobile-menu"),g=document.querySelectorAll(".mobile-menu-link");p?.addEventListener("click",()=>{l?.classList.toggle("hidden")});l?.addEventListener("click",o=>{o.target===l&&l.classList.add("hidden")});g.forEach(o=>{o.addEventListener("click",()=>{l?.classList.add("hidden")})});function m(){const o=document.getElementById("toc-nav");if(!o){console.log("TOC: No toc-nav element found");return}const n=document.querySelector("article");if(!n){console.log("TOC: No article element found");return}const c=n.querySelectorAll("h2, h3");if(c.length===0){console.log("TOC: No headings found");return}console.log(`TOC: Found ${c.length} headings`);const a=document.createElement("ul");a.className="space-y-0 text-sm border-l border-border/50",c.forEach(e=>{const t=e.tagName==="H2"?2:3,r=e.id||e.textContent?.toLowerCase().replace(/[^\w]+/g,"-");!e.id&&r&&(e.id=r);const s=document.createElement("li"),d=document.createElement("a");d.href=`#${r}`,d.textContent=e.textContent,d.className=`toc-link block py-1 px-3 -ml-px border-l-2 border-transparent transition-all no-underline ${t===3?"pl-6 text-xs text-muted-foreground/70":"text-sm text-muted-foreground"} hover:text-foreground hover:border-muted-foreground/50`,s.appendChild(d),a.appendChild(s)}),o.appendChild(a);const i=new IntersectionObserver(e=>{e.forEach(t=>{const r=t.target.id,s=o.querySelector(`a[href="#${r}"]`);t.isIntersecting&&(document.querySelectorAll(".toc-link").forEach(d=>{d.classList.remove("text-foreground","border-accent","font-medium")}),s?.classList.add("text-foreground","border-accent","font-medium"))})},{rootMargin:"-100px 0px -66%",threshold:0});c.forEach(e=>{i.observe(e)})}document.addEventListener("DOMContentLoaded",m);document.addEventListener("astro:page-load",m);function u(){const o=document.getElementById("copy-to-llm-btn"),n=document.getElementById("copy-btn-text");if(!o||!n){console.log("Copy to LLM: Button not found on this page");return}console.log("Copy to LLM: Initialized"),o.addEventListener("click",async()=>{const c=window.location.pathname,a=c.replace(/^\//,"").replace(/\/$/,""),e=`/api/raw-markdown/${a===""?"index":a}`;console.log("Copy to LLM clicked: pathname=",c,"apiUrl=",e);try{n.textContent="Copying...";const t=await fetch(e);if(console.log("Response status:",t.status),!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const r=await t.text();console.log("Got markdown, length:",r.length),await navigator.clipboard.writeText(r),n.textContent="Copied!",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}catch(t){console.error("Copy failed:",t),n.textContent="Failed",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}})}document.addEventListener("DOMContentLoaded",u);document.addEventListener("astro:page-load",u);
2
- </script></head> <body class="antialiased" data-astro-cid-mw7aashj> <div class="min-h-screen" data-astro-cid-mw7aashj> <!-- Mobile Header --> <header class="mobile-header fixed top-0 left-0 right-0 h-16 bg-card border-b border-border z-50 md:hidden" data-astro-cid-mw7aashj> <div class="flex items-center justify-between h-full px-4" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-2xl">➰</span> <span>loopwind</span> </h1> </a> <button id="mobile-menu-button" class="p-2 text-foreground hover:bg-accent rounded-md transition-colors" aria-label="Toggle menu" data-astro-cid-mw7aashj> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-mw7aashj></path> </svg> </button> </div> </header> <!-- Mobile Menu Overlay --> <div id="mobile-menu" class="mobile-menu fixed inset-0 bg-background/80 backdrop-blur-sm z-40 md:hidden hidden" data-astro-cid-mw7aashj> <div class="fixed top-0 left-0 h-screen w-64 bg-card border-r border-border overflow-y-auto" data-astro-cid-mw7aashj> <div class="p-6 pt-20" data-astro-cid-mw7aashj> <nav data-astro-cid-mw7aashj> <ul class="space-y-1" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </div> </div> <!-- Desktop Sidebar --> <aside class="desktop-sidebar fixed top-0 left-0 h-screen w-64 border-r border-border bg-card overflow-y-auto z-10" data-astro-cid-mw7aashj> <div class="p-6" data-astro-cid-mw7aashj> <div class="block mb-3" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-3xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-4xl">➰</span> <span>loopwind</span> </h1> </a> </div> <nav data-astro-cid-mw7aashj> <ul class="space-y-0" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </aside> <!-- Main content --> <main class="ml-64 mr-64" data-astro-cid-mw7aashj> <div class="p-12" data-astro-cid-mw7aashj> <button id="copy-to-llm-btn" class="mb-6 px-4 py-2 bg-accent hover:bg-accent/80 text-accent-foreground rounded-md text-sm font-medium transition-colors flex items-center gap-2" aria-label="Copy raw markdown to clipboard" data-astro-cid-mw7aashj> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" data-astro-cid-mw7aashj></path> </svg> <span id="copy-btn-text" data-astro-cid-mw7aashj>Copy to LLM</span> </button> <article class="prose prose-invert max-w-4xl" data-astro-cid-mw7aashj> <h1 id="template-helpers">Template Helpers</h1>
1
+ <!DOCTYPE html><html lang="en" data-astro-cid-mw7aashj> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v4.16.19"><link rel="canonical" href="https://loopwind.dev/helpers/"><!-- Primary Meta Tags --><title></title><meta name="title"><meta name="description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="keywords" content="loopwind, image generation, video generation, React, Tailwind CSS, Satori, CLI tool, templates, shadcn/ui, AI agents, Cursor, automation, serverless, WASM, Open Graph, social media, marketing automation"><meta name="author" content="loopwind"><!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://loopwind.dev/helpers/"><meta property="og:title"><meta property="og:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta property="og:image" content="https://loopwind.dev/api/og/helpers"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:alt"><meta property="og:site_name" content="loopwind"><meta property="og:locale" content="en_US"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://loopwind.dev/helpers/"><meta name="twitter:title"><meta name="twitter:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="twitter:image" content="https://loopwind.dev/api/og/helpers"><meta name="twitter:image:alt"><meta name="twitter:creator" content="@loopwind"><meta name="twitter:site" content="@loopwind"><!-- Theme Color --><meta name="theme-color" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#fafafa"><!-- Additional SEO --><meta name="robots" content="index, follow"><meta name="googlebot" content="index, follow"><meta name="language" content="English"><meta name="revisit-after" content="7 days"><meta name="rating" content="general"><!-- Mobile Web App --><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="loopwind"><!-- Structured Data (JSON-LD) --><script type="application/ld+json">{"@context":"https://schema.org","@type":"SoftwareApplication","name":"loopwind","applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","description":"CLI-based Image & Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates.","url":"https://loopwind.dev/","author":{"@type":"Organization","name":"loopwind","url":"https://loopwind.dev/"},"offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"softwareVersion":"0.11.0","releaseNotes":"https://github.com/loopwind/loopwind/releases","screenshot":"https://loopwind.dev/api/og/helpers","featureList":["Image generation from React templates","Video generation with animations","Tailwind CSS support","shadcn/ui design system","CLI-based workflow","Serverless rendering","TypeScript support","AI Agent friendly"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"loopwind","url":"https://loopwind.dev/","logo":"https://loopwind.dev/favicon.svg","sameAs":["https://github.com/loopwind/loopwind","https://www.npmjs.com/package/loopwind"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://loopwind.dev/"},{"@type":"ListItem","position":2,"name":"Helpers","item":"https://loopwind.dev/helpers"}]}</script><link rel="stylesheet" href="/_astro/agents.CZXv4DCM.css">
2
+ <style>.hero[data-astro-cid-bbe6dxrz]{position:relative}html{scroll-behavior:smooth}.mobile-header[data-astro-cid-mw7aashj]{display:none}.toc-sidebar[data-astro-cid-mw7aashj]{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.1) transparent}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar{width:4px}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-track{background:transparent}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-thumb{background-color:#ffffff1a;border-radius:2px}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-thumb:hover{background-color:#fff3}#copy-to-llm-btn[data-astro-cid-mw7aashj]{cursor:pointer}@media (max-width: 768px){.mobile-header[data-astro-cid-mw7aashj]{display:block}.desktop-sidebar[data-astro-cid-mw7aashj]{display:none}main[data-astro-cid-mw7aashj]{margin-left:0;margin-right:0!important;padding:5rem 1.5rem 1.5rem}.toc-sidebar[data-astro-cid-mw7aashj]{display:none}#copy-to-llm-btn[data-astro-cid-mw7aashj]{width:100%;justify-content:center}}@media (max-width: 1280px){.toc-sidebar[data-astro-cid-mw7aashj]{display:none!important}main[data-astro-cid-mw7aashj]{margin-right:0!important}}
3
+ </style><script type="module">const p=document.getElementById("mobile-menu-button"),l=document.getElementById("mobile-menu"),g=document.querySelectorAll(".mobile-menu-link");p?.addEventListener("click",()=>{l?.classList.toggle("hidden")});l?.addEventListener("click",o=>{o.target===l&&l.classList.add("hidden")});g.forEach(o=>{o.addEventListener("click",()=>{l?.classList.add("hidden")})});function m(){const o=document.getElementById("toc-nav");if(!o){console.log("TOC: No toc-nav element found");return}const n=document.querySelector("article");if(!n){console.log("TOC: No article element found");return}const c=n.querySelectorAll("h2, h3");if(c.length===0){console.log("TOC: No headings found");return}console.log(`TOC: Found ${c.length} headings`);const a=document.createElement("ul");a.className="space-y-0 text-sm border-l border-border/50",c.forEach(e=>{const t=e.tagName==="H2"?2:3,r=e.id||e.textContent?.toLowerCase().replace(/[^\w]+/g,"-");!e.id&&r&&(e.id=r);const s=document.createElement("li"),d=document.createElement("a");d.href=`#${r}`,d.textContent=e.textContent,d.className=`toc-link block py-1 px-3 -ml-px border-l-2 border-transparent transition-all no-underline ${t===3?"pl-6 text-xs text-muted-foreground/70":"text-sm text-muted-foreground"} hover:text-foreground hover:border-muted-foreground/50`,s.appendChild(d),a.appendChild(s)}),o.appendChild(a);const i=new IntersectionObserver(e=>{e.forEach(t=>{const r=t.target.id,s=o.querySelector(`a[href="#${r}"]`);t.isIntersecting&&(document.querySelectorAll(".toc-link").forEach(d=>{d.classList.remove("text-foreground","border-accent","font-medium")}),s?.classList.add("text-foreground","border-accent","font-medium"))})},{rootMargin:"-100px 0px -66%",threshold:0});c.forEach(e=>{i.observe(e)})}document.addEventListener("DOMContentLoaded",m);document.addEventListener("astro:page-load",m);function u(){const o=document.getElementById("copy-to-llm-btn"),n=document.getElementById("copy-btn-text");if(!o||!n){console.log("Copy to LLM: Button not found on this page");return}console.log("Copy to LLM: Initialized"),o.addEventListener("click",async()=>{const c=window.location.pathname,a=c.replace(/^\//,"").replace(/\/$/,""),e=`/api/raw-markdown/${a===""?"index":a}`;console.log("Copy to LLM clicked: pathname=",c,"apiUrl=",e);try{n.textContent="Copying...";const t=await fetch(e);if(console.log("Response status:",t.status),!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const r=await t.text();console.log("Got markdown, length:",r.length),await navigator.clipboard.writeText(r),n.textContent="Copied!",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}catch(t){console.error("Copy failed:",t),n.textContent="Failed",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}})}document.addEventListener("DOMContentLoaded",u);document.addEventListener("astro:page-load",u);
4
+ </script></head> <body class="antialiased" data-astro-cid-mw7aashj> <div class="min-h-screen" data-astro-cid-mw7aashj> <!-- Mobile Header --> <header class="mobile-header fixed top-0 left-0 right-0 h-16 bg-card border-b border-border z-50 md:hidden" data-astro-cid-mw7aashj> <div class="flex items-center justify-between h-full px-4" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-2xl">➰</span> <span>loopwind</span> </h1> </a> <button id="mobile-menu-button" class="p-2 text-foreground hover:bg-accent rounded-md transition-colors" aria-label="Toggle menu" data-astro-cid-mw7aashj> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-mw7aashj></path> </svg> </button> </div> </header> <!-- Mobile Menu Overlay --> <div id="mobile-menu" class="mobile-menu fixed inset-0 bg-background/80 backdrop-blur-sm z-40 md:hidden hidden" data-astro-cid-mw7aashj> <div class="fixed top-0 left-0 h-screen w-64 bg-card border-r border-border overflow-y-auto" data-astro-cid-mw7aashj> <div class="p-6 pt-20" data-astro-cid-mw7aashj> <nav data-astro-cid-mw7aashj> <ul class="space-y-1" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/playground" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Playground </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </div> </div> <!-- Desktop Sidebar --> <aside class="desktop-sidebar fixed top-0 left-0 h-screen w-64 border-r border-border bg-card overflow-y-auto z-10" data-astro-cid-mw7aashj> <div class="p-6" data-astro-cid-mw7aashj> <div class="block mb-3" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-3xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-4xl">➰</span> <span>loopwind</span> </h1> </a> </div> <nav data-astro-cid-mw7aashj> <ul class="space-y-0" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/playground" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Playground </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </aside> <!-- Main content --> <main class="ml-64 mr-64" data-astro-cid-mw7aashj> <div class="p-12" data-astro-cid-mw7aashj> <button id="copy-to-llm-btn" class="mb-6 px-4 py-2 bg-accent hover:bg-accent/80 text-accent-foreground rounded-md text-sm font-medium transition-colors flex items-center gap-2" aria-label="Copy raw markdown to clipboard" data-astro-cid-mw7aashj> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" data-astro-cid-mw7aashj></path> </svg> <span id="copy-btn-text" data-astro-cid-mw7aashj>Copy to LLM</span> </button> <article class="prose prose-invert max-w-4xl" data-astro-cid-mw7aashj> <h1 id="template-helpers">Template Helpers</h1>
3
5
  <p>Additional helpers for creating powerful, composable templates.</p>
4
6
  <h2 id="overview">Overview</h2>
5
7
  <p>Beyond the basics, loopwind provides:</p>
@@ -133,24 +135,208 @@
133
135
  <span class="line"><span style="color:#E1E4E8">}</span></span>
134
136
  <span class="line"></span></code></pre>
135
137
  <p>This allows templates to adapt to user preferences and brand guidelines.</p>
138
+ <h2 id="text-on-path">Text on Path</h2>
139
+ <p>Render text along curves, circles, and custom paths with automatic character positioning and rotation.</p>
140
+ <h3 id="usage-2">Usage</h3>
141
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> CircleText</span><span style="color:#E1E4E8">({ </span><span style="color:#FFAB70">tw</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">textPath</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">message</span><span style="color:#E1E4E8"> }) {</span></span>
142
+ <span class="line"><span style="color:#F97583"> return</span><span style="color:#E1E4E8"> (</span></span>
143
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">div</span><span style="color:#B392F0"> style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#B392F0">tw</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&#39;relative w-full h-full bg-slate-900&#39;</span><span style="color:#E1E4E8">)}&gt;</span></span>
144
+ <span class="line"><span style="color:#E1E4E8"> {textPath.</span><span style="color:#B392F0">onCircle</span><span style="color:#E1E4E8">(</span></span>
145
+ <span class="line"><span style="color:#E1E4E8"> message,</span></span>
146
+ <span class="line"><span style="color:#79B8FF"> 960</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// center x</span></span>
147
+ <span class="line"><span style="color:#79B8FF"> 540</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// center y</span></span>
148
+ <span class="line"><span style="color:#79B8FF"> 400</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// radius</span></span>
149
+ <span class="line"><span style="color:#79B8FF"> 0</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// rotation offset (0-1)</span></span>
150
+ <span class="line"><span style="color:#E1E4E8"> {</span></span>
151
+ <span class="line"><span style="color:#E1E4E8"> fontSize: </span><span style="color:#9ECBFF">&quot;4xl&quot;</span><span style="color:#E1E4E8">,</span></span>
152
+ <span class="line"><span style="color:#E1E4E8"> fontWeight: </span><span style="color:#9ECBFF">&quot;bold&quot;</span><span style="color:#E1E4E8">,</span></span>
153
+ <span class="line"><span style="color:#E1E4E8"> color: </span><span style="color:#9ECBFF">&quot;white&quot;</span><span style="color:#E1E4E8">,</span></span>
154
+ <span class="line"><span style="color:#E1E4E8"> letterSpacing: </span><span style="color:#79B8FF">0.05</span></span>
155
+ <span class="line"><span style="color:#E1E4E8"> }</span></span>
156
+ <span class="line"><span style="color:#E1E4E8"> )}</span></span>
157
+ <span class="line"><span style="color:#E1E4E8"> &lt;/</span><span style="color:#85E89D">div</span><span style="color:#E1E4E8">&gt;</span></span>
158
+ <span class="line"><span style="color:#E1E4E8"> );</span></span>
159
+ <span class="line"><span style="color:#E1E4E8">}</span></span>
160
+ <span class="line"></span></code></pre>
161
+ <h3 id="available-functions">Available Functions</h3>
162
+ <p>All <code>textPath</code> functions return an array of positioned character elements:</p>
163
+ <p><strong><code>textPath.onCircle(text, cx, cy, radius, offset, options?)</code></strong></p>
164
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// Text around a circle</span></span>
165
+ <span class="line"><span style="color:#E1E4E8">textPath.</span><span style="color:#B392F0">onCircle</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&quot;HELLO WORLD&quot;</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">960</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">540</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">, {</span></span>
166
+ <span class="line"><span style="color:#E1E4E8"> fontSize: </span><span style="color:#9ECBFF">&quot;4xl&quot;</span><span style="color:#E1E4E8">,</span></span>
167
+ <span class="line"><span style="color:#E1E4E8"> color: </span><span style="color:#9ECBFF">&quot;white&quot;</span></span>
168
+ <span class="line"><span style="color:#E1E4E8">})</span></span>
169
+ <span class="line"></span></code></pre>
170
+ <p><strong><code>textPath.onPath(text, pathFollower, options?)</code></strong></p>
171
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// Text along any custom path</span></span>
172
+ <span class="line"><span style="color:#E1E4E8">textPath.</span><span style="color:#B392F0">onPath</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&quot;CUSTOM PATH&quot;</span><span style="color:#E1E4E8">, (</span><span style="color:#FFAB70">t</span><span style="color:#E1E4E8">) </span><span style="color:#F97583">=&gt;</span><span style="color:#E1E4E8"> ({</span></span>
173
+ <span class="line"><span style="color:#E1E4E8"> x: </span><span style="color:#79B8FF">100</span><span style="color:#F97583"> +</span><span style="color:#E1E4E8"> t </span><span style="color:#F97583">*</span><span style="color:#79B8FF"> 800</span><span style="color:#E1E4E8">,</span></span>
174
+ <span class="line"><span style="color:#E1E4E8"> y: </span><span style="color:#79B8FF">200</span><span style="color:#F97583"> +</span><span style="color:#E1E4E8"> Math.</span><span style="color:#B392F0">sin</span><span style="color:#E1E4E8">(t </span><span style="color:#F97583">*</span><span style="color:#E1E4E8"> Math.</span><span style="color:#79B8FF">PI</span><span style="color:#E1E4E8">) </span><span style="color:#F97583">*</span><span style="color:#79B8FF"> 100</span><span style="color:#E1E4E8">,</span></span>
175
+ <span class="line"><span style="color:#E1E4E8"> angle: Math.</span><span style="color:#B392F0">cos</span><span style="color:#E1E4E8">(t </span><span style="color:#F97583">*</span><span style="color:#E1E4E8"> Math.</span><span style="color:#79B8FF">PI</span><span style="color:#E1E4E8">) </span><span style="color:#F97583">*</span><span style="color:#79B8FF"> 20</span></span>
176
+ <span class="line"><span style="color:#E1E4E8">}), {</span></span>
177
+ <span class="line"><span style="color:#E1E4E8"> fontSize: </span><span style="color:#9ECBFF">&quot;2xl&quot;</span><span style="color:#E1E4E8">,</span></span>
178
+ <span class="line"><span style="color:#E1E4E8"> fontWeight: </span><span style="color:#9ECBFF">&quot;semibold&quot;</span></span>
179
+ <span class="line"><span style="color:#E1E4E8">})</span></span>
180
+ <span class="line"></span></code></pre>
181
+ <p><strong><code>textPath.onQuadratic(text, p0, p1, p2, options?)</code></strong></p>
182
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// Text along a quadratic Bezier curve</span></span>
183
+ <span class="line"><span style="color:#E1E4E8">textPath.</span><span style="color:#B392F0">onQuadratic</span><span style="color:#E1E4E8">(</span></span>
184
+ <span class="line"><span style="color:#9ECBFF"> &quot;CURVED TEXT&quot;</span><span style="color:#E1E4E8">,</span></span>
185
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">200</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// start</span></span>
186
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">960</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">100</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// control point</span></span>
187
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">1720</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// end</span></span>
188
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;3xl&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;blue-300&quot;</span><span style="color:#E1E4E8"> }</span></span>
189
+ <span class="line"><span style="color:#E1E4E8">)</span></span>
190
+ <span class="line"></span></code></pre>
191
+ <p><strong><code>textPath.onCubic(text, p0, p1, p2, p3, options?)</code></strong></p>
192
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// Text along a cubic Bezier curve</span></span>
193
+ <span class="line"><span style="color:#E1E4E8">textPath.</span><span style="color:#B392F0">onCubic</span><span style="color:#E1E4E8">(</span></span>
194
+ <span class="line"><span style="color:#9ECBFF"> &quot;S-CURVE&quot;</span><span style="color:#E1E4E8">,</span></span>
195
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">200</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">600</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// start</span></span>
196
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">600</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// control 1</span></span>
197
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">1320</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">800</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// control 2</span></span>
198
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">1720</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">600</span><span style="color:#E1E4E8"> }, </span><span style="color:#6A737D">// end</span></span>
199
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;3xl&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;purple-300&quot;</span><span style="color:#E1E4E8"> }</span></span>
200
+ <span class="line"><span style="color:#E1E4E8">)</span></span>
201
+ <span class="line"></span></code></pre>
202
+ <p><strong><code>textPath.onArc(text, cx, cy, radius, startAngle, endAngle, options?)</code></strong></p>
203
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// Text along a circular arc</span></span>
204
+ <span class="line"><span style="color:#E1E4E8">textPath.</span><span style="color:#B392F0">onArc</span><span style="color:#E1E4E8">(</span></span>
205
+ <span class="line"><span style="color:#9ECBFF"> &quot;ARC TEXT&quot;</span><span style="color:#E1E4E8">,</span></span>
206
+ <span class="line"><span style="color:#79B8FF"> 960</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// center x</span></span>
207
+ <span class="line"><span style="color:#79B8FF"> 540</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// center y</span></span>
208
+ <span class="line"><span style="color:#79B8FF"> 400</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// radius</span></span>
209
+ <span class="line"><span style="color:#79B8FF"> 0</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// start angle (degrees)</span></span>
210
+ <span class="line"><span style="color:#79B8FF"> 180</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// end angle (degrees)</span></span>
211
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;2xl&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;pink-300&quot;</span><span style="color:#E1E4E8"> }</span></span>
212
+ <span class="line"><span style="color:#E1E4E8">)</span></span>
213
+ <span class="line"></span></code></pre>
214
+ <h3 id="options">Options</h3>
215
+ <p>All <code>textPath</code> functions accept an optional <code>options</code> object:</p>
216
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="typescript"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
217
+ <span class="line"><span style="color:#E1E4E8"> fontSize</span><span style="color:#F97583">?:</span><span style="color:#E1E4E8"> string; </span><span style="color:#6A737D">// Tailwind size: &quot;xl&quot;, &quot;2xl&quot;, &quot;4xl&quot;, etc.</span></span>
218
+ <span class="line"><span style="color:#E1E4E8"> fontWeight</span><span style="color:#F97583">?:</span><span style="color:#E1E4E8"> string; </span><span style="color:#6A737D">// Tailwind weight: &quot;bold&quot;, &quot;semibold&quot;, etc.</span></span>
219
+ <span class="line"><span style="color:#E1E4E8"> color</span><span style="color:#F97583">?:</span><span style="color:#E1E4E8"> string; </span><span style="color:#6A737D">// Tailwind color: &quot;white&quot;, &quot;blue-500&quot;, etc.</span></span>
220
+ <span class="line"><span style="color:#E1E4E8"> letterSpacing</span><span style="color:#F97583">?:</span><span style="color:#E1E4E8"> number; </span><span style="color:#6A737D">// Space between characters (0-1, default: 0)</span></span>
221
+ <span class="line"><span style="color:#E1E4E8"> style</span><span style="color:#F97583">?:</span><span style="color:#E1E4E8"> any; </span><span style="color:#6A737D">// Additional inline styles</span></span>
222
+ <span class="line"><span style="color:#E1E4E8">}</span></span>
223
+ <span class="line"></span></code></pre>
224
+ <h3 id="examples">Examples</h3>
225
+ <p><strong>Animated rotating text:</strong></p>
226
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> RotatingText</span><span style="color:#E1E4E8">({ </span><span style="color:#FFAB70">tw</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">textPath</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">progress</span><span style="color:#E1E4E8"> }) {</span></span>
227
+ <span class="line"><span style="color:#F97583"> return</span><span style="color:#E1E4E8"> (</span></span>
228
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">div</span><span style="color:#B392F0"> style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#B392F0">tw</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&#39;relative w-full h-full bg-black&#39;</span><span style="color:#E1E4E8">)}&gt;</span></span>
229
+ <span class="line"><span style="color:#E1E4E8"> {textPath.</span><span style="color:#B392F0">onCircle</span><span style="color:#E1E4E8">(</span></span>
230
+ <span class="line"><span style="color:#9ECBFF"> &quot;SPINNING • TEXT • &quot;</span><span style="color:#E1E4E8">,</span></span>
231
+ <span class="line"><span style="color:#79B8FF"> 960</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">540</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8">,</span></span>
232
+ <span class="line"><span style="color:#E1E4E8"> progress, </span><span style="color:#6A737D">// Rotate based on video progress</span></span>
233
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;3xl&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;yellow-300&quot;</span><span style="color:#E1E4E8"> }</span></span>
234
+ <span class="line"><span style="color:#E1E4E8"> )}</span></span>
235
+ <span class="line"><span style="color:#E1E4E8"> &lt;/</span><span style="color:#85E89D">div</span><span style="color:#E1E4E8">&gt;</span></span>
236
+ <span class="line"><span style="color:#E1E4E8"> );</span></span>
237
+ <span class="line"><span style="color:#E1E4E8">}</span></span>
238
+ <span class="line"></span></code></pre>
239
+ <p><strong>Multiple text paths:</strong></p>
240
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> MultiPath</span><span style="color:#E1E4E8">({ </span><span style="color:#FFAB70">tw</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">textPath</span><span style="color:#E1E4E8"> }) {</span></span>
241
+ <span class="line"><span style="color:#F97583"> return</span><span style="color:#E1E4E8"> (</span></span>
242
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">div</span><span style="color:#B392F0"> style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#B392F0">tw</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&#39;relative w-full h-full bg-gradient-to-br from-slate-900 to-slate-700&#39;</span><span style="color:#E1E4E8">)}&gt;</span></span>
243
+ <span class="line"><span style="color:#E1E4E8"> {</span><span style="color:#6A737D">/* Text on outer circle */</span><span style="color:#E1E4E8">}</span></span>
244
+ <span class="line"><span style="color:#E1E4E8"> {textPath.</span><span style="color:#B392F0">onCircle</span><span style="color:#E1E4E8">(</span></span>
245
+ <span class="line"><span style="color:#9ECBFF"> &quot;OUTER RING&quot;</span><span style="color:#E1E4E8">,</span></span>
246
+ <span class="line"><span style="color:#79B8FF"> 960</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">540</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">500</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">,</span></span>
247
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;5xl&quot;</span><span style="color:#E1E4E8">, fontWeight: </span><span style="color:#9ECBFF">&quot;bold&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;white&quot;</span><span style="color:#E1E4E8"> }</span></span>
248
+ <span class="line"><span style="color:#E1E4E8"> )}</span></span>
249
+ <span class="line"></span>
250
+ <span class="line"><span style="color:#E1E4E8"> {</span><span style="color:#6A737D">/* Text on inner circle */</span><span style="color:#E1E4E8">}</span></span>
251
+ <span class="line"><span style="color:#E1E4E8"> {textPath.</span><span style="color:#B392F0">onCircle</span><span style="color:#E1E4E8">(</span></span>
252
+ <span class="line"><span style="color:#9ECBFF"> &quot;inner ring&quot;</span><span style="color:#E1E4E8">,</span></span>
253
+ <span class="line"><span style="color:#79B8FF"> 960</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">540</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">300</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">0.5</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// offset by 50% for rotation</span></span>
254
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;2xl&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;white/60&quot;</span><span style="color:#E1E4E8"> }</span></span>
255
+ <span class="line"><span style="color:#E1E4E8"> )}</span></span>
256
+ <span class="line"><span style="color:#E1E4E8"> &lt;/</span><span style="color:#85E89D">div</span><span style="color:#E1E4E8">&gt;</span></span>
257
+ <span class="line"><span style="color:#E1E4E8"> );</span></span>
258
+ <span class="line"><span style="color:#E1E4E8">}</span></span>
259
+ <span class="line"></span></code></pre>
260
+ <p><strong>Text following a drawn path:</strong></p>
261
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> PathText</span><span style="color:#E1E4E8">({ </span><span style="color:#FFAB70">tw</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">textPath</span><span style="color:#E1E4E8"> }) {</span></span>
262
+ <span class="line"><span style="color:#F97583"> return</span><span style="color:#E1E4E8"> (</span></span>
263
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">div</span><span style="color:#B392F0"> style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#B392F0">tw</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">&#39;relative w-full h-full bg-gray-900&#39;</span><span style="color:#E1E4E8">)}&gt;</span></span>
264
+ <span class="line"><span style="color:#E1E4E8"> {</span><span style="color:#6A737D">/* Draw the path */</span><span style="color:#E1E4E8">}</span></span>
265
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">svg</span><span style="color:#B392F0"> width</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">&quot;1920&quot;</span><span style="color:#B392F0"> height</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">&quot;1080&quot;</span><span style="color:#B392F0"> style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{{ position: </span><span style="color:#9ECBFF">&#39;absolute&#39;</span><span style="color:#E1E4E8"> }}&gt;</span></span>
266
+ <span class="line"><span style="color:#E1E4E8"> &lt;</span><span style="color:#85E89D">path</span></span>
267
+ <span class="line"><span style="color:#B392F0"> d</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">&quot;M 200 400 Q 960 150 1720 400&quot;</span></span>
268
+ <span class="line"><span style="color:#B392F0"> stroke</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">&quot;rgba(255,255,255,0.2)&quot;</span></span>
269
+ <span class="line"><span style="color:#B392F0"> strokeWidth</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#79B8FF">2</span><span style="color:#E1E4E8">}</span></span>
270
+ <span class="line"><span style="color:#B392F0"> fill</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">&quot;none&quot;</span></span>
271
+ <span class="line"><span style="color:#E1E4E8"> /&gt;</span></span>
272
+ <span class="line"><span style="color:#E1E4E8"> &lt;/</span><span style="color:#85E89D">svg</span><span style="color:#E1E4E8">&gt;</span></span>
273
+ <span class="line"></span>
274
+ <span class="line"><span style="color:#E1E4E8"> {</span><span style="color:#6A737D">/* Text following the path */</span><span style="color:#E1E4E8">}</span></span>
275
+ <span class="line"><span style="color:#E1E4E8"> {textPath.</span><span style="color:#B392F0">onQuadratic</span><span style="color:#E1E4E8">(</span></span>
276
+ <span class="line"><span style="color:#9ECBFF"> &quot;FOLLOWING THE CURVE&quot;</span><span style="color:#E1E4E8">,</span></span>
277
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">200</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8"> },</span></span>
278
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">960</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">150</span><span style="color:#E1E4E8"> },</span></span>
279
+ <span class="line"><span style="color:#E1E4E8"> { x: </span><span style="color:#79B8FF">1720</span><span style="color:#E1E4E8">, y: </span><span style="color:#79B8FF">400</span><span style="color:#E1E4E8"> },</span></span>
280
+ <span class="line"><span style="color:#E1E4E8"> { fontSize: </span><span style="color:#9ECBFF">&quot;3xl&quot;</span><span style="color:#E1E4E8">, fontWeight: </span><span style="color:#9ECBFF">&quot;bold&quot;</span><span style="color:#E1E4E8">, color: </span><span style="color:#9ECBFF">&quot;blue-300&quot;</span><span style="color:#E1E4E8"> }</span></span>
281
+ <span class="line"><span style="color:#E1E4E8"> )}</span></span>
282
+ <span class="line"><span style="color:#E1E4E8"> &lt;/</span><span style="color:#85E89D">div</span><span style="color:#E1E4E8">&gt;</span></span>
283
+ <span class="line"><span style="color:#E1E4E8"> );</span></span>
284
+ <span class="line"><span style="color:#E1E4E8">}</span></span>
285
+ <span class="line"></span></code></pre>
286
+ <p>For animated text paths, see <a href="/animation#text-path-animations">Text Path Animations</a>.</p>
287
+ <h2 id="reserved-prop-names">Reserved Prop Names</h2>
288
+ <p>The following prop names are <strong>reserved</strong> and cannot be used in your template’s <code>meta.props</code>:</p>
289
+ <ul>
290
+ <li><code>tw</code>, <code>qr</code>, <code>image</code>, <code>template</code> - Core helpers</li>
291
+ <li><code>path</code>, <code>textPath</code> - Path and text helpers</li>
292
+ <li><code>config</code>, <code>frame</code>, <code>progress</code> - System props</li>
293
+ </ul>
294
+ <p><strong>Why?</strong> These names are used for loopwind’s built-in helpers. Using them as prop names would cause conflicts.</p>
295
+ <p><strong>Example:</strong></p>
296
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#6A737D">// ❌ BAD - &#39;image&#39; is reserved</span></span>
297
+ <span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> const</span><span style="color:#79B8FF"> meta</span><span style="color:#F97583"> =</span><span style="color:#E1E4E8"> {</span></span>
298
+ <span class="line"><span style="color:#E1E4E8"> props: {</span></span>
299
+ <span class="line"><span style="color:#E1E4E8"> title: </span><span style="color:#9ECBFF">&quot;string&quot;</span><span style="color:#E1E4E8">,</span></span>
300
+ <span class="line"><span style="color:#E1E4E8"> image: </span><span style="color:#9ECBFF">&quot;string&quot;</span><span style="color:#6A737D"> // Error!</span></span>
301
+ <span class="line"><span style="color:#E1E4E8"> }</span></span>
302
+ <span class="line"><span style="color:#E1E4E8">};</span></span>
303
+ <span class="line"></span>
304
+ <span class="line"><span style="color:#6A737D">// ✅ GOOD - Use descriptive alternatives</span></span>
305
+ <span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> const</span><span style="color:#79B8FF"> meta</span><span style="color:#F97583"> =</span><span style="color:#E1E4E8"> {</span></span>
306
+ <span class="line"><span style="color:#E1E4E8"> props: {</span></span>
307
+ <span class="line"><span style="color:#E1E4E8"> title: </span><span style="color:#9ECBFF">&quot;string&quot;</span><span style="color:#E1E4E8">,</span></span>
308
+ <span class="line"><span style="color:#E1E4E8"> imageUrl: </span><span style="color:#9ECBFF">&quot;string&quot;</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// or imageSrc, photoUrl, etc.</span></span>
309
+ <span class="line"><span style="color:#E1E4E8"> logoUrl: </span><span style="color:#9ECBFF">&quot;string&quot;</span></span>
310
+ <span class="line"><span style="color:#E1E4E8"> }</span></span>
311
+ <span class="line"><span style="color:#E1E4E8">};</span></span>
312
+ <span class="line"></span></code></pre>
313
+ <p>If you try to use a reserved name, you’ll get a helpful error:</p>
314
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="plaintext"><code><span class="line"><span>Template uses reserved prop names: image</span></span>
315
+ <span class="line"><span></span></span>
316
+ <span class="line"><span>Try renaming: &quot;image&quot; → &quot;imageUrl&quot; or &quot;imageSrc&quot;</span></span>
317
+ <span class="line"><span></span></span>
318
+ <span class="line"><span>Reserved names: tw, qr, image, template, path, textPath, config, frame, progress</span></span>
319
+ <span class="line"><span></span></span></code></pre>
136
320
  <h2 id="all-props-reference">All Props Reference</h2>
137
321
  <p>Every template receives these props:</p>
138
- <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> MyTemplate</span><span style="color:#E1E4E8">({ </span></span>
139
- <span class="line"><span style="color:#6A737D"> // Core helpers</span></span>
322
+ <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> MyTemplate</span><span style="color:#E1E4E8">({</span></span>
323
+ <span class="line"><span style="color:#6A737D"> // Core helpers (RESERVED - cannot be used as prop names)</span></span>
140
324
  <span class="line"><span style="color:#FFAB70"> tw</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Tailwind class converter</span></span>
141
325
  <span class="line"><span style="color:#FFAB70"> qr</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// QR code generator (this page)</span></span>
142
326
  <span class="line"><span style="color:#FFAB70"> template</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Template composer (this page)</span></span>
143
327
  <span class="line"><span style="color:#FFAB70"> config</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// User config from loopwind.json (this page)</span></span>
144
- <span class="line"><span style="color:#E1E4E8"> </span></span>
145
- <span class="line"><span style="color:#6A737D"> // Media helpers (see dedicated pages)</span></span>
328
+ <span class="line"><span style="color:#FFAB70"> textPath</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Text on path helpers (this page)</span></span>
329
+ <span class="line"></span>
330
+ <span class="line"><span style="color:#6A737D"> // Media helpers (RESERVED)</span></span>
146
331
  <span class="line"><span style="color:#FFAB70"> image</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Image embedder → see /images</span></span>
332
+ <span class="line"><span style="color:#FFAB70"> path</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Path following → see /animation</span></span>
147
333
  <span class="line"></span>
148
- <span class="line"><span style="color:#6A737D"> // Video-specific (only in video templates)</span></span>
334
+ <span class="line"><span style="color:#6A737D"> // Video-specific (RESERVED - only in video templates)</span></span>
149
335
  <span class="line"><span style="color:#FFAB70"> frame</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Current frame number → see /video</span></span>
150
336
  <span class="line"><span style="color:#FFAB70"> progress</span><span style="color:#E1E4E8">, </span><span style="color:#6A737D">// Animation progress 0-1 → see /video</span></span>
151
- <span class="line"><span style="color:#E1E4E8"> </span></span>
152
- <span class="line"><span style="color:#6A737D"> // Your custom props</span></span>
153
- <span class="line"><span style="color:#F97583"> ...</span><span style="color:#FFAB70">props</span><span style="color:#6A737D"> // Any props from your props.json</span></span>
337
+ <span class="line"></span>
338
+ <span class="line"><span style="color:#6A737D"> // Your custom props (use any names EXCEPT the reserved ones above)</span></span>
339
+ <span class="line"><span style="color:#F97583"> ...</span><span style="color:#FFAB70">props</span><span style="color:#6A737D"> // Any props from your meta.props</span></span>
154
340
  <span class="line"><span style="color:#E1E4E8">}) {</span></span>
155
341
  <span class="line"><span style="color:#6A737D"> // Your template code</span></span>
156
342
  <span class="line"><span style="color:#E1E4E8">}</span></span>
@@ -1,5 +1,7 @@
1
- <!DOCTYPE html><html lang="en" data-astro-cid-mw7aashj> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v4.16.19"><link rel="canonical" href="https://loopwind.dev/images/"><!-- Primary Meta Tags --><title></title><meta name="title"><meta name="description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="keywords" content="loopwind, image generation, video generation, React, Tailwind CSS, Satori, CLI tool, templates, shadcn/ui, AI agents, Cursor, automation, serverless, WASM, Open Graph, social media, marketing automation"><meta name="author" content="loopwind"><!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://loopwind.dev/images/"><meta property="og:title"><meta property="og:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta property="og:image" content="https://loopwind.dev/api/og/images"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:alt"><meta property="og:site_name" content="loopwind"><meta property="og:locale" content="en_US"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://loopwind.dev/images/"><meta name="twitter:title"><meta name="twitter:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="twitter:image" content="https://loopwind.dev/api/og/images"><meta name="twitter:image:alt"><meta name="twitter:creator" content="@loopwind"><meta name="twitter:site" content="@loopwind"><!-- Theme Color --><meta name="theme-color" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#fafafa"><!-- Additional SEO --><meta name="robots" content="index, follow"><meta name="googlebot" content="index, follow"><meta name="language" content="English"><meta name="revisit-after" content="7 days"><meta name="rating" content="general"><!-- Mobile Web App --><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="loopwind"><!-- Structured Data (JSON-LD) --><script type="application/ld+json">{"@context":"https://schema.org","@type":"SoftwareApplication","name":"loopwind","applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","description":"CLI-based Image & Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates.","url":"https://loopwind.dev/","author":{"@type":"Organization","name":"loopwind","url":"https://loopwind.dev/"},"offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"softwareVersion":"0.11.0","releaseNotes":"https://github.com/loopwind/loopwind/releases","screenshot":"https://loopwind.dev/api/og/images","featureList":["Image generation from React templates","Video generation with animations","Tailwind CSS support","shadcn/ui design system","CLI-based workflow","Serverless rendering","TypeScript support","AI Agent friendly"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"loopwind","url":"https://loopwind.dev/","logo":"https://loopwind.dev/favicon.svg","sameAs":["https://github.com/loopwind/loopwind","https://www.npmjs.com/package/loopwind"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://loopwind.dev/"},{"@type":"ListItem","position":2,"name":"Images","item":"https://loopwind.dev/images"}]}</script><link rel="stylesheet" href="/_astro/agents.Yx-L_igG.css"><script type="module">const p=document.getElementById("mobile-menu-button"),l=document.getElementById("mobile-menu"),g=document.querySelectorAll(".mobile-menu-link");p?.addEventListener("click",()=>{l?.classList.toggle("hidden")});l?.addEventListener("click",o=>{o.target===l&&l.classList.add("hidden")});g.forEach(o=>{o.addEventListener("click",()=>{l?.classList.add("hidden")})});function m(){const o=document.getElementById("toc-nav");if(!o){console.log("TOC: No toc-nav element found");return}const n=document.querySelector("article");if(!n){console.log("TOC: No article element found");return}const c=n.querySelectorAll("h2, h3");if(c.length===0){console.log("TOC: No headings found");return}console.log(`TOC: Found ${c.length} headings`);const a=document.createElement("ul");a.className="space-y-0 text-sm border-l border-border/50",c.forEach(e=>{const t=e.tagName==="H2"?2:3,r=e.id||e.textContent?.toLowerCase().replace(/[^\w]+/g,"-");!e.id&&r&&(e.id=r);const s=document.createElement("li"),d=document.createElement("a");d.href=`#${r}`,d.textContent=e.textContent,d.className=`toc-link block py-1 px-3 -ml-px border-l-2 border-transparent transition-all no-underline ${t===3?"pl-6 text-xs text-muted-foreground/70":"text-sm text-muted-foreground"} hover:text-foreground hover:border-muted-foreground/50`,s.appendChild(d),a.appendChild(s)}),o.appendChild(a);const i=new IntersectionObserver(e=>{e.forEach(t=>{const r=t.target.id,s=o.querySelector(`a[href="#${r}"]`);t.isIntersecting&&(document.querySelectorAll(".toc-link").forEach(d=>{d.classList.remove("text-foreground","border-accent","font-medium")}),s?.classList.add("text-foreground","border-accent","font-medium"))})},{rootMargin:"-100px 0px -66%",threshold:0});c.forEach(e=>{i.observe(e)})}document.addEventListener("DOMContentLoaded",m);document.addEventListener("astro:page-load",m);function u(){const o=document.getElementById("copy-to-llm-btn"),n=document.getElementById("copy-btn-text");if(!o||!n){console.log("Copy to LLM: Button not found on this page");return}console.log("Copy to LLM: Initialized"),o.addEventListener("click",async()=>{const c=window.location.pathname,a=c.replace(/^\//,"").replace(/\/$/,""),e=`/api/raw-markdown/${a===""?"index":a}`;console.log("Copy to LLM clicked: pathname=",c,"apiUrl=",e);try{n.textContent="Copying...";const t=await fetch(e);if(console.log("Response status:",t.status),!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const r=await t.text();console.log("Got markdown, length:",r.length),await navigator.clipboard.writeText(r),n.textContent="Copied!",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}catch(t){console.error("Copy failed:",t),n.textContent="Failed",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}})}document.addEventListener("DOMContentLoaded",u);document.addEventListener("astro:page-load",u);
2
- </script></head> <body class="antialiased" data-astro-cid-mw7aashj> <div class="min-h-screen" data-astro-cid-mw7aashj> <!-- Mobile Header --> <header class="mobile-header fixed top-0 left-0 right-0 h-16 bg-card border-b border-border z-50 md:hidden" data-astro-cid-mw7aashj> <div class="flex items-center justify-between h-full px-4" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-2xl">➰</span> <span>loopwind</span> </h1> </a> <button id="mobile-menu-button" class="p-2 text-foreground hover:bg-accent rounded-md transition-colors" aria-label="Toggle menu" data-astro-cid-mw7aashj> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-mw7aashj></path> </svg> </button> </div> </header> <!-- Mobile Menu Overlay --> <div id="mobile-menu" class="mobile-menu fixed inset-0 bg-background/80 backdrop-blur-sm z-40 md:hidden hidden" data-astro-cid-mw7aashj> <div class="fixed top-0 left-0 h-screen w-64 bg-card border-r border-border overflow-y-auto" data-astro-cid-mw7aashj> <div class="p-6 pt-20" data-astro-cid-mw7aashj> <nav data-astro-cid-mw7aashj> <ul class="space-y-1" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </div> </div> <!-- Desktop Sidebar --> <aside class="desktop-sidebar fixed top-0 left-0 h-screen w-64 border-r border-border bg-card overflow-y-auto z-10" data-astro-cid-mw7aashj> <div class="p-6" data-astro-cid-mw7aashj> <div class="block mb-3" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-3xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-4xl">➰</span> <span>loopwind</span> </h1> </a> </div> <nav data-astro-cid-mw7aashj> <ul class="space-y-0" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </aside> <!-- Main content --> <main class="ml-64 mr-64" data-astro-cid-mw7aashj> <div class="p-12" data-astro-cid-mw7aashj> <button id="copy-to-llm-btn" class="mb-6 px-4 py-2 bg-accent hover:bg-accent/80 text-accent-foreground rounded-md text-sm font-medium transition-colors flex items-center gap-2" aria-label="Copy raw markdown to clipboard" data-astro-cid-mw7aashj> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" data-astro-cid-mw7aashj></path> </svg> <span id="copy-btn-text" data-astro-cid-mw7aashj>Copy to LLM</span> </button> <article class="prose prose-invert max-w-4xl" data-astro-cid-mw7aashj> <h1 id="image-rendering">Image Rendering</h1>
1
+ <!DOCTYPE html><html lang="en" data-astro-cid-mw7aashj> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v4.16.19"><link rel="canonical" href="https://loopwind.dev/images/"><!-- Primary Meta Tags --><title></title><meta name="title"><meta name="description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="keywords" content="loopwind, image generation, video generation, React, Tailwind CSS, Satori, CLI tool, templates, shadcn/ui, AI agents, Cursor, automation, serverless, WASM, Open Graph, social media, marketing automation"><meta name="author" content="loopwind"><!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://loopwind.dev/images/"><meta property="og:title"><meta property="og:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta property="og:image" content="https://loopwind.dev/api/og/images"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:alt"><meta property="og:site_name" content="loopwind"><meta property="og:locale" content="en_US"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://loopwind.dev/images/"><meta name="twitter:title"><meta name="twitter:description" content="CLI-based Image &#38; Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates."><meta name="twitter:image" content="https://loopwind.dev/api/og/images"><meta name="twitter:image:alt"><meta name="twitter:creator" content="@loopwind"><meta name="twitter:site" content="@loopwind"><!-- Theme Color --><meta name="theme-color" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0a0a0a"><meta name="theme-color" media="(prefers-color-scheme: light)" content="#fafafa"><!-- Additional SEO --><meta name="robots" content="index, follow"><meta name="googlebot" content="index, follow"><meta name="language" content="English"><meta name="revisit-after" content="7 days"><meta name="rating" content="general"><!-- Mobile Web App --><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="loopwind"><!-- Structured Data (JSON-LD) --><script type="application/ld+json">{"@context":"https://schema.org","@type":"SoftwareApplication","name":"loopwind","applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","description":"CLI-based Image & Video Generator for developers and AI Agents. Generate stunning visuals from React + Tailwind templates.","url":"https://loopwind.dev/","author":{"@type":"Organization","name":"loopwind","url":"https://loopwind.dev/"},"offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"softwareVersion":"0.11.0","releaseNotes":"https://github.com/loopwind/loopwind/releases","screenshot":"https://loopwind.dev/api/og/images","featureList":["Image generation from React templates","Video generation with animations","Tailwind CSS support","shadcn/ui design system","CLI-based workflow","Serverless rendering","TypeScript support","AI Agent friendly"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"loopwind","url":"https://loopwind.dev/","logo":"https://loopwind.dev/favicon.svg","sameAs":["https://github.com/loopwind/loopwind","https://www.npmjs.com/package/loopwind"]}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://loopwind.dev/"},{"@type":"ListItem","position":2,"name":"Images","item":"https://loopwind.dev/images"}]}</script><link rel="stylesheet" href="/_astro/agents.CZXv4DCM.css">
2
+ <style>.hero[data-astro-cid-bbe6dxrz]{position:relative}html{scroll-behavior:smooth}.mobile-header[data-astro-cid-mw7aashj]{display:none}.toc-sidebar[data-astro-cid-mw7aashj]{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.1) transparent}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar{width:4px}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-track{background:transparent}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-thumb{background-color:#ffffff1a;border-radius:2px}.toc-sidebar[data-astro-cid-mw7aashj]::-webkit-scrollbar-thumb:hover{background-color:#fff3}#copy-to-llm-btn[data-astro-cid-mw7aashj]{cursor:pointer}@media (max-width: 768px){.mobile-header[data-astro-cid-mw7aashj]{display:block}.desktop-sidebar[data-astro-cid-mw7aashj]{display:none}main[data-astro-cid-mw7aashj]{margin-left:0;margin-right:0!important;padding:5rem 1.5rem 1.5rem}.toc-sidebar[data-astro-cid-mw7aashj]{display:none}#copy-to-llm-btn[data-astro-cid-mw7aashj]{width:100%;justify-content:center}}@media (max-width: 1280px){.toc-sidebar[data-astro-cid-mw7aashj]{display:none!important}main[data-astro-cid-mw7aashj]{margin-right:0!important}}
3
+ </style><script type="module">const p=document.getElementById("mobile-menu-button"),l=document.getElementById("mobile-menu"),g=document.querySelectorAll(".mobile-menu-link");p?.addEventListener("click",()=>{l?.classList.toggle("hidden")});l?.addEventListener("click",o=>{o.target===l&&l.classList.add("hidden")});g.forEach(o=>{o.addEventListener("click",()=>{l?.classList.add("hidden")})});function m(){const o=document.getElementById("toc-nav");if(!o){console.log("TOC: No toc-nav element found");return}const n=document.querySelector("article");if(!n){console.log("TOC: No article element found");return}const c=n.querySelectorAll("h2, h3");if(c.length===0){console.log("TOC: No headings found");return}console.log(`TOC: Found ${c.length} headings`);const a=document.createElement("ul");a.className="space-y-0 text-sm border-l border-border/50",c.forEach(e=>{const t=e.tagName==="H2"?2:3,r=e.id||e.textContent?.toLowerCase().replace(/[^\w]+/g,"-");!e.id&&r&&(e.id=r);const s=document.createElement("li"),d=document.createElement("a");d.href=`#${r}`,d.textContent=e.textContent,d.className=`toc-link block py-1 px-3 -ml-px border-l-2 border-transparent transition-all no-underline ${t===3?"pl-6 text-xs text-muted-foreground/70":"text-sm text-muted-foreground"} hover:text-foreground hover:border-muted-foreground/50`,s.appendChild(d),a.appendChild(s)}),o.appendChild(a);const i=new IntersectionObserver(e=>{e.forEach(t=>{const r=t.target.id,s=o.querySelector(`a[href="#${r}"]`);t.isIntersecting&&(document.querySelectorAll(".toc-link").forEach(d=>{d.classList.remove("text-foreground","border-accent","font-medium")}),s?.classList.add("text-foreground","border-accent","font-medium"))})},{rootMargin:"-100px 0px -66%",threshold:0});c.forEach(e=>{i.observe(e)})}document.addEventListener("DOMContentLoaded",m);document.addEventListener("astro:page-load",m);function u(){const o=document.getElementById("copy-to-llm-btn"),n=document.getElementById("copy-btn-text");if(!o||!n){console.log("Copy to LLM: Button not found on this page");return}console.log("Copy to LLM: Initialized"),o.addEventListener("click",async()=>{const c=window.location.pathname,a=c.replace(/^\//,"").replace(/\/$/,""),e=`/api/raw-markdown/${a===""?"index":a}`;console.log("Copy to LLM clicked: pathname=",c,"apiUrl=",e);try{n.textContent="Copying...";const t=await fetch(e);if(console.log("Response status:",t.status),!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const r=await t.text();console.log("Got markdown, length:",r.length),await navigator.clipboard.writeText(r),n.textContent="Copied!",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}catch(t){console.error("Copy failed:",t),n.textContent="Failed",setTimeout(()=>{n.textContent="Copy to LLM"},2e3)}})}document.addEventListener("DOMContentLoaded",u);document.addEventListener("astro:page-load",u);
4
+ </script></head> <body class="antialiased" data-astro-cid-mw7aashj> <div class="min-h-screen" data-astro-cid-mw7aashj> <!-- Mobile Header --> <header class="mobile-header fixed top-0 left-0 right-0 h-16 bg-card border-b border-border z-50 md:hidden" data-astro-cid-mw7aashj> <div class="flex items-center justify-between h-full px-4" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-2xl">➰</span> <span>loopwind</span> </h1> </a> <button id="mobile-menu-button" class="p-2 text-foreground hover:bg-accent rounded-md transition-colors" aria-label="Toggle menu" data-astro-cid-mw7aashj> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-mw7aashj></path> </svg> </button> </div> </header> <!-- Mobile Menu Overlay --> <div id="mobile-menu" class="mobile-menu fixed inset-0 bg-background/80 backdrop-blur-sm z-40 md:hidden hidden" data-astro-cid-mw7aashj> <div class="fixed top-0 left-0 h-screen w-64 bg-card border-r border-border overflow-y-auto" data-astro-cid-mw7aashj> <div class="p-6 pt-20" data-astro-cid-mw7aashj> <nav data-astro-cid-mw7aashj> <ul class="space-y-1" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/playground" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Playground </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="mobile-menu-link block px-3 py-2 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </div> </div> <!-- Desktop Sidebar --> <aside class="desktop-sidebar fixed top-0 left-0 h-screen w-64 border-r border-border bg-card overflow-y-auto z-10" data-astro-cid-mw7aashj> <div class="p-6" data-astro-cid-mw7aashj> <div class="block mb-3" data-astro-cid-mw7aashj> <a href="/" class="no-underline"> <h1 class="text-3xl flex items-center gap-2 bg-linear-to-r from-brand-from to-brand-to bg-clip-text text-transparent"> <span class="text-4xl">➰</span> <span>loopwind</span> </h1> </a> </div> <nav data-astro-cid-mw7aashj> <ul class="space-y-0" data-astro-cid-mw7aashj> <li data-astro-cid-mw7aashj> <a href="/" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Home </a> </li><li data-astro-cid-mw7aashj> <a href="/getting-started" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Getting Started </a> </li><li data-astro-cid-mw7aashj> <a href="/templates" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Templates </a> </li><li data-astro-cid-mw7aashj> <a href="/images" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Images </a> </li><li data-astro-cid-mw7aashj> <a href="/video" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Video </a> </li><li data-astro-cid-mw7aashj> <a href="/preview" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Preview </a> </li><li data-astro-cid-mw7aashj> <a href="/animation" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Animation </a> </li><li data-astro-cid-mw7aashj> <a href="/helpers" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Helpers </a> </li><li data-astro-cid-mw7aashj> <a href="/styling" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Styling </a> </li><li data-astro-cid-mw7aashj> <a href="/fonts" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Fonts </a> </li><li data-astro-cid-mw7aashj> <a href="/config" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> loopwind.json </a> </li><li data-astro-cid-mw7aashj> <a href="/sdk" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> SDK </a> </li><li data-astro-cid-mw7aashj> <a href="/playground" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Playground </a> </li><li data-astro-cid-mw7aashj> <a href="/agents" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> Use with AI Agents </a> </li><li data-astro-cid-mw7aashj> <a href="/llm.txt" class="block px-3 py-1.5 rounded-md text-sm transition-colors no-underline text-muted-foreground hover:text-foreground hover:bg-accent/50" data-astro-cid-mw7aashj> llm.txt ⇱ </a> </li> </ul> </nav> </div> </aside> <!-- Main content --> <main class="ml-64 mr-64" data-astro-cid-mw7aashj> <div class="p-12" data-astro-cid-mw7aashj> <button id="copy-to-llm-btn" class="mb-6 px-4 py-2 bg-accent hover:bg-accent/80 text-accent-foreground rounded-md text-sm font-medium transition-colors flex items-center gap-2" aria-label="Copy raw markdown to clipboard" data-astro-cid-mw7aashj> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-mw7aashj> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" data-astro-cid-mw7aashj></path> </svg> <span id="copy-btn-text" data-astro-cid-mw7aashj>Copy to LLM</span> </button> <article class="prose prose-invert max-w-4xl" data-astro-cid-mw7aashj> <h1 id="image-rendering">Image Rendering</h1>
3
5
  <p>Generate beautiful images from React components using loopwind’s powerful image rendering engine powered by Satori.</p>
4
6
  <h2 id="quick-start">Quick Start</h2>
5
7
  <pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D"># Render an image template with inline props</span></span>