From anima-pack
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".
npx claudepluginhub flight505/skill-forge --plugin anima-packThis skill is limited to using the following tools:
Production patterns for `@animaapp/anima-sdk`: singleton client, generation caching, output normalization, and configurable settings presets.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
Production patterns for @animaapp/anima-sdk: singleton client, generation caching, output normalization, and configurable settings presets.
// 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;
// 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 };
// 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 };
// 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));
}
}
}
Apply patterns in anima-core-workflow-a for automated design pipelines.