4.1 KiB
/ Performance Investigation Summary
This is the high-level handoff for the default route at:
https://rover.otter.land/
The detailed issue writeups live in perf/issues/.
Main Finding
The / page is doing too much main-thread work for low-end devices. On the current powerful
machine it can appear smooth, but CPU throttling shows real risk for mobile and weaker
computers.
The biggest measured problem is repeated global input listener churn. The broader underlying theme is that high-frequency live data and broad React context invalidation cause many parts of the page to rerender or recommit DOM attributes.
Key Measurements
Clean / Profile, 8x Mobile CPU Throttle
Artifact:
perf/results/2026-06-11T03-15-51-398Z/report.json
Results:
average frame interval: ~140ms
p95 frame interval: ~166.8ms
p99 frame interval: ~383.4ms
long tasks: 67
event listener delta: +13,481
JS heap delta: +22.76MB
ScriptDuration delta: ~35.85s
TaskDuration delta: ~52.88s
Top notable CPU self-time included:
removeEventListener ~1.30s
addEventListener ~0.94s
Listener Audit
Artifact:
perf/results/2026-06-11T03-03-31-625Z-listeners/listener-report.json
Worst churn:
keydown adds=8040 removes=8039
keyup adds=8040 removes=8039
blur adds=8040 removes=8039
gamepadconnected adds=8040 removes=8039
gamepaddisconnected adds=8040 removes=8039
/ Runtime Audit, 6x Mobile CPU Throttle, 30s
Artifact:
perf/results/2026-06-11T03-21-51-263Z-root-runtime/root-runtime-report.json
Results:
average frame interval: ~88ms
p95 frame interval: 150ms
p99 frame interval: 183ms
long tasks: 18
WebSocket messages: at least 1000 sampled
WebSocket bytes: ~798KB sampled
DOM mutation records: 41,062
DOM attribute records: 40,761
Top sampled WebSocket events:
log:entry 526
sensorFrame 306
commandAck 145
session:sync 5
/ Runtime Audit With Mutation Targets, 6x Mobile CPU Throttle, 18s
Artifact:
perf/results/2026-06-11T03-22-44-714Z-root-runtime/root-runtime-report.json
Results:
average frame interval: ~116.6ms
p95 frame interval: ~166.7ms
p99 frame interval: ~316.6ms
long tasks: 16
DOM mutation records: 18,758
DOM attribute records: 18,490
Top WebSocket events:
log:entry 850
sensorFrame 277
commandAck 200
session:sync 23
Top mutation targets:
input.accent-emerald-400 name 5300
input.accent-emerald-400 type 2650
field-input name ~1300 each
div.h-full style 1238
path d 621
path fill 619
Ordered Work Plan
- Fix
KeyboardInputManagerandGamepadInputManagerlistener churn. - Split/stabilize
ControlContextso action consumers do not rerender on every state change. - Batch or gate
log:entrysocket updates. - Throttle visual telemetry rendering.
- Memoize or lazy-mount
ReplaySourcesPanel. - Split and memoize chat composer/nickname form.
- Clean up or share timers.
Reproduction Commands
Install Playwright dependency if missing:
npm install --prefix perf playwright@1.60.0
npx playwright install chromium
Clean CPU profile:
CPU_THROTTLE=8 VIEWPORT=390x844 MOBILE=1 node perf/live-cpu-profile.mjs https://rover.otter.land/ perf/results
Listener audit:
node perf/live-listener-audit.mjs https://rover.otter.land/ perf/results
Runtime audit:
CPU_THROTTLE=6 VIEWPORT=390x844 MOBILE=1 SAMPLE_MS=30000 node perf/live-root-runtime-audit.mjs https://rover.otter.land/ perf/results
Runtime audit with shorter mutation target sample:
CPU_THROTTLE=6 VIEWPORT=390x844 MOBILE=1 SAMPLE_MS=18000 node perf/live-root-runtime-audit.mjs https://rover.otter.land/ perf/results
Notes
The perf/results/2026-06-11T03-11-39-596Z-route-sweep/ route sweep includes /spectate,
/mini, /display, and /scanner. Those are not the current priority. Use them only for
context.