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 pipelinepackages/core/src/app/__tests__/widgetRenderer.transition.test.ts— transition behavior expectationspackages/core/src/runtime/commit.ts— VNode → RuntimeInstance treepackages/core/src/layout/— layout enginepackages/core/src/renderer/renderToDrawlist/— draw operationspackages/core/src/widgets/composition.ts— animation hook implementationspackages/core/src/ui/— design tokens, recipes, and capability tiers
Debugging steps
-
Enable profiling:
REZI_PERF=1 REZI_PERF_DETAIL=1 node your-app.js -
Check VNode tree structure — ensure no missing children or null nodes
-
Check widget IDs — must be unique across the entire tree. Duplicate IDs cause unpredictable behavior
-
Check nesting depth:
- Warning at 200 levels
- Fatal at 500 levels
- Flatten unnecessary wrapper nodes
-
Check
keyprops on list items — missing keys cause full re-render and lost state -
Inspect with test renderer:
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 -
Review layout props:
width,height,flex,p,gap,align -
If animation is involved, verify:
- container widgets (
ui.box,ui.row,ui.column,ui.grid) usetransitionwith expectedproperties(position,size,opacity) properties: []is not accidentally disabling tracksopacitystays within[0..1]exitTransitionexists 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
- container widgets (
-
Read enriched runtime errors carefully:
ZRUI_DUPLICATE_IDnow includes both conflicting widget kinds +ctx.id()guidanceZRUI_DUPLICATE_KEYincludes the duplicate key and parent contextZRUI_INVALID_PROPSincludes prop name, widget kind, and expected typeZRUI_UPDATE_DURING_RENDERincludes 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 |