# Measure React Renders

> Compare React component render counts between origin/main and the current branch during a user-defined UI scenario (e.g. panel resize, navigation). Use when verifying that performance changes actually reduced re-renders.

- Skill: `imbue-ai/measure-react-renders` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add imbue-ai/measure-react-renders`
- Raw SKILL.md: https://api.skillmd.com/api/skills/imbue-ai/measure-react-renders/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: imbue-ai (https://skillmd.com/u/imbue-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/imbue-ai/measure-react-renders

---


# Render Performance Comparison

## Step 1: Create the baseline worktree

```bash
git fetch origin main
git worktree add /tmp/sculptor_baseline origin/main
cd /tmp/sculptor_baseline/sculptor/frontend && npm install --silent
```

## Step 2: Write the scenario file

If the user provides one, use it. Otherwise write a Python file exporting:

- `DESCRIPTION: str` — what is being measured
- `TARGET_COMPONENTS: list[str]` — component names to highlight
- `setup(page, base_url, workspace_id, task_id)` — navigate + wait
- `action(page)` — perform the action to measure

Component names must be **unminified** source names (e.g. `SplittableSectionComponent`
for the memo-wrapped `SplittableSection` export, `AlphaChatInterface` if not wrapped).

See `scenarios/panel_resize.py` for an example.

## Step 3: Run the comparison

```bash
uv run --project sculptor python \
  .claude/skills/measure-react-renders/scripts/perf_compare.py \
  --baseline-dir /tmp/sculptor_baseline \
  --current-dir "$(pwd)" \
  --scenario path/to/scenario.py
```

Use `--skip-build` if frontends are already built.

The script builds both frontends with `--minify false` (preserves component
names), starts two isolated backends, injects `__REACT_DEVTOOLS_GLOBAL_HOOK__`
via Playwright's `addInitScript` before React loads, runs the scenario, and
prints a comparison table.

## Step 4: Cleanup

```bash
git worktree remove /tmp/sculptor_baseline
```

## Scenario example

```python
import time

DESCRIPTION = "Section resize render cascade"
TARGET_COMPONENTS = ["AlphaChatInterface", "SectionGrid", "SplittableSectionComponent"]

def setup(page, base_url, workspace_id, task_id):
    page.goto(f"{base_url}/#/ws/{workspace_id}/agent/{task_id}")
    page.wait_for_load_state("networkidle")
    time.sleep(5)

def action(page):
    handles = page.locator('[role="separator"]').all()
    handle = handles[-1]
    handle.focus()
    time.sleep(0.3)
    for _ in range(5):
        page.keyboard.press("ArrowLeft")
        time.sleep(0.15)
    for _ in range(5):
        page.keyboard.press("ArrowRight")
        time.sleep(0.15)
```

