Install
$ agentstack add skill-medy-gribkov-arcana-performance-optimization ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Senior performance engineer who identifies bottlenecks and applies targeted optimizations with measurable impact.
Use this skill when
- Diagnosing or improving Core Web Vitals (LCP, INP, CLS)
- Reducing JavaScript bundle size or optimizing code splitting
- Implementing caching at any layer (HTTP, CDN, Redis, application)
- Optimizing database queries or fixing N+1 problems
- Debugging memory leaks in Node.js or browser
- Designing async processing pipelines for throughput
Core Web Vitals
LCP (Largest Contentful Paint) — Target: `
- Inline critical CSS, defer the rest. Use
crittersfor automated critical CSS extraction. - Set
fetchpriority="high"on the LCP image. Removeloading="lazy"from above-the-fold images. - Serve from CDN. Eliminate redirect chains.
- Use
103 Early Hintsto let the browser start fetching before HTML arrives.
INP (Interaction to Next Paint) — Target: 50ms) with scheduler.yield() or setTimeout(0).
- Move heavy computation to Web Workers.
- Debounce rapid-fire events (scroll, resize, input) — 100-150ms debounce.
- Avoid layout thrashing: batch DOM reads, then batch DOM writes.
- Use
content-visibility: autoon offscreen sections.
// Break a long task into yielding chunks
async function processItems(items: Item[]) {
for (let i = 0; i setTimeout(resolve, 0));
}
}
}
CLS (Cumulative Layout Shift) — Target: import("./pages/Dashboard"));
const Settings = lazy(() => import("./pages/Settings"));
// Component-level splitting for heavy UI const HeavyChart = lazy(() => import("./components/HeavyChart"));
function App() { return ( }>
} /> } />
); }
// Prefetch on hover for perceived instant loading function NavLink({ to, children }: { to: string; children: React.ReactNode }) { const prefetch = () => { if (to === "/dashboard") import("./pages/Dashboard"); }; return {children}; }
### Tree Shaking Essentials
- Use ESM (`import/export`), not CJS (`require`). CJS is not tree-shakeable.
- Set `"sideEffects": false` in package.json (or list files with side effects).
- Avoid barrel files (`index.ts` re-exporting everything) — they defeat tree shaking.
## Image Optimization
### Format Selection
| Format | Use for | Browser support |
|--------|---------|-----------------|
| AVIF | Photos, complex images. 50% smaller than JPEG. | Chrome, Firefox, Safari 16.4+ |
| WebP | Universal fallback. 30% smaller than JPEG. | All modern browsers |
| SVG | Icons, logos, simple graphics. Infinite scale. | Universal |
| PNG | Screenshots with text, transparency needed. | Universal |
### Next.js Image Component
```tsx
import Image from "next/image";
// Automatically serves AVIF > WebP > JPEG, responsive sizes, lazy loaded
Sharp for Server-Side Processing
import sharp from "sharp";
await sharp(inputBuffer)
.resize(1200, 630, { fit: "cover", position: "attention" }) // Smart crop
.avif({ quality: 50 }) // AVIF at quality 50 ≈ JPEG at quality 80
.toFile("output.avif");
Caching Strategies
HTTP Cache-Control Headers
# Static assets (hashed filenames): cache forever
Cache-Control: public, max-age=31536000, immutable
# API responses: revalidate after 60s, serve stale while revalidating
Cache-Control: public, max-age=60, stale-while-revalidate=300
# User-specific data: no shared cache
Cache-Control: private, max-age=0, must-revalidate
# Never cache
Cache-Control: no-store
Redis Caching Patterns
async function getCachedOrFetch(
key: string,
fetcher: () => Promise,
ttlSeconds: number
): Promise {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached) as T;
const data = await fetcher();
// SET with EX (expire) and NX (only if not exists) to prevent thundering herd
await redis.set(key, JSON.stringify(data), "EX", ttlSeconds);
return data;
}
// Cache-aside with stale-while-revalidate pattern
async function getWithSWR(key: string, fetcher: () => Promise, ttl: number): Promise {
const cached = await redis.get(key);
if (cached) {
const parsed = JSON.parse(cached) as { data: T; fetchedAt: number };
const age = Date.now() - parsed.fetchedAt;
if (age > ttl * 500) {
// Over 50% of TTL — revalidate in background
fetcher().then((fresh) =>
redis.set(key, JSON.stringify({ data: fresh, fetchedAt: Date.now() }), "EX", ttl)
);
}
return parsed.data;
}
const data = await fetcher();
await redis.set(key, JSON.stringify({ data, fetchedAt: Date.now() }), "EX", ttl);
return data;
}
Database Query Optimization
Index Strategy
- Run
EXPLAIN ANALYZEon every slow query. Look forSeq Scanon large tables. - Index columns used in
WHERE,JOIN,ORDER BY. Composite indexes: leftmost prefix matters. - Covering indexes: include all
SELECTcolumns so the DB reads only the index, not the table.
-- Composite index: supports WHERE user_id = ? AND created_at > ?
CREATE INDEX idx_orders_user_created ON orders (user_id, created_at DESC);
-- Covering index: query satisfied entirely from index
CREATE INDEX idx_orders_covering ON orders (user_id, created_at DESC)
INCLUDE (total_amount, status);
-- Partial index: only index rows that matter
CREATE INDEX idx_orders_pending ON orders (created_at)
WHERE status = 'pending';
N+1 Detection and Fix
// BAD: N+1 — 1 query for users + N queries for orders
const users = await db.query("SELECT * FROM users LIMIT 100");
for (const user of users) {
user.orders = await db.query("SELECT * FROM orders WHERE user_id = $1", [user.id]);
}
// GOOD: 2 queries total with a join or IN clause
const users = await db.query("SELECT * FROM users LIMIT 100");
const userIds = users.map((u) => u.id);
const orders = await db.query("SELECT * FROM orders WHERE user_id = ANY($1)", [userIds]);
const ordersByUser = Map.groupBy(orders, (o) => o.user_id);
for (const user of users) {
user.orders = ordersByUser.get(user.id) ?? [];
}
Memory Leak Detection
Node.js
# Start with inspector
node --inspect dist/server.js
# Generate heap snapshot programmatically
kill -USR2 # Node writes .heapsnapshot to cwd
Common Node.js leak sources:
- Event listeners never removed. Use
AbortControllerto clean up. - Closures capturing large objects. Null out references after use.
- Global caches without eviction. Use
lru-cachewithmaxandttl. - Unreferenced timers. Always
clearInterval/clearTimeouton shutdown.
import { LRUCache } from "lru-cache";
// Bounded cache: max 1000 entries, 5-minute TTL
const cache = new LRUCache({
max: 1000,
ttl: 1000 * 60 * 5,
});
Browser (Chrome DevTools)
- Open Memory tab. Take a heap snapshot (Snapshot 1).
- Perform the suspected leaking action (navigate, open modal, etc.).
- Take Snapshot 2. Use "Comparison" view to see allocated-but-not-freed objects.
- Look for
Detached HTMLDivElement— DOM nodes removed from tree but still referenced in JS. - Filter by "Objects allocated between Snapshot 1 and 2" to find the leak source.
Connection Pooling
// Go database/sql — pool is built in
db, err := sql.Open("postgres", connStr)
db.SetMaxOpenConns(25) // Match your DB's max_connections / number_of_instances
db.SetMaxIdleConns(10) // Keep idle connections warm
db.SetConnMaxLifetime(5 * time.Minute) // Rotate connections to rebalance after DB failover
db.SetConnMaxIdleTime(1 * time.Minute) // Close idle connections to free DB resources
// Node.js with pg pool
import { Pool } from "pg";
const pool = new Pool({
max: 20, // Max connections in pool
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 5000, // Fail fast if no connection available
});
// Always release connections — use pool.query() for auto-release
const result = await pool.query("SELECT * FROM users WHERE id = $1", [userId]);
Async Processing Patterns
When an API handler does work that isn't needed for the response, move it out of the request path.
// BAD: user waits for email sending + analytics
app.post("/signup", async (req, res) => {
const user = await createUser(req.body);
await sendWelcomeEmail(user); // 500ms
await trackSignupEvent(user); // 200ms
res.json(user); // Total: 700ms+ for user
});
// GOOD: respond immediately, process async via queue
app.post("/signup", async (req, res) => {
const user = await createUser(req.body);
await queue.add("send-welcome-email", { userId: user.id });
await queue.add("track-signup", { userId: user.id });
res.json(user); // Total: ~50ms for user
});
Use BullMQ (Node.js), Celery (Python), or a message broker (RabbitMQ, SQS) for production queues. Always make queue consumers idempotent — jobs may be retried.
Game Performance
Frame Budgets
| Target FPS | Frame Time | Platform | |------------|------------|----------| | 30 FPS | 33.3 ms | Console (heavy games) | | 60 FPS | 16.6 ms | PC, Console, Mobile | | 90 FPS | 11.1 ms | VR (minimum) | | 120 FPS | 8.3 ms | Competitive games | | 144+ FPS | 6.9 ms | High-end PC |
At 60 FPS (16.6ms), budget roughly 8ms CPU (game logic, physics, animation, audio) and 8ms GPU (geometry, lighting, post-process, UI).
CPU Optimization
- Algorithmic: Spatial hashing for neighbor queries, early-out conditions, reduce O(n^2) to O(n log n).
- Cache-friendly data: Data-oriented design (Struct of Arrays over Array of Structs), process data linearly, minimize cache misses.
- Allocation: Object pooling, pre-allocate collections, avoid GC in hot paths.
- Threading: Offload to job systems, async loading, parallel processing.
GPU Optimization
- Draw calls: Static/dynamic batching, GPU instancing, merge meshes. Target <2000 on PC, <200 on mobile.
- Overdraw: Front-to-back rendering, occlusion culling, reduce transparency.
- Shaders: Reduce instruction count, use half precision, minimize texture samples.
- Geometry: LOD systems, mesh simplification, frustum culling.
Platform Targets
Mobile constraints:
- Thermal throttling and battery drain are primary limits
- Memory: 500MB-2GB. Draw calls: 100-200. Triangles: 100K-500K/frame. Texture memory: 200-500MB.
- Target 30-60 FPS stable.
VR requirements:
- Maintain 90 FPS constantly (dropped frames cause nausea).
- Single-pass stereo rendering, fixed foveated rendering, aggressive LOD, minimal post-processing.
Frame Rate Troubleshooting
- Frame drops: Profile CPU vs GPU bound. Check for GC spikes. Move logic to FixedUpdate or coroutines. Add object pooling and LOD.
- Long loads: Async loading with progress bar. Stream assets in background. Compress aggressively. Pre-warm caches.
- Inconsistent pacing: Enable VSync. Use fixed timestep for physics. Spread heavy work across frames.
Profiling Tools
| Engine | CPU Profiler | GPU Profiler | Memory | |--------|--------------|--------------|--------| | Unity | Profiler | Frame Debugger | Memory Profiler | | Unreal | Insights | RenderDoc | Memreport | | Godot | Profiler | GPU Debugger | Built-in | | Any | Platform tools | RenderDoc/PIX | Valgrind/Instruments |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: medy-gribkov
- Source: medy-gribkov/arcana
- License: Apache-2.0
- Homepage: https://www.npmjs.com/package/@sporesec/arcana
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.