[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C4XYDC6W16Y6KTY347S6ZC":3,"skill-same:01M6C4XYDC6W16Y6KTY347S6ZC":46},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":13,"repositoryHtmlUrl":27,"repositoryHomepageUrl":28,"ownerHtmlUrl":29,"ownerBlogUrl":30,"ownerDescription":6,"updatedAt":31,"install":32,"resources":45},"01M6C4XYDC6W16Y6KTY347S6ZC","astro-islands",null,"joshribakoff\u002Ffightingwithai.com","joshribakoff","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F4021306?v=4","01M6C4XRSWK3RV2R7FF1CH2FGA","Josh Ribakoff","01M6C4XRYAPRF3PM6E2VY4MNXM",0,"MIT","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fastro-islands\u002FSKILL.md",[],[18,19],"astro","astro islands","2026-11-10 10:12:30",false,"# Astro Islands Architecture Skill\n\n## When to Use This Skill\n\nUse this skill when:\n- Adding interactive components to Astro pages\n- Deciding between React, vanilla JS, or static HTML\n- Troubleshooting hydration errors\n- Optimizing JavaScript bundle size\n\n## Core Principle\n\n> **React is for composition and layout. Vanilla JS is for interactivity.**\n\nIn Astro, the best architecture ships minimal JavaScript:\n- Use React\u002Fcomponents for **SSR composition** (zero JS shipped)\n- Use vanilla JS for **simple interactions** (theme toggle, mobile menu)\n- Use `client:only` **sparingly** for complex widgets that truly need React state\n\n## Astro Client Directives\n\n| Directive | Server Renders? | Ships JS? | Use For |\n|-----------|-----------------|-----------|---------|\n| None | Yes | No | Static content, layouts |\n| `client:load` | Yes | Yes | Hydrates immediately (avoid if possible) |\n| `client:idle` | Yes | Yes | Hydrates when idle |\n| `client:visible` | Yes | Yes | Hydrates when visible |\n| `client:only=\"react\"` | No | Yes | Complex widgets, no SSR |\n\n## Architecture Patterns\n\n### Pattern 1: Pure SSR (Recommended for most content)\n\n```astro\n---\n\u002F\u002F index.astro\nimport { HomePage } from '..\u002Fcomponents\u002FHomePage';\nconst data = await fetchData();\n---\n\u003CHomePage data={data} \u002F>  \u003C!-- NO client directive = static HTML -->\n```\n\n**What you get:**\n- React components render to static HTML at build time\n- Zero JavaScript shipped\n- Fully testable in isolation\n- Fast page loads\n\n### Pattern 2: Vanilla JS for Simple Interactivity\n\n```astro\n---\n\u002F\u002F Layout.astro\n---\n\u003Cbutton id=\"theme-toggle\">Toggle Theme\u003C\u002Fbutton>\n\n\u003Cscript is:inline>\n  document.getElementById('theme-toggle').addEventListener('click', () => {\n    const current = document.documentElement.getAttribute('data-theme');\n    const next = current === 'dark' ? 'light' : 'dark';\n    document.documentElement.setAttribute('data-theme', next);\n    localStorage.setItem('theme', next);\n  });\n\u003C\u002Fscript>\n```\n\n**Use for:**\n- Theme toggles (~20 lines)\n- Mobile menu open\u002Fclose (~15 lines)\n- Simple form validation\n- Scroll-triggered animations\n\n**Benefits:**\n- ~0.5kb vs ~5kb+ for React hydration\n- No hydration bugs\n- Works immediately (no waiting for React to load)\n\n### Pattern 3: client:only for Complex Widgets (Last Resort)\n\n```astro\n---\n\u002F\u002F page.astro\nimport { PhotoGallery } from '..\u002Fcomponents\u002FPhotoGallery';\n---\n\u003C!-- Only when vanilla JS isn't sufficient -->\n\u003CPhotoGallery client:only=\"react\" photos={photos} \u002F>\n```\n\n**Use for:**\n- Complex state management\n- Heavy user interaction (drag-drop, canvas)\n- Third-party React libraries\n\n**Trade-offs:**\n- Ships React runtime (~5kb+)\n- Renders empty until JS loads\n- Cannot be nested inside SSR React\n\n## Critical Constraint\n\n### You CANNOT Nest Client Islands Inside SSR React\n\n```astro\n\u003C!-- THIS DOES NOT WORK -->\n\u003CHomePage data={data} \u002F>  \u003C!-- SSR React -->\n\u003Cscript>\n  \u002F\u002F Trying to mount React inside a div that HomePage rendered\n  createRoot(document.getElementById('widget-root')).render(\u003CWidget \u002F>);\n\u003C\u002Fscript>\n```\n\n**Error:** `@vitejs\u002Fplugin-react can't detect preamble`\n\n**Why:** Astro's React integration doesn't support split-brain React:\n- Part server-rendered\n- Part client-mounted into server-rendered placeholders\n\n**Solution:** Use vanilla JS for the interaction, or restructure so the interactive part is a sibling, not a child.\n\n## Decision Tree\n\n```\nNeed to render HTML?\n├── Yes → Use React component (no directive)\n│   └── Need interactivity?\n│       ├── Simple (toggle, menu) → Vanilla JS script\n│       └── Complex (gallery, forms) → Separate client:only component\n└── No → Why are you here?\n```\n\n## Performance Comparison\n\n| Approach | JS Shipped | Time to Interactive |\n|----------|------------|---------------------|\n| SSR React (no directive) | 0kb | Instant |\n| SSR + Vanilla JS | ~0.5kb | Instant |\n| SSR + client:load | ~5kb+ | After React loads |\n| client:only | ~5kb+ | After React loads |\n\n## Common Pitfalls\n\n### DON'T: Use client:load on Layout Components\n```astro\n\u003C!-- Bad: Ships React for static content -->\n\u003CLayout client:load>\n  \u003CContent \u002F>\n\u003C\u002FLayout>\n```\n\n### DON'T: Over-engineer Simple Interactions\n```astro\n\u003C!-- Bad: React for a toggle -->\n\u003CThemeToggle client:only=\"react\" \u002F>\n\n\u003C!-- Good: Vanilla JS -->\n\u003Cbutton id=\"theme-toggle\">Toggle\u003C\u002Fbutton>\n\u003Cscript is:inline>\u002F* 10 lines *\u002F\u003C\u002Fscript>\n```\n\n### DON'T: Mix Astro Components Inside React\n```tsx\n\u002F\u002F This DOES NOT WORK\nexport const Page = () => {\n  return \u003CAstroComponent \u002F>;  \u002F\u002F Can't import .astro into .tsx\n};\n```\n\n### DO: Keep React Containers Pure SSR\n```tsx\n\u002F\u002F Good: No useState, no useEffect\nexport const HomePage: React.FC\u003CProps> = ({ articles }) => {\n  return (\n    \u003C>\n      \u003CHeader \u002F>\n      \u003CArticleGrid articles={articles} \u002F>\n      \u003CFooter \u002F>\n    \u003C\u002F>\n  );\n};\n```\n\n## Script Directive Reference\n\n| Directive | Bundled? | Deferred? | Use For |\n|-----------|----------|-----------|---------|\n| `\u003Cscript>` | Yes | Yes | Most scripts |\n| `\u003Cscript is:inline>` | No | No | Theme init (before paint), small scripts |\n\nUse `is:inline` for:\n- Theme initialization (must run before first paint)\n- Tiny scripts where bundling overhead isn't worth it\n- Scripts that need to run synchronously\n\n## Testing Strategy\n\n| What | Where | How |\n|------|-------|-----|\n| React components | Ladle\u002FStorybook | Visual regression |\n| Full page with interactions | Astro dev server | Playwright integration tests |\n| Vanilla JS | Integration tests | Playwright |\n\nYou cannot test vanilla JS interactions in component isolation tools like Ladle - they need the full Astro page context.\n",{},"main","456b6e5999d9613b2065544f7789689d31742769",".claude\u002Fskills\u002Fastro-islands","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com","https:\u002F\u002Ffightingwithai.vercel.app","https:\u002F\u002Fgithub.com\u002Fjoshribakoff","joshribakoff.com","2026-01-22 14:44:35",{"source":7,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add joshribakoff\u002Ffightingwithai.com --skill astro-islands",{"tool":38,"command":39},"bunx","bunx skills add joshribakoff\u002Ffightingwithai.com --skill astro-islands",{"tool":41,"command":42},"pnpm","pnpm dlx skills add joshribakoff\u002Ffightingwithai.com --skill astro-islands","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fastro-islands\u002FSKILL.md",true,[],[47,54,62,69,80,93],{"skillNo":48,"name":49,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":50,"categories":51,"keywords":52,"publishedAt":20},"01M6C4Y9B23N3BZYDHRRVW13PF","simple-commands","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fsimple-commands\u002FSKILL.md",[],[53],"simple commands",{"skillNo":55,"name":56,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":57,"categories":58,"keywords":59,"publishedAt":20},"01M6C4Y7XQM8QNRMDDFXTDMW7P","meta-skill","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fmeta-skill\u002FSKILL.md",[],[60,61],"Meta","meta skill",{"skillNo":63,"name":64,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":20},"01M6C4Y65GQJC86RRJN64NZ4R5","magic-links","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fmagic-links\u002FSKILL.md",[],[68],"magic links",{"skillNo":70,"name":71,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":79,"publishedAt":20},"01M6C4Y508MC06FWACP82JNYMN","copywriting","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcopywriting\u002FSKILL.md",[74],{"categoryNo":75,"categoryName":76,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",[71],{"skillNo":81,"name":82,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":90,"publishedAt":20},"01M6C4Y2QWSAXM4QMZT7B148R7","content-ordering","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcontent-ordering\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[91,92],"content","content ordering",{"skillNo":94,"name":95,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":101,"publishedAt":20},"01M6C4Y0W01TCYVVFE4ZSQ8K02","code-cleanup","https:\u002F\u002Fgithub.com\u002Fjoshribakoff\u002Ffightingwithai.com\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcode-cleanup\u002FSKILL.md",[98],{"categoryNo":99,"categoryName":100,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000030","开发工程师",[102,103,104],"cleanup","code","code cleanup"]