--- name: rezi-debug-rendering description: Debug rendering and layout issues in Rezi apps. Use when UI looks wrong, has layout problems, or renders unexpectedly. user-invocable: true allowed-tools: Read, Glob, Grep, Bash(REZI_PERF=1 *) argument-hint: "[symptom-description]" metadata: short-description: Debug rendering --- ## When to use Use this skill when: - UI does not look right or has layout problems - Widgets overlap, disappear, or have wrong dimensions - Unexpected re-renders or flicker - Performance issues during rendering ## Source of truth - `packages/core/src/app/widgetRenderer.ts` — full render pipeline - `packages/core/src/app/__tests__/widgetRenderer.transition.test.ts` — transition behavior expectations - `packages/core/src/runtime/commit.ts` — VNode → RuntimeInstance tree - `packages/core/src/layout/` — layout engine - `packages/core/src/renderer/renderToDrawlist/` — draw operations - `packages/core/src/widgets/composition.ts` — animation hook implementations - `packages/core/src/ui/` — design tokens, recipes, and capability tiers ## Debugging steps 1. **Enable profiling**: ```bash REZI_PERF=1 REZI_PERF_DETAIL=1 node your-app.js ``` 2. **Check VNode tree structure** — ensure no missing children or null nodes 3. **Check widget IDs** — must be unique across the entire tree. Duplicate IDs cause unpredictable behavior 4. **Check nesting depth**: - Warning at 200 levels - Fatal at 500 levels - Flatten unnecessary wrapper nodes 5. **Check `key` props** on list items — missing keys cause full re-render and lost state 6. **Inspect with test renderer**: ```typescript const r = createTestRenderer({ viewport: { cols: 80, rows: 24 } }); const result = r.render(myView(state)); console.log(result.toText()); // see actual output result.findById("my-widget"); // locate specific nodes ``` 7. **Review layout props**: `width`, `height`, `flex`, `p`, `gap`, `align` 8. **If animation is involved**, verify: - container widgets (`ui.box`, `ui.row`, `ui.column`, `ui.grid`) use `transition` with expected `properties` (`position`, `size`, `opacity`) - `properties: []` is not accidentally disabling tracks - `opacity` stays within `[0..1]` - `exitTransition` exists on nodes that should animate out before removal - keyed re-entry behavior is intentional (same key cancels in-flight exit) - exiting nodes are expected to be render-only (not focusable/hit-testable) - animation hooks are not conditionally called 9. **Read enriched runtime errors carefully**: - `ZRUI_DUPLICATE_ID` now includes both conflicting widget kinds + `ctx.id()` guidance - `ZRUI_DUPLICATE_KEY` includes the duplicate key and parent context - `ZRUI_INVALID_PROPS` includes prop name, widget kind, and expected type - `ZRUI_UPDATE_DURING_RENDER` includes guidance to move updates into event handlers/effects ## Common causes | Symptom | Likely cause | |---------|-------------| | Widget not visible | Missing from VNode tree, or zero width/height | | Overlapping widgets | Wrong container type (use `column`/`row` not `box`) | | Content truncated | Fixed width too small, missing `flex` | | Flicker/full re-render | Missing `key` on list items | | Transition not animating | `transition` missing, wrong `properties`, or no actual value delta | | Opacity animation looks wrong | `opacity` outside `[0..1]` (clamped) or `properties` excludes `opacity` | | Exit animation not visible | Missing `exitTransition`, zero/invalid duration, or node has no stable key | | Exit node still interactive | Exit nodes are render-only; focus/hit-test should come from active tree only | | Crash on deep tree | Nesting depth > 500 | | DS styling not applied | DS styling is automatic with `ThemeDefinition`; check semantic tokens/theme activation (no `dsVariant` required) | | Wheel scrolling not working | Ensure the container uses `overflow: "scroll"` and content exceeds viewport size |