--- name: rezi-perf-profiling description: Profile and optimize Rezi app performance. Use when app feels slow, frames drop, or render phases take too long. user-invocable: true allowed-tools: Read, Glob, Grep, Bash(REZI_PERF=1 REZI_PERF_DETAIL=1 *), Bash(npx tsx packages/bench/*) argument-hint: "[performance-concern]" metadata: short-description: Performance profiling --- ## When to use Use this skill when: - App feels slow or unresponsive - Frames drop or input lags - Need to identify which render phase is the bottleneck - Optimizing a specific widget or screen ## Source of truth - `packages/core/src/app/widgetRenderer.ts` — render pipeline with phase timing - `packages/core/src/runtime/commit.ts` — reconciliation (leaf/container reuse) - `packages/core/src/layout/` — layout engine (FNV-1a stability signatures) - `packages/core/src/widgets/composition.ts` — animation utility hooks - `packages/bench/src/` — profiling scripts ## Steps 1. **Enable profiling** and run: ```bash REZI_PERF=1 REZI_PERF_DETAIL=1 node your-app.js ``` 2. **Observe phase timings**: view → commit → layout → render → build 3. **Run systematic profiling**: ```bash npx tsx packages/bench/src/profile-phases.ts npx tsx packages/bench/src/profile-construction.ts ``` 4. **Apply common fixes**: | Bottleneck | Fix | |-----------|-----| | View phase slow | `ctx.useMemo(() => expensiveComputation, [deps])` for expensive computations | | Commit phase slow | Add `key` props on list items for stable reconciliation | | Layout phase slow | Reduce nesting depth; layout stability signatures skip relayout when tree is stable | | Render phase slow | Use `ui.virtualList()` for large datasets | | Animation-heavy screen slow | Limit transition scope (`properties`), animate only visible rows, avoid per-frame object churn | | Overall slow | Flatten unnecessary wrapper nodes | 5. **Depth guardrails**: - Warning at 200 levels - Fatal at 500 levels - Refactor deep nesting into flatter structures ## Key optimization patterns - `ctx.useMemo(() => expensiveComputation, [deps])` — skip recomputation - `key` on every list item — enables O(1) reconciliation - `ui.virtualList()` — only renders visible rows - `useStagger(...)` + `ui.virtualList(...)` — stagger only the visible window - `ui.box({ transition: { properties: [...] } })` — animate only required dimensions - Avoid creating new closures/objects in render — use `ctx.useCallback(fn, [deps])`