> anima-sdk-patterns
Apply production-ready patterns for the Anima SDK design-to-code pipeline. Use when building reusable Anima client wrappers, implementing output caching, or establishing team standards for design-to-code automation. Trigger: "anima SDK patterns", "anima best practices", "anima code patterns".
curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/anima-sdk-patterns?format=md"Anima SDK Patterns
Overview
Production patterns for @animaapp/anima-sdk: singleton client, generation caching, output normalization, and configurable settings presets.
Instructions
Step 1: Singleton Client with Configuration
// src/anima/client.ts
import { Anima } from '@animaapp/anima-sdk';
let instance: Anima | null = null;
export function getAnimaClient(): Anima {
if (!instance) {
if (!process.env.ANIMA_TOKEN) throw new Error('ANIMA_TOKEN not set');
instance = new Anima({ auth: { token: process.env.ANIMA_TOKEN } });
}
return instance;
}
// Preset configurations for different project needs
export const PRESETS = {
nextjs: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const, uiLibrary: 'shadcn' as const },
vite: { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const },
vue: { language: 'typescript' as const, framework: 'vue' as const, styling: 'tailwind' as const },
static: { language: 'javascript' as const, framework: 'html' as const, styling: 'css' as const },
} as const;
Step 2: Generation Cache
// src/anima/cache.ts
import crypto from 'crypto';
import fs from 'fs';
interface CacheEntry {
files: Array<{ fileName: string; content: string }>;
generatedAt: string;
settingsHash: string;
}
class AnimaCache {
private cacheDir: string;
constructor(cacheDir: string = '.anima-cache') {
this.cacheDir = cacheDir;
fs.mkdirSync(cacheDir, { recursive: true });
}
private getKey(fileKey: string, nodeId: string, settings: object): string {
const hash = crypto.createHash('md5')
.update(`${fileKey}:${nodeId}:${JSON.stringify(settings)}`)
.digest('hex');
return hash;
}
get(fileKey: string, nodeId: string, settings: object): CacheEntry | null {
const key = this.getKey(fileKey, nodeId, settings);
const path = `${this.cacheDir}/${key}.json`;
if (!fs.existsSync(path)) return null;
return JSON.parse(fs.readFileSync(path, 'utf8'));
}
set(fileKey: string, nodeId: string, settings: object, files: any[]): void {
const key = this.getKey(fileKey, nodeId, settings);
const entry: CacheEntry = {
files,
generatedAt: new Date().toISOString(),
settingsHash: key,
};
fs.writeFileSync(`${this.cacheDir}/${key}.json`, JSON.stringify(entry));
}
}
export { AnimaCache };
Step 3: Output Normalizer
// src/anima/normalizer.ts
// Normalize Anima output to match project conventions
interface NormalizationConfig {
componentNameCase: 'PascalCase' | 'kebab-case';
addBarrelExport: boolean;
wrapWithCn: boolean;
addTypeAnnotations: boolean;
}
function normalizeOutput(
files: Array<{ fileName: string; content: string }>,
config: NormalizationConfig,
): Array<{ fileName: string; content: string }> {
return files.map(file => {
let content = file.content;
if (config.wrapWithCn && file.fileName.endsWith('.tsx')) {
// Add cn() import and wrap className strings
if (!content.includes("import { cn }")) {
content = content.replace(
/^(import .+\n)/m,
"$1import { cn } from '@/lib/utils';\n"
);
}
}
if (config.addTypeAnnotations && file.fileName.endsWith('.tsx')) {
content = content.replace(
/export default function (\w+)\(\)/g,
'export default function $1(): React.ReactElement'
);
}
return { fileName: file.fileName, content };
});
}
export { normalizeOutput, NormalizationConfig };
Step 4: Error Recovery Pattern
// src/anima/retry.ts
async function generateWithRetry(
anima: Anima,
params: any,
maxRetries: number = 3,
): Promise<any> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await anima.generateCode(params);
} catch (err: any) {
if (attempt === maxRetries) throw err;
const delay = 2000 * Math.pow(2, attempt - 1);
console.log(`Generation failed, retry ${attempt}/${maxRetries} in ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
}
}
}
Output
- Singleton client with preset configurations
- File-based generation cache (avoid redundant API calls)
- Output normalizer for project convention matching
- Retry pattern for API resilience
Resources
Next Steps
Apply patterns in anima-core-workflow-a for automated design pipelines.
> related_skills --same-repo
> fathom-cost-tuning
Optimize Fathom API usage and plan selection. Trigger with phrases like "fathom cost", "fathom pricing", "fathom plan".
> fathom-core-workflow-b
Sync Fathom meeting data to CRM and build automated follow-up workflows. Use when integrating Fathom with Salesforce, HubSpot, or custom CRMs, or creating automated post-meeting email summaries. Trigger with phrases like "fathom crm sync", "fathom salesforce", "fathom follow-up", "fathom post-meeting workflow".
> fathom-core-workflow-a
Build a meeting analytics pipeline with Fathom transcripts and summaries. Use when extracting insights from meetings, building CRM sync, or creating automated meeting follow-up workflows. Trigger with phrases like "fathom analytics", "fathom meeting pipeline", "fathom transcript analysis", "fathom action items sync".
> fathom-common-errors
Diagnose and fix Fathom API errors including auth failures and missing data. Use when API calls fail, transcripts are empty, or webhooks are not firing. Trigger with phrases like "fathom error", "fathom not working", "fathom api failure", "fix fathom".