[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F6VR7BH86AM8HQD5B91FSP":3,"skill-same:01M6F6VR7BH86AM8HQD5B91FSP":90},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":34,"publishedAt":55,"linkOnly":56,"markdownContent":57,"markdownBody":58,"frontMatter":59,"refName":67,"commitSha":68,"skillDirectory":69,"forksCount":70,"repositoryHtmlUrl":71,"repositoryHomepageUrl":72,"ownerHtmlUrl":73,"ownerBlogUrl":6,"ownerDescription":74,"updatedAt":75,"install":76,"resources":89},"01M6F6VR7BH86AM8HQD5B91FSP","anima-sdk-patterns",null,"Apply production-ready patterns for the Anima SDK design-to-code pipeline.\nUse when building reusable Anima client wrappers, implementing output caching,\nor establishing team standards for design-to-code automation.\nTrigger: \"anima SDK patterns\", \"anima best practices\", \"anima code patterns\".","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fanima-sdk-patterns\u002FSKILL.md",[18,23,26,31],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",{"categoryNo":32,"categoryName":33,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000032","设计师",[35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"sdk","anima sdk patterns","anima","patterns","pipeline","team","read","write","edit","use","ready","standards","reusable","figma","caching","io","trigger","code patterns","code","design","2026-11-10 10:12:30",false,"---\nname: anima-sdk-patterns\ndescription: |\n  Apply production-ready patterns for the Anima SDK design-to-code pipeline.\n  Use when building reusable Anima client wrappers, implementing output caching,\n  or establishing team standards for design-to-code automation.\n  Trigger: \"anima SDK patterns\", \"anima best practices\", \"anima code patterns\".\nallowed-tools: Read, Write, Edit\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\ntags: [saas, design, figma, anima, patterns]\ncompatible-with: claude-code\n---\n\n# Anima SDK Patterns\n\n## Overview\n\nProduction patterns for `@animaapp\u002Fanima-sdk`: singleton client, generation caching, output normalization, and configurable settings presets.\n\n## Instructions\n\n### Step 1: Singleton Client with Configuration\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fclient.ts\nimport { Anima } from '@animaapp\u002Fanima-sdk';\n\nlet instance: Anima | null = null;\n\nexport function getAnimaClient(): Anima {\n  if (!instance) {\n    if (!process.env.ANIMA_TOKEN) throw new Error('ANIMA_TOKEN not set');\n    instance = new Anima({ auth: { token: process.env.ANIMA_TOKEN } });\n  }\n  return instance;\n}\n\n\u002F\u002F Preset configurations for different project needs\nexport const PRESETS = {\n  nextjs: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const, uiLibrary: 'shadcn' as const },\n  vite: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const },\n  vue: { language: 'typescript' as const, framework: 'vue' as const, styling: 'tailwind' as const },\n  static: { language: 'javascript' as const, framework: 'html' as const, styling: 'css' as const },\n} as const;\n```\n\n### Step 2: Generation Cache\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fcache.ts\nimport crypto from 'crypto';\nimport fs from 'fs';\n\ninterface CacheEntry {\n  files: Array\u003C{ fileName: string; content: string }>;\n  generatedAt: string;\n  settingsHash: string;\n}\n\nclass AnimaCache {\n  private cacheDir: string;\n\n  constructor(cacheDir: string = '.anima-cache') {\n    this.cacheDir = cacheDir;\n    fs.mkdirSync(cacheDir, { recursive: true });\n  }\n\n  private getKey(fileKey: string, nodeId: string, settings: object): string {\n    const hash = crypto.createHash('md5')\n      .update(`${fileKey}:${nodeId}:${JSON.stringify(settings)}`)\n      .digest('hex');\n    return hash;\n  }\n\n  get(fileKey: string, nodeId: string, settings: object): CacheEntry | null {\n    const key = this.getKey(fileKey, nodeId, settings);\n    const path = `${this.cacheDir}\u002F${key}.json`;\n    if (!fs.existsSync(path)) return null;\n    return JSON.parse(fs.readFileSync(path, 'utf8'));\n  }\n\n  set(fileKey: string, nodeId: string, settings: object, files: any[]): void {\n    const key = this.getKey(fileKey, nodeId, settings);\n    const entry: CacheEntry = {\n      files,\n      generatedAt: new Date().toISOString(),\n      settingsHash: key,\n    };\n    fs.writeFileSync(`${this.cacheDir}\u002F${key}.json`, JSON.stringify(entry));\n  }\n}\n\nexport { AnimaCache };\n```\n\n### Step 3: Output Normalizer\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fnormalizer.ts\n\u002F\u002F Normalize Anima output to match project conventions\n\ninterface NormalizationConfig {\n  componentNameCase: 'PascalCase' | 'kebab-case';\n  addBarrelExport: boolean;\n  wrapWithCn: boolean;\n  addTypeAnnotations: boolean;\n}\n\nfunction normalizeOutput(\n  files: Array\u003C{ fileName: string; content: string }>,\n  config: NormalizationConfig,\n): Array\u003C{ fileName: string; content: string }> {\n  return files.map(file => {\n    let content = file.content;\n\n    if (config.wrapWithCn && file.fileName.endsWith('.tsx')) {\n      \u002F\u002F Add cn() import and wrap className strings\n      if (!content.includes(\"import { cn }\")) {\n        content = content.replace(\n          \u002F^(import .+\\n)\u002Fm,\n          \"$1import { cn } from '@\u002Flib\u002Futils';\\n\"\n        );\n      }\n    }\n\n    if (config.addTypeAnnotations && file.fileName.endsWith('.tsx')) {\n      content = content.replace(\n        \u002Fexport default function (\\w+)\\(\\)\u002Fg,\n        'export default function $1(): React.ReactElement'\n      );\n    }\n\n    return { fileName: file.fileName, content };\n  });\n}\n\nexport { normalizeOutput, NormalizationConfig };\n```\n\n### Step 4: Error Recovery Pattern\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fretry.ts\nasync function generateWithRetry(\n  anima: Anima,\n  params: any,\n  maxRetries: number = 3,\n): Promise\u003Cany> {\n  for (let attempt = 1; attempt \u003C= maxRetries; attempt++) {\n    try {\n      return await anima.generateCode(params);\n    } catch (err: any) {\n      if (attempt === maxRetries) throw err;\n      const delay = 2000 * Math.pow(2, attempt - 1);\n      console.log(`Generation failed, retry ${attempt}\u002F${maxRetries} in ${delay}ms`);\n      await new Promise(r => setTimeout(r, delay));\n    }\n  }\n}\n```\n\n## Output\n\n- Singleton client with preset configurations\n- File-based generation cache (avoid redundant API calls)\n- Output normalizer for project convention matching\n- Retry pattern for API resilience\n\n## Resources\n\n- [Anima SDK GitHub](https:\u002F\u002Fgithub.com\u002FAnimaApp\u002Fanima-sdk)\n- [Anima API Docs](https:\u002F\u002Fdocs.animaapp.com\u002Fdocs\u002Fanima-api)\n\n## Next Steps\n\nApply patterns in `anima-core-workflow-a` for automated design pipelines.\n\n","# Anima SDK Patterns\n\n## Overview\n\nProduction patterns for `@animaapp\u002Fanima-sdk`: singleton client, generation caching, output normalization, and configurable settings presets.\n\n## Instructions\n\n### Step 1: Singleton Client with Configuration\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fclient.ts\nimport { Anima } from '@animaapp\u002Fanima-sdk';\n\nlet instance: Anima | null = null;\n\nexport function getAnimaClient(): Anima {\n  if (!instance) {\n    if (!process.env.ANIMA_TOKEN) throw new Error('ANIMA_TOKEN not set');\n    instance = new Anima({ auth: { token: process.env.ANIMA_TOKEN } });\n  }\n  return instance;\n}\n\n\u002F\u002F Preset configurations for different project needs\nexport const PRESETS = {\n  nextjs: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const, uiLibrary: 'shadcn' as const },\n  vite: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const },\n  vue: { language: 'typescript' as const, framework: 'vue' as const, styling: 'tailwind' as const },\n  static: { language: 'javascript' as const, framework: 'html' as const, styling: 'css' as const },\n} as const;\n```\n\n### Step 2: Generation Cache\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fcache.ts\nimport crypto from 'crypto';\nimport fs from 'fs';\n\ninterface CacheEntry {\n  files: Array\u003C{ fileName: string; content: string }>;\n  generatedAt: string;\n  settingsHash: string;\n}\n\nclass AnimaCache {\n  private cacheDir: string;\n\n  constructor(cacheDir: string = '.anima-cache') {\n    this.cacheDir = cacheDir;\n    fs.mkdirSync(cacheDir, { recursive: true });\n  }\n\n  private getKey(fileKey: string, nodeId: string, settings: object): string {\n    const hash = crypto.createHash('md5')\n      .update(`${fileKey}:${nodeId}:${JSON.stringify(settings)}`)\n      .digest('hex');\n    return hash;\n  }\n\n  get(fileKey: string, nodeId: string, settings: object): CacheEntry | null {\n    const key = this.getKey(fileKey, nodeId, settings);\n    const path = `${this.cacheDir}\u002F${key}.json`;\n    if (!fs.existsSync(path)) return null;\n    return JSON.parse(fs.readFileSync(path, 'utf8'));\n  }\n\n  set(fileKey: string, nodeId: string, settings: object, files: any[]): void {\n    const key = this.getKey(fileKey, nodeId, settings);\n    const entry: CacheEntry = {\n      files,\n      generatedAt: new Date().toISOString(),\n      settingsHash: key,\n    };\n    fs.writeFileSync(`${this.cacheDir}\u002F${key}.json`, JSON.stringify(entry));\n  }\n}\n\nexport { AnimaCache };\n```\n\n### Step 3: Output Normalizer\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fnormalizer.ts\n\u002F\u002F Normalize Anima output to match project conventions\n\ninterface NormalizationConfig {\n  componentNameCase: 'PascalCase' | 'kebab-case';\n  addBarrelExport: boolean;\n  wrapWithCn: boolean;\n  addTypeAnnotations: boolean;\n}\n\nfunction normalizeOutput(\n  files: Array\u003C{ fileName: string; content: string }>,\n  config: NormalizationConfig,\n): Array\u003C{ fileName: string; content: string }> {\n  return files.map(file => {\n    let content = file.content;\n\n    if (config.wrapWithCn && file.fileName.endsWith('.tsx')) {\n      \u002F\u002F Add cn() import and wrap className strings\n      if (!content.includes(\"import { cn }\")) {\n        content = content.replace(\n          \u002F^(import .+\\n)\u002Fm,\n          \"$1import { cn } from '@\u002Flib\u002Futils';\\n\"\n        );\n      }\n    }\n\n    if (config.addTypeAnnotations && file.fileName.endsWith('.tsx')) {\n      content = content.replace(\n        \u002Fexport default function (\\w+)\\(\\)\u002Fg,\n        'export default function $1(): React.ReactElement'\n      );\n    }\n\n    return { fileName: file.fileName, content };\n  });\n}\n\nexport { normalizeOutput, NormalizationConfig };\n```\n\n### Step 4: Error Recovery Pattern\n\n```typescript\n\u002F\u002F src\u002Fanima\u002Fretry.ts\nasync function generateWithRetry(\n  anima: Anima,\n  params: any,\n  maxRetries: number = 3,\n): Promise\u003Cany> {\n  for (let attempt = 1; attempt \u003C= maxRetries; attempt++) {\n    try {\n      return await anima.generateCode(params);\n    } catch (err: any) {\n      if (attempt === maxRetries) throw err;\n      const delay = 2000 * Math.pow(2, attempt - 1);\n      console.log(`Generation failed, retry ${attempt}\u002F${maxRetries} in ${delay}ms`);\n      await new Promise(r => setTimeout(r, delay));\n    }\n  }\n}\n```\n\n## Output\n\n- Singleton client with preset configurations\n- File-based generation cache (avoid redundant API calls)\n- Output normalizer for project convention matching\n- Retry pattern for API resilience\n\n## Resources\n\n- [Anima SDK GitHub](https:\u002F\u002Fgithub.com\u002FAnimaApp\u002Fanima-sdk)\n- [Anima API Docs](https:\u002F\u002Fdocs.animaapp.com\u002Fdocs\u002Fanima-api)\n\n## Next Steps\n\nApply patterns in `anima-core-workflow-a` for automated design pipelines.\n\n",{"name":5,"tags":60,"author":62,"license":15,"version":63,"description":64,"allowed-tools":65,"compatible-with":66},[61,54,48,37,38],"saas","Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Apply production-ready patterns for the Anima SDK design-to-code pipeline.\nUse when building reusable Anima client wrappers, implementing output caching,\nor establishing team standards for design-to-code automation.\nTrigger: \"anima SDK patterns\", \"anima best practices\", \"anima code patterns\".\n","Read, Write, Edit","claude-code","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fanima-sdk-patterns",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":77,"prompt":87,"zipAvailable":88},[78,81,84],{"tool":79,"command":80},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill anima-sdk-patterns",{"tool":82,"command":83},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill anima-sdk-patterns",{"tool":85,"command":86},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill anima-sdk-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fanima-sdk-patterns\u002FSKILL.md",true,[],[91,101,111,119,125,132],{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":97,"publishedAt":55},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[96],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[98,99,100],"model","model hierarchy","model hierarchy skill",{"skillNo":102,"name":103,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":107,"publishedAt":55},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[106],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[108,109,110],"MCP","zoom","zoom mcp",{"skillNo":112,"name":113,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":116,"publishedAt":55},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[35,117,118,109],"zoom apps sdk","apps",{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":55},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[121],{"skillNo":126,"name":127,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":131,"publishedAt":55},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[130],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[127],{"skillNo":133,"name":134,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":137,"publishedAt":55},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[134]]