react |
typescript, javascript
Build automated Figma-to-React pipeline with the Anima SDK.
ReadWriteEditBash(npm:*)Grep
Anima Core Workflow A — Figma-to-React Pipeline
Overview
Primary workflow: automated pipeline that watches a Figma file, generates React components whenever the design changes, and integrates them into your codebase. This replaces manual design handoff with continuous design-to-code automation.
Prerequisites
- Completed
anima-install-auth setup
- Figma file with organized components (auto-layout recommended)
- React project (Next.js, Vite, or CRA)
Instructions
Step 1: Design System Scanner
// src/pipeline/figma-scanner.ts
import { Anima } from '@animaapp/anima-sdk';
interface FigmaComponent {
nodeId: string;
name: string;
type: 'COMPONENT' | 'FRAME' | 'COMPONENT_SET';
}
const anima = new Anima({
auth: { token: process.env.ANIMA_TOKEN! },
});
// Fetch all top-level components from a Figma page
async function scanFigmaComponents(fileKey: string): Promise<FigmaComponent[]> {
const response = await fetch(
`https://api.figma.com/v1/files/${fileKey}/components`,
{ headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! } }
);
const data = await response.json();
return data.meta.components.map((comp: any) => ({
nodeId: comp.node_id,
name: comp.name,
type: comp.containing_frame?.type || 'COMPONENT',
}));
}
Step 2: Batch Code Generator
// src/pipeline/batch-generator.ts
import { Anima } from '@animaapp/anima-sdk';
import fs from 'fs';
import path from 'path';
const anima = new Anima({
auth: { token: process.env.ANIMA_TOKEN! },
});
interface GenerationConfig {
fileKey: string;
outputDir: string;
settings: {
language: 'typescript' | 'javascript';
framework: 'react' | 'vue' | 'html';
styling: 'tailwind' | 'css' | 'styled-components';
uiLibrary?: 'none' | 'mui' | 'antd' | 'shadcn';
};
}
async function generateComponentBatch(
config: GenerationConfig,
nodeIds: string[],
): Promise<{ generated: number; failed: string[] }> {
const failed: string[] = [];
let generated = 0;
fs.mkdirSync(config.outputDir, { recursive: true });
// Generate each component (Anima processes one node at a time)
for (const nodeId of nodeIds) {
try {
const { files } = await anima.generateCode({
fileKey: config.fileKey,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: [nodeId],
settings: config.settings,
});
for (const file of files) {
const filePath = path.join(config.outputDir, file.fileName);
fs.writeFileSync(filePath, file.content);
console.log(`Generated: ${file.fileName}`);
}
generated++;
} catch (err) {
console.error(`Failed to generate
Clone websites to React/HTML code and customize Anima output with AI.
ReadWriteEditBash(npm:*)Grep
Anima Core Workflow B — Website-to-Code & AI Customization
Overview
Secondary workflow: use Anima to clone live websites into React/HTML code and customize generated output with AI-powered code modification. Anima supports URL-to-code conversion alongside Figma-to-code.
Prerequisites
- Completed
anima-install-auth setup
- Understanding of Anima's code generation settings
Instructions
Step 1: Website-to-Code Conversion
// src/workflows/website-to-code.ts
// Anima can clone any public website and generate React or HTML code
import { Anima } from '@animaapp/anima-sdk';
const anima = new Anima({
auth: { token: process.env.ANIMA_TOKEN! },
});
// Note: URL-to-code may use a different API endpoint
// Check docs.animaapp.com for current availability
async function cloneWebsiteToReact(url: string, outputDir: string) {
// Anima's website-to-code feature captures the page and generates code
// This is available via the Anima Playground or API (partner access)
// For Figma-based workflow, use the Figma plugin to import website screenshots
// then generate code from the imported frames
console.log(`Cloning ${url} to React components...`);
// Process via Figma intermediary:
// 1. Use Anima Figma plugin to capture website layout
// 2. Generate code from the captured frames
// 3. Customize with AI post-processing
}
Step 2: Post-Generation Customization
// src/workflows/customize-output.ts
import fs from 'fs';
import path from 'path';
interface CustomizationRule {
pattern: RegExp;
replacement: string;
description: string;
}
// Apply project-specific customizations to Anima output
function customizeGeneratedCode(
files: Array<{ fileName: string; content: string }>,
rules: CustomizationRule[],
): Array<{ fileName: string; content: string }> {
return files.map(file => {
let content = file.content;
for (const rule of rules) {
content = content.replace(rule.pattern, rule.replacement);
}
return { ...file, content };
});
}
// Common customization rules
const PROJECT_RULES: CustomizationRule[] = [
{
pattern: /className="([^"]+)"/g,
replacement: 'className={cn("$1")}',
description: 'Wrap Tailwind classes with cn() utility',
},
{
pattern: /import React from 'react'/g,
replacement: "import React from 'react';\nimport { cn } from '@/lib/utils'",
description: 'Add cn import for className merging',
},
{
pattern: /export default function (\w+)/g,
replacement: 'export const $1: React.FC = function $1',
description: 'Use React.FC type annotation',
},
];
Step 3: Design Token Mapper
// src/workfl
Optimize Anima API costs through caching, incremental generation, and tier selection.
ReadWriteEditBash(npm:*)
Anima Cost Tuning
Pricing Context
Anima uses partner-based pricing (not self-service). API access is currently granted to partners with custom agreements. Costs are typically per-generation or per-seat.
Cost Optimization Strategies
| Strategy |
Savings |
Implementation |
| Generation cache |
60-80% |
Cache results; only regenerate on design change |
| Incremental generation |
40-60% |
Detect changed components; skip unchanged |
| Batch scheduling |
20-30% |
Generate during off-peak; avoid real-time |
| Output reuse |
30-50% |
Generate once, customize programmatically |
Instructions
Step 1: Usage Tracker
// src/cost/usage-tracker.ts
interface GenerationRecord {
timestamp: string;
fileKey: string;
nodeId: string;
cached: boolean;
durationMs: number;
}
class AnimaUsageTracker {
private records: GenerationRecord[] = [];
record(entry: GenerationRecord): void { this.records.push(entry); }
getReport(): { total: number; cached: number; savings: string } {
const total = this.records.length;
const cached = this.records.filter(r => r.cached).length;
return {
total,
cached,
savings: total > 0 ? `${((cached / total) * 100).toFixed(0)}% saved by caching` : 'No data',
};
}
}
Step 2: Smart Generation Policy
// Only generate when:
// 1. Figma file version changed (check via Figma API)
// 2. Cache is expired (>1 hour for active dev, >24h for CI)
// 3. Settings changed (new framework/styling)
// 4. Force flag passed (manual override)
async function shouldGenerate(
fileKey: string,
nodeId: string,
cache: any,
): Promise<boolean> {
// Check cache first
const cached = cache.get(fileKey, nodeId);
if (cached && Date.now() - new Date(cached.generatedAt).getTime() < 3600000) {
console.log('Using cached generation (< 1 hour old)');
return false;
}
return true;
}
Output
- Usage tracking with cache hit rate reporting
- Smart generation policy reducing unnecessary API calls
- Cost savings through caching and incremental updates
Resources
Next Steps
For architecture design, see anima-reference-architecture.
Collect Anima SDK debug evidence for support tickets and troubleshooting.
ReadWriteEditBash(curl:*)Bash(node:*)Grep
Anima Debug Bundle
Instructions
Step 1: Generate Debug Bundle
// src/debug/anima-debug.ts
import fs from 'fs';
async function generateDebugBundle() {
const bundle = {
timestamp: new Date().toISOString(),
environment: {
nodeVersion: process.version,
sdkVersion: require('@animaapp/anima-sdk/package.json').version,
animaToken: process.env.ANIMA_TOKEN ? 'SET (redacted)' : 'NOT SET',
figmaToken: process.env.FIGMA_TOKEN ? 'SET (redacted)' : 'NOT SET',
},
figmaAccess: await testFigmaAccess(),
generationTest: await testGeneration(),
};
const filename = `anima-debug-${Date.now()}.json`;
fs.writeFileSync(filename, JSON.stringify(bundle, null, 2));
console.log(`Debug bundle: ${filename}`);
return bundle;
}
async function testFigmaAccess() {
try {
const res = await fetch('https://api.figma.com/v1/me', {
headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! },
});
const data = await res.json();
return { status: res.ok ? 'ok' : 'failed', user: data.handle || data.err };
} catch (err: any) {
return { status: 'failed', error: err.message };
}
}
async function testGeneration() {
try {
const { Anima } = await import('@animaapp/anima-sdk');
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
return { status: 'sdk_loaded', version: 'check package.json' };
} catch (err: any) {
return { status: 'sdk_failed', error: err.message };
}
}
generateDebugBundle().catch(console.error);
Output
- JSON debug bundle with SDK version, token status, and connectivity test
- Figma API access verification
- Safe for sharing with Anima support (tokens redacted)
Resources
Next Steps
For rate limiting, see anima-rate-limits.
Deploy Anima design-to-code service as a backend API endpoint.
ReadWriteEditBash(vercel:*)Bash(gcloud:*)Bash(docker:*)
Anima Deploy Integration
Overview
Deploy the Anima SDK as a backend service. The SDK is server-side only, so deploy it behind an API endpoint that accepts Figma file/node references and returns generated code.
Instructions
Step 1: Express API Wrapper
// src/server.ts
import express from 'express';
import { Anima } from '@animaapp/anima-sdk';
const app = express();
app.use(express.json());
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
app.post('/api/generate', async (req, res) => {
const { fileKey, nodesId, settings } = req.body;
if (!fileKey || !nodesId?.length) {
return res.status(400).json({ error: 'fileKey and nodesId required' });
}
try {
const { files } = await anima.generateCode({
fileKey,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId,
settings: settings || { language: 'typescript', framework: 'react', styling: 'tailwind' },
});
res.json({ files, count: files.length });
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
app.get('/health', (_req, res) => res.json({ status: 'ok' }));
app.listen(3000, () => console.log('Anima service on :3000'));
Step 2: Vercel Serverless Function
// api/generate.ts
import { Anima } from '@animaapp/anima-sdk';
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
export default async function handler(req: any, res: any) {
if (req.method !== 'POST') return res.status(405).end();
const { fileKey, nodesId, settings } = req.body;
const { files } = await anima.generateCode({
fileKey, figmaToken: process.env.FIGMA_TOKEN!, nodesId,
settings: settings || { language: 'typescript', framework: 'react', styling: 'tailwind' },
});
res.json({ files });
}
Step 3: Deploy Commands
# Vercel
vercel secrets add anima_token "$ANIMA_TOKEN"
vercel secrets add figma_token "$FIGMA_TOKEN"
vercel --prod
# Cloud Run
gcloud run deploy anima-service \
--source . \
--set-secrets=ANIMA_TOKEN=anima-token:latest,FIGMA_TOKEN=figma-token:latest \
--region us-central1 --allow-unauthenticated
Output
- Express API wrapping Anima SDK for internal design tooling
- Vercel serverless function for lightweight deployment
- Cloud Run deployment with Secret Manager
Resources
Next Steps
For webhook integration, see anima-webhooks-events.
Generate React/Vue/HTML code from a Figma design using the Anima SDK.
ReadWriteEditBash(npm:*)
Anima Hello World
Overview
Generate production-ready React, Vue, or HTML code from a Figma design using the @animaapp/anima-sdk. This example converts a Figma component into clean TypeScript React with Tailwind CSS.
Prerequisites
- Completed
anima-install-auth setup
- A Figma file with at least one frame/component
- Know your file key and node ID
Instructions
Step 1: Generate React + Tailwind Code
// src/hello-world.ts
import { Anima } from '@animaapp/anima-sdk';
import fs from 'fs';
import path from 'path';
const anima = new Anima({
auth: { token: process.env.ANIMA_TOKEN! },
});
async function generateReactComponent() {
const { files } = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!, // From Figma URL
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: [process.env.FIGMA_NODE_ID!], // e.g., '1:2'
settings: {
language: 'typescript',
framework: 'react',
styling: 'tailwind',
uiLibrary: 'none', // or 'mui', 'antd', 'shadcn'
},
});
// Write generated files to disk
const outputDir = './generated';
fs.mkdirSync(outputDir, { recursive: true });
for (const file of files) {
const filePath = path.join(outputDir, file.fileName);
fs.writeFileSync(filePath, file.content);
console.log(`Generated: ${filePath} (${file.content.length} chars)`);
}
return files;
}
generateReactComponent().catch(console.error);
Step 2: Try Different Framework Outputs
// Generate Vue + Tailwind
const vueFiles = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2'],
settings: {
language: 'typescript',
framework: 'vue',
styling: 'tailwind',
},
});
// Generate HTML + CSS (no framework)
const htmlFiles = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2'],
settings: {
language: 'javascript',
framework: 'html',
styling: 'css',
},
});
// Generate React + shadcn/ui
const shadcnFiles = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2'],
settings: {
language: 'typescript',
framework: 'react',
styling: 'tailwind',
uiLibrary: 'shadcn',
},
});
Step 3: Inspect Generated Output
// The generated files array contains:
interface GeneratedFile {
fileName: string; // e.g., 'HeroSection.tsx', 'styles.css'
content: string; // Full file content
type: strin
Install the Anima SDK and configure authentication for Figma-to-code generation.
ReadWriteEditBash(npm:*)Grep
Anima Install & Auth
Overview
Install @animaapp/anima-sdk and configure authentication tokens. Anima converts Figma designs into production-ready React, Vue, or HTML code with Tailwind, MUI, AntD, or shadcn styling. The SDK runs server-side only.
Prerequisites
- Node.js 18+ (SDK is server-side only)
- Figma account with API access
- Anima API token (request at animaapp.com)
- Figma Personal Access Token
Instructions
Step 1: Install the Anima SDK
npm install @animaapp/anima-sdk
Step 2: Get Your Tokens
# 1. Figma Personal Access Token:
# Figma > Settings > Account > Personal Access Tokens > Generate
# 2. Anima API Token:
# Request from Anima team (currently limited partner access)
# https://docs.animaapp.com/docs/anima-api
# Store securely
cat > .env << 'EOF'
ANIMA_TOKEN=your-anima-api-token
FIGMA_TOKEN=your-figma-personal-access-token
EOF
echo ".env" >> .gitignore
chmod 600 .env
Step 3: Initialize and Verify
// src/anima-client.ts
import { Anima } from '@animaapp/anima-sdk';
const anima = new Anima({
auth: {
token: process.env.ANIMA_TOKEN!,
},
});
// Verify connection by generating code from a known Figma file
async function verifySetup() {
try {
const { files } = await anima.generateCode({
fileKey: 'your-figma-file-key', // From Figma URL: figma.com/file/{fileKey}/...
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2'], // Specific node to convert
settings: {
language: 'typescript',
framework: 'react',
styling: 'tailwind',
},
});
console.log(`Generated ${files.length} files`);
for (const file of files) {
console.log(` ${file.fileName} (${file.content.length} chars)`);
}
return true;
} catch (error) {
console.error('Setup verification failed:', error);
return false;
}
}
verifySetup();
Step 4: Get Your Figma File Key
Figma URL format:
https://www.figma.com/file/ABC123xyz/My-Design?node-id=1:2
File Key: ABC123xyz
Node ID: 1:2 (from the URL query parameter)
Output
@animaapp/anima-sdk installed
- Anima token and Figma token configured in
.env
- Verified code generation from a Figma design
- Understanding of file key and node ID extraction
Error Handling
| Error |
Cause |
Solution |
Invalid Anima token |
Token not provisioned |
Request token from Anima team |
Invalid Figma token
Set up iterative design-to-code development loop with Anima SDK.
ReadWriteEditBash(npm:*)Grep
Anima Local Dev Loop
Overview
Iterative development workflow for Anima design-to-code: generate from Figma, preview in browser, tweak settings, regenerate. Includes side-by-side comparison of React vs Vue vs HTML output.
Instructions
Step 1: Project Setup
mkdir anima-dev && cd anima-dev
npm init -y
npm install @animaapp/anima-sdk dotenv
npm install -D vite @vitejs/plugin-react typescript
Step 2: Generate and Preview Script
// scripts/generate-preview.ts
import { Anima } from '@animaapp/anima-sdk';
import fs from 'fs';
import 'dotenv/config';
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
const SETTINGS_PRESETS = {
'react-tailwind': { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const },
'react-shadcn': { language: 'typescript' as const, framework: 'react' as const, styling: 'tailwind' as const, uiLibrary: 'shadcn' as const },
'vue-tailwind': { language: 'typescript' as const, framework: 'vue' as const, styling: 'tailwind' as const },
'html-css': { language: 'javascript' as const, framework: 'html' as const, styling: 'css' as const },
};
async function generateWithPreset(preset: keyof typeof SETTINGS_PRESETS, nodeId: string) {
const settings = SETTINGS_PRESETS[preset];
const outputDir = `./generated/${preset}`;
fs.mkdirSync(outputDir, { recursive: true });
const { files } = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: [nodeId],
settings,
});
for (const file of files) {
fs.writeFileSync(`${outputDir}/${file.fileName}`, file.content);
}
console.log(`${preset}: ${files.length} files generated`);
}
// Compare all presets
async function compareOutputs(nodeId: string) {
for (const preset of Object.keys(SETTINGS_PRESETS) as Array<keyof typeof SETTINGS_PRESETS>) {
await generateWithPreset(preset, nodeId);
await new Promise(r => setTimeout(r, 2000)); // Rate limit
}
console.log('\nAll presets generated in ./generated/');
}
const nodeId = process.argv[2] || '1:2';
compareOutputs(nodeId).catch(console.error);
Step 3: Development Scripts
{
"scripts": {
"generate": "tsx scripts/generate-preview.ts",
"generate:node": "tsx scripts/generate-preview.ts",
"preview": "vite",
"dev": "npm run generate && npm run preview"
}
}
Output
- Multi-preset code generation comparison
- Side-by-side React/Vue/HTML output for same design
- Vite preview server f
Optimize Anima code generation performance with caching, parallelism, and output tuning.
ReadWriteEditBash(npm:*)
Anima Performance Tuning
Performance Targets
| Operation |
Target |
Notes |
| Single component generation |
< 10s |
Depends on complexity |
| Batch (10 components) |
< 2 min |
With rate limit delays |
| Cache hit |
< 10ms |
File-based cache |
| Full design system (50 components) |
< 15 min |
Sequential with 6s delays |
Instructions
Step 1: File-Based Generation Cache
// src/performance/cache.ts
import crypto from 'crypto';
import fs from 'fs';
class GenerationCache {
private dir: string;
constructor(cacheDir = '.anima-cache') {
this.dir = cacheDir;
fs.mkdirSync(cacheDir, { recursive: true });
}
private hash(fileKey: string, nodeId: string, settings: any): string {
return crypto.createHash('md5').update(`${fileKey}:${nodeId}:${JSON.stringify(settings)}`).digest('hex');
}
async getOrGenerate(
anima: any,
params: any,
maxAgeMs: number = 3600000, // 1 hour
): Promise<any> {
const key = this.hash(params.fileKey, params.nodesId[0], params.settings);
const path = `${this.dir}/${key}.json`;
if (fs.existsSync(path)) {
const stat = fs.statSync(path);
if (Date.now() - stat.mtimeMs < maxAgeMs) {
return JSON.parse(fs.readFileSync(path, 'utf8'));
}
}
const result = await anima.generateCode(params);
fs.writeFileSync(path, JSON.stringify(result));
return result;
}
clearOlderThan(maxAgeMs: number): number {
let cleared = 0;
for (const file of fs.readdirSync(this.dir)) {
const path = `${this.dir}/${file}`;
if (Date.now() - fs.statSync(path).mtimeMs > maxAgeMs) {
fs.unlinkSync(path);
cleared++;
}
}
return cleared;
}
}
export { GenerationCache };
Step 2: Incremental Generation (Only Changed Components)
// src/performance/incremental.ts
// Only regenerate components whose Figma nodes changed
async function getNodeLastModified(fileKey: string, nodeId: string): Promise<string> {
const res = await fetch(
`https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeId}`,
{ headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! } }
);
const data = await res.json();
return data.lastModified;
}
async function generateOnlyChanged(
anima: any,
fileKey: string,
nodeIds: string[],
lastModifiedCache: Map<string, string>,
): Promise<string[]> {
const changed: string[] = [];
for (const nodeId of nodeIds) {
const lastMod = await getNodeLastModified(fileKey, nodeId);
if (lastMod !== lastModifiedCache.get(nodeId)) {
changed.push(nodeId);
lastModifiedCache.set(nodeId, lastMod);
Production readiness checklist for Anima design-to-code pipelines.
ReadWriteEditBash(curl:*)Grep
Anima Production Checklist
Overview
Anima converts Figma designs into production-ready code for React, Vue, and HTML. A failed design-to-code pipeline means engineers receive broken components, mismatched tokens, or stale screens that drift from the source of truth. This checklist ensures your Anima integration produces reliable, framework-compliant output before it reaches CI/CD.
Authentication & Secrets
- [ ]
ANIMAAPIKEY stored in secrets manager (never in source)
- [ ] Figma personal access token scoped to read-only with expiration
- [ ] Separate API keys for dev/staging/prod environments
- [ ] Key rotation schedule documented (90-day cycle recommended)
- [ ] Tokens excluded from client bundles and build artifacts
API Integration
- [ ] Production base URL configured (
https://api.animaapp.com)
- [ ] Rate limit handling for standard tier (10 generations/min)
- [ ] Generation cache prevents redundant API calls for unchanged screens
- [ ] Figma file version polling detects design changes automatically
- [ ] Webhook or polling configured for async generation completion
- [ ] Component mapping rules tested for target framework (React/Vue/HTML)
Error Handling & Resilience
- [ ] Circuit breaker configured for Anima API outages
- [ ] Retry with exponential backoff for 429/5xx responses
- [ ] Graceful fallback when Figma PAT expires mid-pipeline
- [ ] Generated code validated against ESLint/Prettier before merge
- [ ] Design token mismatches flagged before component output
- [ ] Empty generation results handled (missing layers, unsupported elements)
Monitoring & Alerting
- [ ] API latency tracked per generation request
- [ ] Error rate alerts set (threshold: >5% over 5 minutes)
- [ ] Generation quality score monitored (component render pass rate)
- [ ] Figma sync failures trigger immediate notification
- [ ] Daily digest of generation counts and token usage
Validation Script
async function checkAnimaReadiness(): Promise<void> {
const checks: { name: string; pass: boolean; detail: string }[] = [];
// Verify Anima API connectivity
try {
const res = await fetch('https://api.animaapp.com/v1/projects', {
headers: { Authorization: `Bearer ${process.env.ANIMA_API_KEY}` },
});
checks.push({ name: 'Anima API', pass: res.ok, detail: res.ok ? 'Connected' : `HTTP ${res.status}` });
} catch (e: any) { checks.push({ name: 'Anima API', pass: false, detail: e.message }); }
// Verify Figma access
try {
const res = await fetch('https://api.figma.com/v1/me', {
headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! },
});
checks.push({ name: &
Implement rate limiting for Anima API code generation requests.
ReadWriteEditBash(npm:*)
Anima Rate Limits
Overview
Anima API has per-minute rate limits on code generation. Each generateCode call processes one Figma node through AI — it's compute-intensive and rate-limited accordingly.
Rate Limit Tiers
| Tier |
Generations/min |
Concurrent |
Notes |
| Partner (standard) |
10 |
2 |
Most common |
| Enterprise |
30 |
5 |
Custom agreement |
Instructions
Step 1: Throttled Generator with Bottleneck
// src/anima/throttled-generator.ts
import Bottleneck from 'bottleneck';
import { Anima } from '@animaapp/anima-sdk';
const limiter = new Bottleneck({
maxConcurrent: 2,
minTime: 6000, // 10 per minute = 1 every 6 seconds
reservoir: 10,
reservoirRefreshInterval: 60000,
reservoirRefreshAmount: 10,
});
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
async function throttledGenerate(params: any) {
return limiter.schedule(() => anima.generateCode(params));
}
// Batch generate with automatic throttling
async function batchGenerate(nodeIds: string[], settings: any) {
const results = [];
for (const nodeId of nodeIds) {
const result = await throttledGenerate({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: [nodeId],
settings,
});
results.push({ nodeId, files: result.files });
console.log(`Generated ${nodeId}: ${result.files.length} files`);
}
return results;
}
export { throttledGenerate, batchGenerate };
Step 2: 429 Retry Handler
async function generateWithRetry(anima: Anima, params: any, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await anima.generateCode(params);
} catch (err: any) {
if (err.response?.status !== 429 || attempt === maxRetries) throw err;
const wait = Math.min(60000, 10000 * attempt); // Wait up to 60s
console.log(`Rate limited — waiting ${wait / 1000}s`);
await new Promise(r => setTimeout(r, wait));
}
}
}
Output
- Bottleneck-throttled code generation matching API limits
- Batch generator for design system-scale operations
- 429 retry handler with progressive backoff
Resources
Next Steps
For security practices, see anima-security-basics.
Implement reference architecture for Anima design-to-code automation.
ReadWriteEdit
Anima Reference Architecture
System Architecture
┌────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Figma Design │────▶│ Figma API │────▶│ Anima SDK │
│ (Components) │ │ (Webhooks) │ │ (Code Gen) │
└────────────────┘ └──────────────┘ └────────┬────────┘
│
┌─────────▼────────┐
│ Post-Processing │
│ - Token mapping │
│ - Normalization │
│ - Lint/format │
└─────────┬────────┘
│
┌─────────▼────────┐
│ Output │
│ - React/Vue/HTML │
│ - PR creation │
│ - Storybook sync │
└──────────────────┘
Project Structure
design-to-code/
├── src/
│ ├── anima/
│ │ ├── client.ts # Singleton SDK client
│ │ ├── cache.ts # Generation cache
│ │ ├── retry.ts # Error recovery
│ │ └── presets.ts # Framework/styling presets
│ ├── pipeline/
│ │ ├── scanner.ts # Figma component discovery
│ │ ├── generator.ts # Batch code generation
│ │ ├── change-detector.ts # Figma version tracking
│ │ └── runner.ts # Pipeline orchestrator
│ ├── post-process/
│ │ ├── normalizer.ts # Output normalization
│ │ ├── token-mapper.ts # Design token mapping
│ │ └── organizer.ts # File organization + barrel exports
│ ├── webhooks/
│ │ └── figma-handler.ts # Figma webhook receiver
│ └── server.ts # Express API (optional)
├── scripts/
│ ├── generate-components.ts # CLI generation script
│ └── compare-presets.ts # Side-by-side preset comparison
├── fixtures/
│ └── component-map.json # Figma node ID → component name mapping
├── generated/ # Output directory (gitignored or committed)
├── .anima-cache/ # Generation cache (gitignored)
└── package.json
Key Design Decisions
| Decision |
Choice |
Rationale |
| SDK |
@animaapp/anima-sdk |
Official, server-side, typed |
| Change detection |
Figma Webhooks v2 |
Event-driven, no polling waste |
| Caching |
File-based with MD5 keys |
Simple, no external dependencies |
<
Apply production-ready patterns for the Anima SDK design-to-code pipeline.
ReadWriteEdit
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;
Secure Anima and Figma tokens for design-to-code pipelines.
ReadWriteEditGrep
Anima Security Basics
Security Checklist
- [ ] Anima token stored in secret manager (not .env in prod)
- [ ] Figma PAT has minimum required scope (file:read only)
- [ ] SDK runs server-side only (never ship tokens to browser)
- [ ]
.env files gitignored and chmod 600
- [ ] CI secrets stored in GitHub Secrets, not workflow files
- [ ] Generated code reviewed before committing (no embedded tokens)
Instructions
Step 1: Figma Token Scope Restriction
# When creating a Figma Personal Access Token:
# - Give it the MINIMUM scope needed: File Content (read-only)
# - Do NOT grant write access unless you need Figma plugin features
# - Set an expiration date (90 days recommended)
# - Create separate tokens for dev vs CI environments
Step 2: Server-Side Only Enforcement
// src/anima/safety.ts
// Anima SDK is designed for server-side use only
function validateEnvironment(): void {
if (typeof window !== 'undefined') {
throw new Error('Anima SDK must run server-side only — never import in browser code');
}
if (!process.env.ANIMA_TOKEN) throw new Error('ANIMA_TOKEN not set');
if (!process.env.FIGMA_TOKEN) throw new Error('FIGMA_TOKEN not set');
}
// Call this at startup
validateEnvironment();
Step 3: Secret Manager Integration
// src/anima/secrets.ts
async function loadAnimaSecrets(): Promise<{ animaToken: string; figmaToken: string }> {
const { SecretManagerServiceClient } = await import('@google-cloud/secret-manager');
const client = new SecretManagerServiceClient();
const [animaVersion] = await client.accessSecretVersion({
name: `projects/${process.env.GCP_PROJECT}/secrets/anima-token/versions/latest`,
});
const [figmaVersion] = await client.accessSecretVersion({
name: `projects/${process.env.GCP_PROJECT}/secrets/figma-token/versions/latest`,
});
return {
animaToken: animaVersion.payload?.data?.toString() || '',
figmaToken: figmaVersion.payload?.data?.toString() || '',
};
}
Output
- Figma token with minimal scope (read-only)
- Server-side enforcement preventing browser usage
- Secrets loaded from cloud secret manager
Resources
Next Steps
For production deployment, see anima-prod-checklist.
Upgrade @animaapp/anima-sdk versions and handle API changes.
ReadWriteEditBash(npm:*)Grep
Anima Upgrade & Migration
Migration Paths
| From |
To |
Complexity |
| Figma plugin (manual) |
SDK automation |
Medium |
| SDK v1 → v2 |
SDK latest |
Low |
| Anima Playground |
SDK API |
Low |
Instructions
Step 1: Upgrade SDK
# Check current version
npm list @animaapp/anima-sdk
# Upgrade to latest
npm install @animaapp/anima-sdk@latest
# Check for breaking changes
npm info @animaapp/anima-sdk changelog
Step 2: Migrate from Manual Plugin to SDK
// BEFORE: Manual Figma plugin workflow
// 1. Open Figma → Plugins → Anima
// 2. Select component → Export → React
// 3. Copy-paste generated code into project
// 4. Manually repeat for each component change
// AFTER: Automated SDK workflow
import { Anima } from '@animaapp/anima-sdk';
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
// Automated: runs in CI on Figma file version change
async function syncDesignToCode() {
const { files } = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2', '3:4', '5:6'], // All design system components
settings: { language: 'typescript', framework: 'react', styling: 'tailwind' },
});
// Write to project, run through linter, create PR
for (const file of files) {
require('fs').writeFileSync(`src/components/generated/${file.fileName}`, file.content);
}
}
Step 3: API Changes Checklist
// Common API changes between versions:
// - New settings options (e.g., uiLibrary: 'shadcn' added later)
// - New frameworks (e.g., Next.js-specific output)
// - Response format changes in files array
// - New authentication methods
// Test after upgrade:
async function testUpgrade() {
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
const { files } = await anima.generateCode({
fileKey: process.env.FIGMA_FILE_KEY!,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: ['1:2'],
settings: { language: 'typescript', framework: 'react', styling: 'tailwind' },
});
console.log(`Upgrade test: ${files.length} files generated`);
}
Output
- SDK upgraded to latest version
- Migrated from manual plugin to automated SDK
- All generation tests passing after upgrade
Resources
Next Steps
For CI/CD setup, see anima-ci-integration.
Use Figma webhooks to trigger automatic Anima code generation on design changes.
ReadWriteEditBash(curl:*)
Anima Webhooks & Events
Overview
Anima doesn't have its own webhooks, but you can use Figma Webhooks (v2 API) to detect design changes and trigger Anima code generation automatically. This creates an event-driven design-to-code pipeline.
Instructions
Step 1: Register Figma Webhook
# Figma Webhooks API (requires team-level access)
curl -X POST "https://api.figma.com/v2/webhooks" \
-H "X-Figma-Token: ${FIGMA_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"event_type": "FILE_VERSION_UPDATE",
"team_id": "YOUR_TEAM_ID",
"endpoint": "https://your-server.com/webhooks/figma",
"passcode": "your-webhook-secret",
"description": "Trigger Anima code generation on design changes"
}'
Step 2: Webhook Handler
// src/webhooks/figma-handler.ts
import express from 'express';
import { Anima } from '@animaapp/anima-sdk';
const router = express.Router();
const anima = new Anima({ auth: { token: process.env.ANIMA_TOKEN! } });
interface FigmaWebhookEvent {
event_type: 'FILE_VERSION_UPDATE' | 'FILE_UPDATE' | 'FILE_DELETE';
file_key: string;
file_name: string;
triggered_by: { id: string; handle: string };
timestamp: string;
passcode: string;
}
router.post('/webhooks/figma', express.json(), async (req, res) => {
const event = req.body as FigmaWebhookEvent;
// Verify passcode
if (event.passcode !== process.env.FIGMA_WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Invalid passcode' });
}
// Only process file version updates
if (event.event_type !== 'FILE_VERSION_UPDATE') {
return res.status(200).json({ skipped: true });
}
console.log(`Design changed: ${event.file_name} by ${event.triggered_by.handle}`);
// Trigger async generation — respond immediately
regenerateComponents(event.file_key).catch(console.error);
res.status(200).json({ accepted: true });
});
async function regenerateComponents(fileKey: string) {
const COMPONENT_NODES = ['1:2', '3:4', '5:6']; // Your component node IDs
for (const nodeId of COMPONENT_NODES) {
try {
const { files } = await anima.generateCode({
fileKey,
figmaToken: process.env.FIGMA_TOKEN!,
nodesId: [nodeId],
settings: { language: 'typescript', framework: 'react', styling: 'tailwind' },
});
console.log(`Regenerated node ${nodeId}: ${files.length} files`);
await new Promise(r => setTimeout(r, 6000)); // Rate limit
} catch (err) {
console.error(`Failed to regenerate ${nodeId}:`, err);
}
}
}
export default router;
Step 3: Figma Webhook Event Types
|
|