mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
slopfixing / issue 002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
# FIXED!
|
||||
# Issue 001: Global Input Listener Churn
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -0,0 +1,849 @@
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/",
|
||||
"runDir": "perf/results/2026-06-12T06-07-57-124Z-root-runtime",
|
||||
"environment": {
|
||||
"cpuThrottle": 6,
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"isMobile": true,
|
||||
"sampleMs": 10000
|
||||
},
|
||||
"metrics": {
|
||||
"Timestamp": 23292.158609,
|
||||
"AudioHandlers": 0,
|
||||
"AudioWorkletProcessors": 0,
|
||||
"Documents": 3,
|
||||
"Frames": 1,
|
||||
"JSEventListeners": 398,
|
||||
"LayoutObjects": 1945,
|
||||
"MediaKeySessions": 0,
|
||||
"MediaKeys": 0,
|
||||
"Nodes": 2266,
|
||||
"Resources": 18,
|
||||
"ContextLifecycleStateObservers": 13,
|
||||
"V8PerContextDatas": 4,
|
||||
"WorkerGlobalScopes": 0,
|
||||
"UACSSResources": 0,
|
||||
"RTCPeerConnections": 0,
|
||||
"ResourceFetchers": 3,
|
||||
"AdSubframes": 0,
|
||||
"DetachedScriptStates": 2,
|
||||
"ArrayBufferContents": 3,
|
||||
"LayoutCount": 12,
|
||||
"RecalcStyleCount": 30,
|
||||
"LayoutDuration": 0.928481,
|
||||
"RecalcStyleDuration": 0.991796,
|
||||
"DevToolsCommandDuration": 0.000323,
|
||||
"ScriptDuration": 6.326745,
|
||||
"V8CompileDuration": 0,
|
||||
"TaskDuration": 11.079249,
|
||||
"TaskOtherDuration": 2.831904,
|
||||
"ThreadTime": 11.911973,
|
||||
"ProcessTime": 14.42,
|
||||
"JSHeapUsedSize": 8961292,
|
||||
"JSHeapTotalSize": 12058624,
|
||||
"FirstMeaningfulPaint": 0,
|
||||
"DomContentLoaded": 23282.130574,
|
||||
"NavigationStart": 23279.964199
|
||||
},
|
||||
"snapshot": {
|
||||
"elapsedMs": 20101.5,
|
||||
"listeners": [
|
||||
{
|
||||
"key": "add:input:invalid",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "add:window:online",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "add:document:visibilitychange",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "remove:window:online",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:document:visibilitychange",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "add:audio:canplay",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:ended",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:error",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:pause",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:play",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:stalled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:audio:waiting",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:auxclick",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:click",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:contextmenu",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:copy",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:cut",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drag",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragend",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragenter",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragexit",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragleave",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragover",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragstart",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drop",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:gotpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:input",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keydown",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keypress",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keyup",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:lostpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mousedown",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mousemove",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mouseout",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mouseover",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mouseup",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:paste",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:pointercancel",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:pointerdown",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:pointermove",
|
||||
"count": 2
|
||||
}
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"key": "timeout:0",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "interval:250",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "interval:60000",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "timeout:12000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "interval:200",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "timeout:15000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "interval:1000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "interval:2000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:4000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:10000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "interval:3000",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"timeouts": 10,
|
||||
"intervals": 12,
|
||||
"timeoutFires": 4,
|
||||
"intervalFires": 45,
|
||||
"webSocketMessageCount": 285,
|
||||
"webSocketBytes": 5610397,
|
||||
"webSocketEvents": [
|
||||
{
|
||||
"event": "log:entry",
|
||||
"count": 150,
|
||||
"bytes": 35714
|
||||
},
|
||||
{
|
||||
"event": "sensorFrame",
|
||||
"count": 76,
|
||||
"bytes": 142196
|
||||
},
|
||||
{
|
||||
"event": "session:sync",
|
||||
"count": 18,
|
||||
"bytes": 306294
|
||||
},
|
||||
{
|
||||
"event": "commandAck",
|
||||
"count": 12,
|
||||
"bytes": 1128
|
||||
},
|
||||
{
|
||||
"event": "",
|
||||
"count": 4,
|
||||
"bytes": 4992972
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:frame",
|
||||
"count": 3,
|
||||
"bytes": 291
|
||||
},
|
||||
{
|
||||
"event": "0{\"sid\":\"CQG",
|
||||
"count": 1,
|
||||
"bytes": 106
|
||||
},
|
||||
{
|
||||
"event": "40{\"sid\":\"-s",
|
||||
"count": 1,
|
||||
"bytes": 32
|
||||
},
|
||||
{
|
||||
"event": "mode",
|
||||
"count": 1,
|
||||
"bytes": 27
|
||||
},
|
||||
{
|
||||
"event": "controlGranted",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "alert",
|
||||
"count": 1,
|
||||
"bytes": 128
|
||||
},
|
||||
{
|
||||
"event": "alert:new",
|
||||
"count": 1,
|
||||
"bytes": 165
|
||||
},
|
||||
{
|
||||
"event": "auth:role",
|
||||
"count": 1,
|
||||
"bytes": 31
|
||||
},
|
||||
{
|
||||
"event": "rovers",
|
||||
"count": 1,
|
||||
"bytes": 5453
|
||||
},
|
||||
{
|
||||
"event": "chat:init",
|
||||
"count": 1,
|
||||
"bytes": 77613
|
||||
},
|
||||
{
|
||||
"event": "overseer:memory",
|
||||
"count": 1,
|
||||
"bytes": 520
|
||||
},
|
||||
{
|
||||
"event": "log:init",
|
||||
"count": 1,
|
||||
"bytes": 44230
|
||||
},
|
||||
{
|
||||
"event": "barcode:state",
|
||||
"count": 1,
|
||||
"bytes": 1627
|
||||
},
|
||||
{
|
||||
"event": "kinect:pointCloudFrame",
|
||||
"count": 1,
|
||||
"bytes": 262
|
||||
},
|
||||
{
|
||||
"event": "kinect:colorFrame",
|
||||
"count": 1,
|
||||
"bytes": 169
|
||||
},
|
||||
{
|
||||
"event": "430[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 40
|
||||
},
|
||||
{
|
||||
"event": "431[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 194
|
||||
},
|
||||
{
|
||||
"event": "432[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 133
|
||||
},
|
||||
{
|
||||
"event": "roverHostStats",
|
||||
"count": 1,
|
||||
"bytes": 766
|
||||
},
|
||||
{
|
||||
"event": "2",
|
||||
"count": 1,
|
||||
"bytes": 1
|
||||
},
|
||||
{
|
||||
"event": "433[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 145
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:status",
|
||||
"count": 1,
|
||||
"bytes": 79
|
||||
},
|
||||
{
|
||||
"event": "WALL-E",
|
||||
"count": 1,
|
||||
"bytes": 40
|
||||
}
|
||||
],
|
||||
"mutationsTotal": {
|
||||
"records": 4729,
|
||||
"added": 175,
|
||||
"removed": 11,
|
||||
"attrs": 4524,
|
||||
"text": 19
|
||||
},
|
||||
"mutationTargets": [
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:name",
|
||||
"count": 1866
|
||||
},
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:type",
|
||||
"count": 933
|
||||
},
|
||||
{
|
||||
"key": "div.h-full:attributes:style",
|
||||
"count": 580
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:d",
|
||||
"count": 292
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:fill",
|
||||
"count": 290
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:name",
|
||||
"count": 242
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:type",
|
||||
"count": 121
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:name",
|
||||
"count": 28
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:name",
|
||||
"count": 28
|
||||
},
|
||||
{
|
||||
"key": "Text:characterData:",
|
||||
"count": 19
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.chat-composer-input:attributes:name",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:name",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:name",
|
||||
"count": 14
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:type",
|
||||
"count": 14
|
||||
},
|
||||
{
|
||||
"key": "section.panel-section.border:attributes:style",
|
||||
"count": 10
|
||||
},
|
||||
{
|
||||
"key": "input.min-w-0.flex-1:attributes:name",
|
||||
"count": 10
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:type",
|
||||
"count": 9
|
||||
},
|
||||
{
|
||||
"key": "header.flex.items-center:attributes:style",
|
||||
"count": 9
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:type",
|
||||
"count": 7
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:stroke",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.min-h-9:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:value",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "span.inline-flex.items-center:attributes:class",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:value",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:playsinline",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:autoplay",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:disableremoteplayback",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "div.rounded-sm.px-2:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "div.flex.flex-col:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:placeholder",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.min-w-0:attributes:disabled",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "div.fixed.bottom-2:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "div.mobile-touch-control.flex:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:value",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.text-sm:attributes:disabled",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:autoplay",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:disableremoteplayback",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"mutationBursts": [
|
||||
{
|
||||
"at": 7974,
|
||||
"records": 241,
|
||||
"added": 123,
|
||||
"removed": 6,
|
||||
"attrs": 110,
|
||||
"text": 2
|
||||
},
|
||||
{
|
||||
"at": 11575,
|
||||
"records": 147,
|
||||
"added": 11,
|
||||
"removed": 2,
|
||||
"attrs": 132,
|
||||
"text": 2
|
||||
},
|
||||
{
|
||||
"at": 12385,
|
||||
"records": 131,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 127,
|
||||
"text": 4
|
||||
},
|
||||
{
|
||||
"at": 12981,
|
||||
"records": 119,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 119,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 18332,
|
||||
"records": 117,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 116,
|
||||
"text": 1
|
||||
},
|
||||
{
|
||||
"at": 17140,
|
||||
"records": 111,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 111,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 13371,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 13636,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 13804,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 14271,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15643,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15909,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 18503,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15238,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15283,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15415,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15495,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 15947,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 16169,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 16317,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
}
|
||||
],
|
||||
"frames": {
|
||||
"count": 86,
|
||||
"average": 206.1918604651163,
|
||||
"p95": 566.5999999999995,
|
||||
"p99": 3399.8999999999996
|
||||
},
|
||||
"longTasks": {
|
||||
"count": 61,
|
||||
"top": [
|
||||
{
|
||||
"startTime": 5290.5,
|
||||
"duration": 2689,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 365.4000000022352,
|
||||
"duration": 1807,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 2182.900000002235,
|
||||
"duration": 1038,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 10371.10000000149,
|
||||
"duration": 709,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 9852,
|
||||
"duration": 519,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 8202.60000000149,
|
||||
"duration": 394,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 3221.699999999255,
|
||||
"duration": 385,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 3882.5,
|
||||
"duration": 356,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 11221.5,
|
||||
"duration": 353,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 18042.900000002235,
|
||||
"duration": 292,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 12110.900000002235,
|
||||
"duration": 276,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 12738.800000000745,
|
||||
"duration": 243,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 16946.5,
|
||||
"duration": 195,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 11575.5,
|
||||
"duration": 186,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 3615.60000000149,
|
||||
"duration": 185,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 14671.699999999255,
|
||||
"duration": 160,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 4239.199999999255,
|
||||
"duration": 130,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 14837.5,
|
||||
"duration": 110,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 15717.60000000149,
|
||||
"duration": 108,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 17352.400000002235,
|
||||
"duration": 107,
|
||||
"name": "self"
|
||||
}
|
||||
]
|
||||
},
|
||||
"consoleErrors": []
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 680 KiB |
@@ -0,0 +1,900 @@
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/",
|
||||
"runDir": "perf/results/2026-06-12T06-09-03-973Z-root-runtime",
|
||||
"environment": {
|
||||
"cpuThrottle": 8,
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"isMobile": true,
|
||||
"sampleMs": 30000
|
||||
},
|
||||
"metrics": {
|
||||
"Timestamp": 23379.874681,
|
||||
"AudioHandlers": 0,
|
||||
"AudioWorkletProcessors": 0,
|
||||
"Documents": 3,
|
||||
"Frames": 1,
|
||||
"JSEventListeners": 683,
|
||||
"LayoutObjects": 1975,
|
||||
"MediaKeySessions": 0,
|
||||
"MediaKeys": 0,
|
||||
"Nodes": 2710,
|
||||
"Resources": 20,
|
||||
"ContextLifecycleStateObservers": 20,
|
||||
"V8PerContextDatas": 4,
|
||||
"WorkerGlobalScopes": 0,
|
||||
"UACSSResources": 0,
|
||||
"RTCPeerConnections": 4,
|
||||
"ResourceFetchers": 3,
|
||||
"AdSubframes": 0,
|
||||
"DetachedScriptStates": 2,
|
||||
"ArrayBufferContents": 12,
|
||||
"LayoutCount": 49,
|
||||
"RecalcStyleCount": 77,
|
||||
"LayoutDuration": 1.49198,
|
||||
"RecalcStyleDuration": 1.886372,
|
||||
"DevToolsCommandDuration": 0.000349,
|
||||
"ScriptDuration": 14.419283,
|
||||
"V8CompileDuration": 0,
|
||||
"TaskDuration": 29.584723,
|
||||
"TaskOtherDuration": 11.786739,
|
||||
"ThreadTime": 32.430498,
|
||||
"ProcessTime": 38.63,
|
||||
"JSHeapUsedSize": 7496328,
|
||||
"JSHeapTotalSize": 13107200,
|
||||
"FirstMeaningfulPaint": 0,
|
||||
"DomContentLoaded": 23349.78059,
|
||||
"NavigationStart": 23346.788167
|
||||
},
|
||||
"snapshot": {
|
||||
"elapsedMs": 38566.699999999255,
|
||||
"listeners": [
|
||||
{
|
||||
"key": "add:input:invalid",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "add:window:online",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:document:visibilitychange",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:canplay",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:ended",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:error",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:pause",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:play",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:stalled",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:waiting",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "remove:window:online",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "remove:document:visibilitychange",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:play",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:pause",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:ended",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:error",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:waiting",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:canplay",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:stalled",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "add:WebSocket:message",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:auxclick",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:click",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:contextmenu",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:copy",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:cut",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drag",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragend",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragenter",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragexit",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragleave",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragover",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragstart",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drop",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:gotpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:input",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keydown",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keypress",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keyup",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:lostpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mousedown",
|
||||
"count": 2
|
||||
}
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"key": "timeout:0",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "interval:250",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "interval:200",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "timeout:2000",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "timeout:12000",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "interval:60000",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "timeout:15000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "timeout:4000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "interval:3000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "interval:1000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "interval:2000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:10000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:1282",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:1257",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"timeouts": 19,
|
||||
"intervals": 15,
|
||||
"timeoutFires": 10,
|
||||
"intervalFires": 121,
|
||||
"webSocketMessageCount": 533,
|
||||
"webSocketBytes": 11199188,
|
||||
"webSocketEvents": [
|
||||
{
|
||||
"event": "log:entry",
|
||||
"count": 308,
|
||||
"bytes": 71889
|
||||
},
|
||||
{
|
||||
"event": "sensorFrame",
|
||||
"count": 90,
|
||||
"bytes": 168271
|
||||
},
|
||||
{
|
||||
"event": "commandAck",
|
||||
"count": 36,
|
||||
"bytes": 3396
|
||||
},
|
||||
{
|
||||
"event": "session:sync",
|
||||
"count": 33,
|
||||
"bytes": 560916
|
||||
},
|
||||
{
|
||||
"event": "",
|
||||
"count": 14,
|
||||
"bytes": 10130394
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:frame",
|
||||
"count": 10,
|
||||
"bytes": 967
|
||||
},
|
||||
{
|
||||
"event": "mode",
|
||||
"count": 2,
|
||||
"bytes": 54
|
||||
},
|
||||
{
|
||||
"event": "controlGranted",
|
||||
"count": 2,
|
||||
"bytes": 82
|
||||
},
|
||||
{
|
||||
"event": "alert",
|
||||
"count": 2,
|
||||
"bytes": 256
|
||||
},
|
||||
{
|
||||
"event": "alert:new",
|
||||
"count": 2,
|
||||
"bytes": 330
|
||||
},
|
||||
{
|
||||
"event": "auth:role",
|
||||
"count": 2,
|
||||
"bytes": 62
|
||||
},
|
||||
{
|
||||
"event": "rovers",
|
||||
"count": 2,
|
||||
"bytes": 10906
|
||||
},
|
||||
{
|
||||
"event": "chat:init",
|
||||
"count": 2,
|
||||
"bytes": 155226
|
||||
},
|
||||
{
|
||||
"event": "overseer:memory",
|
||||
"count": 2,
|
||||
"bytes": 1040
|
||||
},
|
||||
{
|
||||
"event": "log:init",
|
||||
"count": 2,
|
||||
"bytes": 89130
|
||||
},
|
||||
{
|
||||
"event": "barcode:state",
|
||||
"count": 2,
|
||||
"bytes": 3254
|
||||
},
|
||||
{
|
||||
"event": "kinect:pointCloudFrame",
|
||||
"count": 2,
|
||||
"bytes": 524
|
||||
},
|
||||
{
|
||||
"event": "kinect:colorFrame",
|
||||
"count": 2,
|
||||
"bytes": 338
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:status",
|
||||
"count": 2,
|
||||
"bytes": 156
|
||||
},
|
||||
{
|
||||
"event": "0{\"sid\":\"a3i",
|
||||
"count": 1,
|
||||
"bytes": 106
|
||||
},
|
||||
{
|
||||
"event": "40{\"sid\":\"Bp",
|
||||
"count": 1,
|
||||
"bytes": 32
|
||||
},
|
||||
{
|
||||
"event": "430[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 40
|
||||
},
|
||||
{
|
||||
"event": "431[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 194
|
||||
},
|
||||
{
|
||||
"event": "2",
|
||||
"count": 1,
|
||||
"bytes": 1
|
||||
},
|
||||
{
|
||||
"event": "432[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 133
|
||||
},
|
||||
{
|
||||
"event": "433[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 145
|
||||
},
|
||||
{
|
||||
"event": "WALL-E",
|
||||
"count": 1,
|
||||
"bytes": 40
|
||||
},
|
||||
{
|
||||
"event": "0{\"sid\":\"3kq",
|
||||
"count": 1,
|
||||
"bytes": 106
|
||||
},
|
||||
{
|
||||
"event": "40{\"sid\":\"BX",
|
||||
"count": 1,
|
||||
"bytes": 32
|
||||
},
|
||||
{
|
||||
"event": "436[{\"error\"",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "437[{\"error\"",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "438[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 133
|
||||
},
|
||||
{
|
||||
"event": "439[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 145
|
||||
},
|
||||
{
|
||||
"event": "Freaky",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "roverHostStats",
|
||||
"count": 1,
|
||||
"bytes": 767
|
||||
}
|
||||
],
|
||||
"mutationsTotal": {
|
||||
"records": 6037,
|
||||
"added": 199,
|
||||
"removed": 35,
|
||||
"attrs": 5767,
|
||||
"text": 36
|
||||
},
|
||||
"mutationTargets": [
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:name",
|
||||
"count": 2648
|
||||
},
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:type",
|
||||
"count": 1324
|
||||
},
|
||||
{
|
||||
"key": "div.h-full:attributes:style",
|
||||
"count": 512
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:name",
|
||||
"count": 338
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:d",
|
||||
"count": 262
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:fill",
|
||||
"count": 256
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:type",
|
||||
"count": 169
|
||||
},
|
||||
{
|
||||
"key": "Text:characterData:",
|
||||
"count": 36
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:name",
|
||||
"count": 32
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:name",
|
||||
"count": 28
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:name",
|
||||
"count": 22
|
||||
},
|
||||
{
|
||||
"key": "section.panel-section.border:attributes:style",
|
||||
"count": 20
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.chat-composer-input:attributes:name",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "header.flex.items-center:attributes:style",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:stroke",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:name",
|
||||
"count": 14
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:type",
|
||||
"count": 14
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:type",
|
||||
"count": 11
|
||||
},
|
||||
{
|
||||
"key": "input.min-w-0.flex-1:attributes:name",
|
||||
"count": 10
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:type",
|
||||
"count": 7
|
||||
},
|
||||
{
|
||||
"key": "div.rounded-sm.px-2:attributes:class",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "div.fixed.bottom-2:attributes:class",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:value",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "span.inline-flex.items-center:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.min-h-9:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "div.mobile-touch-control.flex:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:placeholder",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:playsinline",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:autoplay",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:disableremoteplayback",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:autoplay",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:disableremoteplayback",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:value",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "span.inline-block.rounded:attributes:style",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "div.flex.flex-col:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.min-w-0:attributes:disabled",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:value",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.text-sm:attributes:disabled",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"mutationBursts": [
|
||||
{
|
||||
"at": 10936,
|
||||
"records": 241,
|
||||
"added": 123,
|
||||
"removed": 6,
|
||||
"attrs": 110,
|
||||
"text": 2
|
||||
},
|
||||
{
|
||||
"at": 27789,
|
||||
"records": 177,
|
||||
"added": 9,
|
||||
"removed": 17,
|
||||
"attrs": 145,
|
||||
"text": 6
|
||||
},
|
||||
{
|
||||
"at": 17412,
|
||||
"records": 133,
|
||||
"added": 2,
|
||||
"removed": 2,
|
||||
"attrs": 118,
|
||||
"text": 11
|
||||
},
|
||||
{
|
||||
"at": 31614,
|
||||
"records": 111,
|
||||
"added": 2,
|
||||
"removed": 1,
|
||||
"attrs": 104,
|
||||
"text": 4
|
||||
},
|
||||
{
|
||||
"at": 37740,
|
||||
"records": 100,
|
||||
"added": 0,
|
||||
"removed": 1,
|
||||
"attrs": 99,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 38360,
|
||||
"records": 99,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 99,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 17915,
|
||||
"records": 59,
|
||||
"added": 11,
|
||||
"removed": 2,
|
||||
"attrs": 45,
|
||||
"text": 1
|
||||
},
|
||||
{
|
||||
"at": 19317,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 20163,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 20363,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 23753,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 24543,
|
||||
"records": 51,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 51,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 31831,
|
||||
"records": 51,
|
||||
"added": 11,
|
||||
"removed": 2,
|
||||
"attrs": 37,
|
||||
"text": 1
|
||||
},
|
||||
{
|
||||
"at": 18579,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 18763,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 19129,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 19374,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 21234,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 22011,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 22767,
|
||||
"records": 47,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 47,
|
||||
"text": 0
|
||||
}
|
||||
],
|
||||
"frames": {
|
||||
"count": 181,
|
||||
"average": 185.53591160220995,
|
||||
"p95": 349.90000000000146,
|
||||
"p99": 1849.9000000000015
|
||||
},
|
||||
"longTasks": {
|
||||
"count": 165,
|
||||
"top": [
|
||||
{
|
||||
"startTime": 7151.60000000149,
|
||||
"duration": 3795,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 459.6000000014901,
|
||||
"duration": 2544,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 3019.199999999255,
|
||||
"duration": 1426,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 29673.900000002235,
|
||||
"duration": 1066,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 14211,
|
||||
"duration": 972,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 28901.800000000745,
|
||||
"duration": 772,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 13490.699999999255,
|
||||
"duration": 720,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 16782.400000002235,
|
||||
"duration": 639,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 11240.199999999255,
|
||||
"duration": 552,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 31092.5,
|
||||
"duration": 524,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 4445.60000000149,
|
||||
"duration": 495,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 5394.800000000745,
|
||||
"duration": 459,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 27348.199999999255,
|
||||
"duration": 445,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 24835.10000000149,
|
||||
"duration": 363,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 4963.800000000745,
|
||||
"duration": 272,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 37513.60000000149,
|
||||
"duration": 228,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 17919.5,
|
||||
"duration": 215,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 27801.60000000149,
|
||||
"duration": 193,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 17425.10000000149,
|
||||
"duration": 179,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 31885.900000002235,
|
||||
"duration": 176,
|
||||
"name": "self"
|
||||
}
|
||||
]
|
||||
},
|
||||
"consoleErrors": []
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 703 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@@ -0,0 +1,529 @@
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/",
|
||||
"runDir": "perf/results/2026-06-12T06-11-56-994Z",
|
||||
"elapsedMs": 83940,
|
||||
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/148.0.7778.96 Safari/537.36",
|
||||
"title": "Roomba Rover",
|
||||
"finalUrl": "http://127.0.0.1:4173/",
|
||||
"environment": {
|
||||
"cpuThrottle": 8,
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"isMobile": true
|
||||
},
|
||||
"metrics": {
|
||||
"afterLoad": {
|
||||
"Timestamp": 23527.948042,
|
||||
"Documents": 3,
|
||||
"Frames": 1,
|
||||
"JSEventListeners": 267,
|
||||
"Nodes": 651,
|
||||
"LayoutCount": 5,
|
||||
"RecalcStyleCount": 7,
|
||||
"LayoutDuration": 0.500736,
|
||||
"RecalcStyleDuration": 0.283234,
|
||||
"ScriptDuration": 5.693685,
|
||||
"TaskDuration": 7.662781,
|
||||
"JSHeapUsedSize": 4764568,
|
||||
"JSHeapTotalSize": 7077888
|
||||
},
|
||||
"end": {
|
||||
"Timestamp": 23593.417486,
|
||||
"Documents": 1,
|
||||
"Frames": 1,
|
||||
"JSEventListeners": 1032,
|
||||
"Nodes": 2696,
|
||||
"LayoutCount": 137,
|
||||
"RecalcStyleCount": 280,
|
||||
"LayoutDuration": 3.566888,
|
||||
"RecalcStyleDuration": 3.703827,
|
||||
"ScriptDuration": 27.965461,
|
||||
"TaskDuration": 67.992237,
|
||||
"JSHeapUsedSize": 12832824,
|
||||
"JSHeapTotalSize": 19759104
|
||||
},
|
||||
"delta": {
|
||||
"Timestamp": 65.46944399999848,
|
||||
"Documents": -2,
|
||||
"Frames": 0,
|
||||
"JSEventListeners": 765,
|
||||
"Nodes": 2045,
|
||||
"LayoutCount": 132,
|
||||
"RecalcStyleCount": 273,
|
||||
"LayoutDuration": 3.066152,
|
||||
"RecalcStyleDuration": 3.420593,
|
||||
"ScriptDuration": 22.271776000000003,
|
||||
"TaskDuration": 60.329456,
|
||||
"JSHeapUsedSize": 8068256,
|
||||
"JSHeapTotalSize": 12681216
|
||||
}
|
||||
},
|
||||
"cpuSummary": {
|
||||
"totalProfileMs": 55106.451,
|
||||
"sampleCount": 40511,
|
||||
"topSelfTime": [
|
||||
{
|
||||
"url": "",
|
||||
"functionName": "(program)",
|
||||
"lineNumber": -1,
|
||||
"columnNumber": -1,
|
||||
"selfMs": 26825.782999999923,
|
||||
"samples": 18512
|
||||
},
|
||||
{
|
||||
"url": "",
|
||||
"functionName": "(idle)",
|
||||
"lineNumber": -1,
|
||||
"columnNumber": -1,
|
||||
"selfMs": 4815.981000000005,
|
||||
"samples": 3701
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "(anonymous)",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 40267,
|
||||
"selfMs": 2656.4819999999972,
|
||||
"samples": 2026
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "ad",
|
||||
"lineNumber": 9,
|
||||
"columnNumber": 7898,
|
||||
"selfMs": 1032.9479999999999,
|
||||
"samples": 818
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Kt",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 48104,
|
||||
"selfMs": 951.7199999999993,
|
||||
"samples": 747
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Ce",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 94317,
|
||||
"selfMs": 905.2510000000005,
|
||||
"samples": 727
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "tryParse",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 49539,
|
||||
"selfMs": 592.3200000000003,
|
||||
"samples": 480
|
||||
},
|
||||
{
|
||||
"url": "",
|
||||
"functionName": "(garbage collector)",
|
||||
"lineNumber": -1,
|
||||
"columnNumber": -1,
|
||||
"selfMs": 578.5280000000001,
|
||||
"samples": 430
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "start",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 1485400,
|
||||
"selfMs": 445.5410000000001,
|
||||
"samples": 322
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "G4",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 28256,
|
||||
"selfMs": 432.7939999999998,
|
||||
"samples": 325
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "lt",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 7348,
|
||||
"selfMs": 360.4799999999999,
|
||||
"samples": 279
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "ga",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 10651,
|
||||
"selfMs": 330.2019999999997,
|
||||
"samples": 260
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "r",
|
||||
"lineNumber": 1,
|
||||
"columnNumber": 967,
|
||||
"selfMs": 323.32300000000004,
|
||||
"samples": 239
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Rl",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 101212,
|
||||
"selfMs": 308.80500000000006,
|
||||
"samples": 225
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "S1",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 40721,
|
||||
"selfMs": 305.08099999999996,
|
||||
"samples": 243
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "C2",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 49311,
|
||||
"selfMs": 304.76900000000006,
|
||||
"samples": 250
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "ws.onmessage",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 33453,
|
||||
"selfMs": 284.5850000000001,
|
||||
"samples": 204
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "N2.emit",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 25371,
|
||||
"selfMs": 275.96699999999987,
|
||||
"samples": 219
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Xl",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 117224,
|
||||
"selfMs": 260.1920000000001,
|
||||
"samples": 208
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "pa",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 10399,
|
||||
"selfMs": 249.32600000000016,
|
||||
"samples": 180
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "S4",
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 91365,
|
||||
"selfMs": 237.0250000000001,
|
||||
"samples": 179
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "N6",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 34144,
|
||||
"selfMs": 234.33099999999988,
|
||||
"samples": 188
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "bl",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 80838,
|
||||
"selfMs": 228.66600000000017,
|
||||
"samples": 171
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "o2",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 42232,
|
||||
"selfMs": 219.2690000000001,
|
||||
"samples": 182
|
||||
},
|
||||
{
|
||||
"url": "",
|
||||
"functionName": "setAttribute",
|
||||
"lineNumber": -1,
|
||||
"columnNumber": -1,
|
||||
"selfMs": 213.44599999999997,
|
||||
"samples": 178
|
||||
},
|
||||
{
|
||||
"url": "",
|
||||
"functionName": "(anonymous)",
|
||||
"lineNumber": 29,
|
||||
"columnNumber": 16,
|
||||
"selfMs": 194.01300000000003,
|
||||
"samples": 148
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "s2",
|
||||
"lineNumber": 9,
|
||||
"columnNumber": 71,
|
||||
"selfMs": 189.78200000000004,
|
||||
"samples": 160
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "na",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 3730,
|
||||
"selfMs": 184.6409999999999,
|
||||
"samples": 146
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Eh",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 95737,
|
||||
"selfMs": 179.85799999999998,
|
||||
"samples": 138
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"functionName": "Oh",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 116259,
|
||||
"selfMs": 179.09700000000007,
|
||||
"samples": 134
|
||||
}
|
||||
]
|
||||
},
|
||||
"responsiveness": {
|
||||
"longTaskCount": 333,
|
||||
"topLongTasks": [
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 7254.699999999255,
|
||||
"duration": 3731
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 409.19999999925494,
|
||||
"duration": 2518
|
||||
},
|
||||
{
|
||||
"name": "unknown",
|
||||
"startTime": 13437.400000002235,
|
||||
"duration": 1801
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 2960.199999999255,
|
||||
"duration": 1382
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 24715.300000000745,
|
||||
"duration": 1038
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 54470.699999999255,
|
||||
"duration": 1002
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 53685.199999999255,
|
||||
"duration": 785
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 23959.699999999255,
|
||||
"duration": 755
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 50997,
|
||||
"duration": 747
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 4343.10000000149,
|
||||
"duration": 621
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 27087.5,
|
||||
"duration": 597
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 22357.300000000745,
|
||||
"duration": 554
|
||||
},
|
||||
{
|
||||
"name": "unknown",
|
||||
"startTime": 15496,
|
||||
"duration": 478
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 5324.5,
|
||||
"duration": 474
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 11302.300000000745,
|
||||
"duration": 448
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 40393.300000000745,
|
||||
"duration": 435
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 55742.5,
|
||||
"duration": 405
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 25906.300000000745,
|
||||
"duration": 323
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 38613.5,
|
||||
"duration": 303
|
||||
},
|
||||
{
|
||||
"name": "self",
|
||||
"startTime": 46738.5,
|
||||
"duration": 286
|
||||
}
|
||||
],
|
||||
"frameCount": 358,
|
||||
"averageFrameMs": 207.5804469273743,
|
||||
"p95FrameMs": 483.3000000000029,
|
||||
"p99FrameMs": 2016.6,
|
||||
"intervalDriftCount": 43,
|
||||
"averageIntervalDriftMs": 1537.434883720913,
|
||||
"p95IntervalDriftMs": 7938.5,
|
||||
"p99IntervalDriftMs": 8055.300000000745
|
||||
},
|
||||
"consoleMessages": [
|
||||
{
|
||||
"type": "info",
|
||||
"text": "[socket] connecting to https://rover.otter.land",
|
||||
"location": {
|
||||
"url": "http://127.0.0.1:4173/assets/index-BcKZ4JVW.js",
|
||||
"line": 11,
|
||||
"column": 63824,
|
||||
"lineNumber": 11,
|
||||
"columnNumber": 63824
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"text": "Failed to load resource: the server responded with a status of 404 ()",
|
||||
"location": {
|
||||
"url": "https://media.discordapp.net/attachments/1424887548622405672/1512626709692682340/cat2.PNG?ex=6a24c6e6&is=6a237566&hm=baeec4c8e666888d89711065b1dbcb391c3415f9c28d1917bdd286776b60c867&=&format=webp&quality=lossless",
|
||||
"line": 0,
|
||||
"column": 0,
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"text": "Failed to load resource: the server responded with a status of 400 ()",
|
||||
"location": {
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"line": 0,
|
||||
"column": 0,
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"text": "Failed to load resource: the server responded with a status of 400 ()",
|
||||
"location": {
|
||||
"url": "https://rover.otter.land/video/Bweeble-audio/whep",
|
||||
"line": 0,
|
||||
"column": 0,
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"text": "Failed to load resource: the server responded with a status of 400 ()",
|
||||
"location": {
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"line": 0,
|
||||
"column": 0,
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"text": "Failed to load resource: the server responded with a status of 400 ()",
|
||||
"location": {
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"line": 0,
|
||||
"column": 0,
|
||||
"lineNumber": 0,
|
||||
"columnNumber": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"failedRequests": [
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"method": "POST",
|
||||
"failure": "net::ERR_ABORTED"
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble-audio/whep",
|
||||
"method": "POST",
|
||||
"failure": "net::ERR_ABORTED"
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"method": "POST",
|
||||
"failure": "net::ERR_ABORTED"
|
||||
}
|
||||
],
|
||||
"errorResponses": [
|
||||
{
|
||||
"url": "https://media.discordapp.net/attachments/1424887548622405672/1512626709692682340/cat2.PNG?ex=6a24c6e6&is=6a237566&hm=baeec4c8e666888d89711065b1dbcb391c3415f9c28d1917bdd286776b60c867&=&format=webp&quality=lossless",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble-audio/whep",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"url": "https://rover.otter.land/video/Bweeble/whep",
|
||||
"status": 400
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 461 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,896 @@
|
||||
{
|
||||
"url": "https://rover.otter.land/",
|
||||
"runDir": "perf/results/2026-06-12T06-15-19-037Z-root-runtime",
|
||||
"environment": {
|
||||
"cpuThrottle": 8,
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"isMobile": true,
|
||||
"sampleMs": 30000
|
||||
},
|
||||
"metrics": {
|
||||
"Timestamp": 23755.664379,
|
||||
"AudioHandlers": 0,
|
||||
"AudioWorkletProcessors": 0,
|
||||
"Documents": 3,
|
||||
"Frames": 1,
|
||||
"JSEventListeners": 1280,
|
||||
"LayoutObjects": 1996,
|
||||
"MediaKeySessions": 0,
|
||||
"MediaKeys": 0,
|
||||
"Nodes": 2628,
|
||||
"Resources": 20,
|
||||
"ContextLifecycleStateObservers": 20,
|
||||
"V8PerContextDatas": 4,
|
||||
"WorkerGlobalScopes": 0,
|
||||
"UACSSResources": 0,
|
||||
"RTCPeerConnections": 4,
|
||||
"ResourceFetchers": 3,
|
||||
"AdSubframes": 0,
|
||||
"DetachedScriptStates": 2,
|
||||
"ArrayBufferContents": 14,
|
||||
"LayoutCount": 43,
|
||||
"RecalcStyleCount": 80,
|
||||
"LayoutDuration": 1.465119,
|
||||
"RecalcStyleDuration": 1.54029,
|
||||
"DevToolsCommandDuration": 0.00038,
|
||||
"ScriptDuration": 15.671196,
|
||||
"V8CompileDuration": 0,
|
||||
"TaskDuration": 30.021546,
|
||||
"TaskOtherDuration": 11.344561,
|
||||
"ThreadTime": 32.951976,
|
||||
"ProcessTime": 39.43,
|
||||
"JSHeapUsedSize": 7054604,
|
||||
"JSHeapTotalSize": 13893632,
|
||||
"FirstMeaningfulPaint": 0,
|
||||
"DomContentLoaded": 23725.629234,
|
||||
"NavigationStart": 23721.84567
|
||||
},
|
||||
"snapshot": {
|
||||
"elapsedMs": 53572.199999999255,
|
||||
"listeners": [
|
||||
{
|
||||
"key": "add:input:invalid",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "add:window:online",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:document:visibilitychange",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:canplay",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:ended",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:error",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:pause",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:play",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:stalled",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "add:audio:waiting",
|
||||
"count": 6
|
||||
},
|
||||
{
|
||||
"key": "remove:window:online",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "remove:document:visibilitychange",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:play",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:pause",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:ended",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:error",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:waiting",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:canplay",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "remove:audio:stalled",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "add:WebSocket:message",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:auxclick",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:click",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:contextmenu",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:copy",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:cut",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drag",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragend",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragenter",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragexit",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragleave",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragover",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:dragstart",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:drop",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:gotpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:input",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keydown",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keypress",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:keyup",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:lostpointercapture",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "add:div#root:mousedown",
|
||||
"count": 2
|
||||
}
|
||||
],
|
||||
"timers": [
|
||||
{
|
||||
"key": "timeout:0",
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"key": "timeout:12000",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "interval:60000",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "interval:250",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "interval:200",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "timeout:2000",
|
||||
"count": 4
|
||||
},
|
||||
{
|
||||
"key": "timeout:15000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "timeout:4000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "interval:3000",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "interval:1000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "interval:2000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:10000",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "timeout:1491",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"timeouts": 19,
|
||||
"intervals": 16,
|
||||
"timeoutFires": 11,
|
||||
"intervalFires": 136,
|
||||
"webSocketMessageCount": 498,
|
||||
"webSocketBytes": 11209457,
|
||||
"webSocketEvents": [
|
||||
{
|
||||
"event": "log:entry",
|
||||
"count": 269,
|
||||
"bytes": 62887
|
||||
},
|
||||
{
|
||||
"event": "sensorFrame",
|
||||
"count": 99,
|
||||
"bytes": 185012
|
||||
},
|
||||
{
|
||||
"event": "session:sync",
|
||||
"count": 31,
|
||||
"bytes": 526178
|
||||
},
|
||||
{
|
||||
"event": "commandAck",
|
||||
"count": 30,
|
||||
"bytes": 2833
|
||||
},
|
||||
{
|
||||
"event": "",
|
||||
"count": 15,
|
||||
"bytes": 10168579
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:frame",
|
||||
"count": 11,
|
||||
"bytes": 1067
|
||||
},
|
||||
{
|
||||
"event": "mode",
|
||||
"count": 2,
|
||||
"bytes": 54
|
||||
},
|
||||
{
|
||||
"event": "controlGranted",
|
||||
"count": 2,
|
||||
"bytes": 83
|
||||
},
|
||||
{
|
||||
"event": "alert",
|
||||
"count": 2,
|
||||
"bytes": 257
|
||||
},
|
||||
{
|
||||
"event": "alert:new",
|
||||
"count": 2,
|
||||
"bytes": 330
|
||||
},
|
||||
{
|
||||
"event": "auth:role",
|
||||
"count": 2,
|
||||
"bytes": 62
|
||||
},
|
||||
{
|
||||
"event": "rovers",
|
||||
"count": 2,
|
||||
"bytes": 10906
|
||||
},
|
||||
{
|
||||
"event": "chat:init",
|
||||
"count": 2,
|
||||
"bytes": 155226
|
||||
},
|
||||
{
|
||||
"event": "overseer:memory",
|
||||
"count": 2,
|
||||
"bytes": 1040
|
||||
},
|
||||
{
|
||||
"event": "log:init",
|
||||
"count": 2,
|
||||
"bytes": 88662
|
||||
},
|
||||
{
|
||||
"event": "barcode:state",
|
||||
"count": 2,
|
||||
"bytes": 3254
|
||||
},
|
||||
{
|
||||
"event": "kinect:pointCloudFrame",
|
||||
"count": 2,
|
||||
"bytes": 524
|
||||
},
|
||||
{
|
||||
"event": "kinect:colorFrame",
|
||||
"count": 2,
|
||||
"bytes": 338
|
||||
},
|
||||
{
|
||||
"event": "2",
|
||||
"count": 2,
|
||||
"bytes": 2
|
||||
},
|
||||
{
|
||||
"event": "roverSnapshot:status",
|
||||
"count": 2,
|
||||
"bytes": 159
|
||||
},
|
||||
{
|
||||
"event": "0{\"sid\":\"v0f",
|
||||
"count": 1,
|
||||
"bytes": 106
|
||||
},
|
||||
{
|
||||
"event": "40{\"sid\":\"5t",
|
||||
"count": 1,
|
||||
"bytes": 32
|
||||
},
|
||||
{
|
||||
"event": "430[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 39
|
||||
},
|
||||
{
|
||||
"event": "431[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 133
|
||||
},
|
||||
{
|
||||
"event": "432[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 145
|
||||
},
|
||||
{
|
||||
"event": "Freaky",
|
||||
"count": 1,
|
||||
"bytes": 40
|
||||
},
|
||||
{
|
||||
"event": "434[{\"succes",
|
||||
"count": 1,
|
||||
"bytes": 194
|
||||
},
|
||||
{
|
||||
"event": "0{\"sid\":\"t1y",
|
||||
"count": 1,
|
||||
"bytes": 106
|
||||
},
|
||||
{
|
||||
"event": "40{\"sid\":\"Bu",
|
||||
"count": 1,
|
||||
"bytes": 32
|
||||
},
|
||||
{
|
||||
"event": "436[{\"error\"",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "437[{\"error\"",
|
||||
"count": 1,
|
||||
"bytes": 41
|
||||
},
|
||||
{
|
||||
"event": "438[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 135
|
||||
},
|
||||
{
|
||||
"event": "439[{\"url\":\"",
|
||||
"count": 1,
|
||||
"bytes": 147
|
||||
},
|
||||
{
|
||||
"event": "Bweeble",
|
||||
"count": 1,
|
||||
"bytes": 42
|
||||
},
|
||||
{
|
||||
"event": "roverHostStats",
|
||||
"count": 1,
|
||||
"bytes": 771
|
||||
}
|
||||
],
|
||||
"mutationsTotal": {
|
||||
"records": 7648,
|
||||
"added": 227,
|
||||
"removed": 34,
|
||||
"attrs": 7351,
|
||||
"text": 36
|
||||
},
|
||||
"mutationTargets": [
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:name",
|
||||
"count": 2612
|
||||
},
|
||||
{
|
||||
"key": "input.accent-emerald-400:attributes:type",
|
||||
"count": 1306
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:name",
|
||||
"count": 432
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:name",
|
||||
"count": 432
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:name",
|
||||
"count": 428
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:name",
|
||||
"count": 330
|
||||
},
|
||||
{
|
||||
"key": "div.h-full:attributes:style",
|
||||
"count": 278
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.chat-composer-input:attributes:name",
|
||||
"count": 216
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:name",
|
||||
"count": 216
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:type",
|
||||
"count": 216
|
||||
},
|
||||
{
|
||||
"key": "input.accent-cyan-500:attributes:type",
|
||||
"count": 214
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:type",
|
||||
"count": 165
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:d",
|
||||
"count": 145
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:fill",
|
||||
"count": 139
|
||||
},
|
||||
{
|
||||
"key": "input:attributes:type",
|
||||
"count": 108
|
||||
},
|
||||
{
|
||||
"key": "Text:characterData:",
|
||||
"count": 36
|
||||
},
|
||||
{
|
||||
"key": "section.panel-section.border:attributes:style",
|
||||
"count": 20
|
||||
},
|
||||
{
|
||||
"key": "header.flex.items-center:attributes:style",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "path.[object.SVGAnimatedString]:attributes:stroke",
|
||||
"count": 18
|
||||
},
|
||||
{
|
||||
"key": "input.min-w-0.flex-1:attributes:name",
|
||||
"count": 14
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:value",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "span.inline-flex.items-center:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "div.rounded-sm.px-2:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.min-h-9:attributes:disabled",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "div.fixed.bottom-2:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "button.mobile-touch-control.flex:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "div.mobile-touch-control.flex:attributes:class",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"key": "input#replay-sources-mobile-portrait-title.field-input.min-w-0:attributes:placeholder",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:playsinline",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:autoplay",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "video.h-full.w-full:attributes:disableremoteplayback",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:autoplay",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "audio:attributes:disableremoteplayback",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.flex-1:attributes:value",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "span.inline-block.rounded:attributes:style",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"key": "div.flex.flex-col:attributes:class",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.min-w-0:attributes:disabled",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "input.field-input.w-full:attributes:value",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"key": "button.button-dark.text-sm:attributes:disabled",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"mutationBursts": [
|
||||
{
|
||||
"at": 10155,
|
||||
"records": 164,
|
||||
"added": 105,
|
||||
"removed": 1,
|
||||
"attrs": 58,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 28081,
|
||||
"records": 103,
|
||||
"added": 7,
|
||||
"removed": 12,
|
||||
"attrs": 79,
|
||||
"text": 5
|
||||
},
|
||||
{
|
||||
"at": 31972,
|
||||
"records": 83,
|
||||
"added": 13,
|
||||
"removed": 3,
|
||||
"attrs": 65,
|
||||
"text": 2
|
||||
},
|
||||
{
|
||||
"at": 18426,
|
||||
"records": 82,
|
||||
"added": 11,
|
||||
"removed": 2,
|
||||
"attrs": 66,
|
||||
"text": 3
|
||||
},
|
||||
{
|
||||
"at": 8027,
|
||||
"records": 69,
|
||||
"added": 19,
|
||||
"removed": 5,
|
||||
"attrs": 42,
|
||||
"text": 3
|
||||
},
|
||||
{
|
||||
"at": 16714,
|
||||
"records": 66,
|
||||
"added": 2,
|
||||
"removed": 2,
|
||||
"attrs": 53,
|
||||
"text": 9
|
||||
},
|
||||
{
|
||||
"at": 40645,
|
||||
"records": 64,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 64,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 40951,
|
||||
"records": 64,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 64,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 42708,
|
||||
"records": 64,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 64,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 36974,
|
||||
"records": 61,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 61,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 24109,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 28572,
|
||||
"records": 60,
|
||||
"added": 2,
|
||||
"removed": 4,
|
||||
"attrs": 53,
|
||||
"text": 1
|
||||
},
|
||||
{
|
||||
"at": 36595,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 42135,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 43257,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 48207,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 48500,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 50368,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 51568,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
},
|
||||
{
|
||||
"at": 52146,
|
||||
"records": 60,
|
||||
"added": 0,
|
||||
"removed": 0,
|
||||
"attrs": 60,
|
||||
"text": 0
|
||||
}
|
||||
],
|
||||
"frames": {
|
||||
"count": 241,
|
||||
"average": 202.06639004149378,
|
||||
"p95": 399.8999999999978,
|
||||
"p99": 1633.199999999999
|
||||
},
|
||||
"longTasks": {
|
||||
"count": 133,
|
||||
"top": [
|
||||
{
|
||||
"startTime": 1510.7999999970198,
|
||||
"duration": 2281,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 10156.89999999851,
|
||||
"duration": 1493,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 3806,
|
||||
"duration": 1311,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 30277.099999997765,
|
||||
"duration": 932,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 14996,
|
||||
"duration": 931,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 9269.89999999851,
|
||||
"duration": 886,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 7147,
|
||||
"duration": 880,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 14298,
|
||||
"duration": 698,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 29581.099999997765,
|
||||
"duration": 696,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 8029.599999997765,
|
||||
"duration": 689,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 5117.39999999851,
|
||||
"duration": 534,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 31587,
|
||||
"duration": 385,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 18074,
|
||||
"duration": 356,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 25434.39999999851,
|
||||
"duration": 344,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 16382.29999999702,
|
||||
"duration": 333,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 12463.199999999255,
|
||||
"duration": 300,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 6124.79999999702,
|
||||
"duration": 285,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 5657.199999999255,
|
||||
"duration": 283,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 18655.79999999702,
|
||||
"duration": 242,
|
||||
"name": "self"
|
||||
},
|
||||
{
|
||||
"startTime": 19023.5,
|
||||
"duration": 236,
|
||||
"name": "self"
|
||||
}
|
||||
]
|
||||
},
|
||||
"consoleErrors": []
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||
<title>Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-DhJId5qi.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-D0FgC_A-.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BVKa8Zph.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
+2
-3
@@ -11,7 +11,7 @@ import {
|
||||
ControlSystemProvider,
|
||||
KeyboardInputManager,
|
||||
GamepadInputManager,
|
||||
useControlSystem,
|
||||
useControlSelector,
|
||||
} from './controls/index.js';
|
||||
import RoomCameraPanel from './components/RoomCameraPanel/index.jsx';
|
||||
import KinectPanel from './components/KinectPanel/index.jsx';
|
||||
@@ -105,10 +105,9 @@ function MobileFeatureTabs({
|
||||
const roverId = String(state.session?.assignment?.roverId || '').trim();
|
||||
return roverId ? state.session?.audioForward?.[roverId] || null : null;
|
||||
});
|
||||
const { state: controlState } = useControlSystem();
|
||||
const pttActive = useControlSelector((control) => Boolean(control.state.mic?.pttActive));
|
||||
const { value: vipAudio } = useSettingsNamespace('vipAudio', { openMicEnabled: false, pttMode: 'live' });
|
||||
const vipDotClass = isVerified ? 'bg-emerald-400' : 'bg-amber-400';
|
||||
const pttActive = Boolean(controlState?.mic?.pttActive);
|
||||
const openMicEnabled = Boolean(vipAudio?.openMicEnabled);
|
||||
const pttMode = vipAudio?.pttMode === 'clip' ? 'clip' : 'live';
|
||||
const vipMicActive = Boolean(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Defines the Drive Dock Action module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import { useTelemetryFrame } from '../../context/TelemetryContext.jsx';
|
||||
import { formatKeyLabel } from '../../controls/keymapUtils.js';
|
||||
import { useManualDockAssist } from '../../features/manualDockAssist/useManualDockAssist.js';
|
||||
@@ -103,10 +103,9 @@ export default function DriveDockAction({
|
||||
compactHeightClass = '',
|
||||
}) {
|
||||
const isMobile = layout === 'mobile';
|
||||
const {
|
||||
state: { roverId, keymap },
|
||||
actions,
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const actions = useControlActions();
|
||||
const dockAssist = useManualDockAssist();
|
||||
const frame = useTelemetryFrame(roverId);
|
||||
const state = driveDockState ?? deriveDriveDockState(frame);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useSessionSelector } from '../../context/SessionContext.jsx';
|
||||
import RoverMediaPlayer from '../RoverMediaPlayer/index.jsx';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import { useDriverVideoModePolicy } from '../../hooks/useDriverVideoModePolicy.js';
|
||||
import TurnsOverlay from '../HudOverlays/TurnsOverlay/index.jsx';
|
||||
import HudOverlay from '../HudOverlays/HudOverlay/index.jsx';
|
||||
@@ -15,9 +15,7 @@ import CardFrame from '../CardFrame/index.jsx';
|
||||
export default function DriverVideo({ layoutFormat = 'desktop' }) {
|
||||
const roverId = useSessionSelector((state) => state.session?.assignment?.roverId ?? null);
|
||||
const videoMode = useDriverVideoModePolicy(roverId);
|
||||
const {
|
||||
state: { lastControlIntentAt },
|
||||
} = useControlSystem();
|
||||
const lastControlIntentAt = useControlSelector((control) => control.state.lastControlIntentAt);
|
||||
|
||||
if (!roverId) {
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Help Overlay
|
||||
// Purpose: Defines the Help Overlay module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import HelpContentView from '../HelpContentView/index.jsx';
|
||||
|
||||
export default function HelpOverlay({ visible, layout, onClose, showOnLoad, onToggleShowOnLoad }) {
|
||||
if (!visible) return null;
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
|
||||
const { state } = useControlSystem();
|
||||
if (!visible) return null;
|
||||
|
||||
const handleCheckbox = (event) => {
|
||||
const keepShowing = !event.target.checked;
|
||||
@@ -39,7 +39,7 @@ export default function HelpOverlay({ visible, layout, onClose, showOnLoad, onTo
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-h-[85vh] overflow-y-auto p-0.5">
|
||||
<HelpContentView layout={layout} keymap={state?.keymap || {}} />
|
||||
<HelpContentView layout={layout} keymap={keymap || {}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Help Panel
|
||||
// Purpose: Defines the Help Panel module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import CardFrame from '../CardFrame/index.jsx';
|
||||
import HelpContentView from '../HelpContentView/index.jsx';
|
||||
|
||||
export default function HelpPanel({ layout, onOpenOverlay }) {
|
||||
const { state } = useControlSystem();
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
|
||||
const actions = (
|
||||
<button
|
||||
@@ -20,7 +20,7 @@ export default function HelpPanel({ layout, onOpenOverlay }) {
|
||||
|
||||
return (
|
||||
<CardFrame title="Help" actions={actions} bodyClassName="space-y-0.5 text-sm">
|
||||
<HelpContentView layout={layout} keymap={state?.keymap || {}} />
|
||||
<HelpContentView layout={layout} keymap={keymap || {}} />
|
||||
</CardFrame>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useMemo } from 'react';
|
||||
import { useSessionActions, useSessionSelector } from '../../context/SessionContext.jsx';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import { formatKeyLabel } from '../../controls/keymapUtils.js';
|
||||
import CardFrame from '../CardFrame/index.jsx';
|
||||
|
||||
@@ -169,9 +169,7 @@ function LampTile({ entity, connected, controlsLocked, onToggle, onSetColor, onS
|
||||
}
|
||||
|
||||
export default function HomeAssistantControls() {
|
||||
const {
|
||||
state: { keymap },
|
||||
} = useControlSystem();
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const ha = useSessionSelector((state) => state.session?.homeAssistant || null);
|
||||
const { homeAssistantToggle, homeAssistantSetLightColor, homeAssistantSetLightWhite } =
|
||||
useSessionActions();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSessionSelector } from '../../../context/SessionContext.jsx';
|
||||
import { useControlSystem } from '../../../controls/index.js';
|
||||
import { useControlSelector } from '../../../controls/index.js';
|
||||
import SocialButton from '../../SocialButton/index.jsx';
|
||||
|
||||
function TurnsOverlay({
|
||||
@@ -15,9 +15,7 @@ function TurnsOverlay({
|
||||
const turnQueues = useSessionSelector((state) => state.session?.turnQueues ?? {});
|
||||
const socketId = useSessionSelector((state) => state.session?.socketId || null);
|
||||
const activeDrivers = useSessionSelector((state) => state.session?.activeDrivers ?? {});
|
||||
const {
|
||||
state: { lastControlIntentAt },
|
||||
} = useControlSystem();
|
||||
const lastControlIntentAt = useControlSelector((control) => control.state.lastControlIntentAt);
|
||||
const [now, setNow] = useState(() => Date.now());
|
||||
const [showTurnCue, setShowTurnCue] = useState(false);
|
||||
const [turnCueStartAt, setTurnCueStartAt] = useState(null);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Defines the Keymap Settings module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useMemo, useState, useEffect, useCallback } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import { DEFAULT_KEYMAP } from '../../controls/constants.js';
|
||||
import { canonicalizeKeyInput, formatKeyLabel } from '../../controls/keymapUtils.js';
|
||||
import { setKeyboardCaptureLocked } from '../../controls/inputs/keyboardCaptureLock.js';
|
||||
@@ -191,10 +191,8 @@ function BindingRow({ action, value, isActive, onCaptureStart, onCancel, onCaptu
|
||||
}
|
||||
|
||||
export default function KeymapSettings() {
|
||||
const {
|
||||
state: { keymap },
|
||||
actions: { updateKeyBinding, resetKeyBindings },
|
||||
} = useControlSystem();
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const { updateKeyBinding, resetKeyBindings } = useControlActions();
|
||||
const { value: inputSettings, save: saveInputSettings } = useSettingsNamespace('inputs', INPUT_SETTINGS_DEFAULTS);
|
||||
const keyboardSettings = {
|
||||
...INPUT_SETTINGS_DEFAULTS.keyboard,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Assembles the mobile auxiliary controls column, which is the left column by default.
|
||||
// Scope: Owns mobile aux/camera/night vision/horn wiring while reusing desktop variation components where intended.
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import { useManualDockAssist } from '../../features/manualDockAssist/useManualDockAssist.js';
|
||||
import HornControl from '../HornControl/index.jsx';
|
||||
import NightVisionControl from '../NightVisionControl/index.jsx';
|
||||
@@ -11,19 +11,20 @@ import VacuumControls from './VacuumControls.jsx';
|
||||
import VerticalCameraTilt from './VerticalCameraTilt.jsx';
|
||||
|
||||
function AuxColumnContent() {
|
||||
const {
|
||||
state: { roverId, camera, horn },
|
||||
pipeline,
|
||||
actions: { setServoAngle, setNightVision, setAuxMotors, startHorn, stopHorn },
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const camera = useControlSelector((control) => control.state.camera);
|
||||
const horn = useControlSelector((control) => control.state.horn);
|
||||
const nightVision = useControlSelector((control) => control.pipeline?.nightVision);
|
||||
const nightVisionState = useControlSelector((control) => control.pipeline?.nightVisionState);
|
||||
const pipelineHorn = useControlSelector((control) => control.pipeline?.horn);
|
||||
const { setServoAngle, setNightVision, setAuxMotors, startHorn, stopHorn } = useControlActions();
|
||||
const dockAssist = useManualDockAssist();
|
||||
const disabled = !roverId;
|
||||
const activeAuxButtonRef = useRef(null);
|
||||
const cameraConfig = camera?.config;
|
||||
const cameraEnabled = Boolean(roverId && camera?.enabled && cameraConfig);
|
||||
const nightVisionAvailable = Boolean(roverId && pipeline?.nightVision);
|
||||
const nightVisionState = pipeline?.nightVisionState;
|
||||
const hornAvailable = Boolean(roverId && pipeline?.horn);
|
||||
const nightVisionAvailable = Boolean(roverId && nightVision);
|
||||
const hornAvailable = Boolean(roverId && pipelineHorn);
|
||||
const hornBlocked = horn?.overheated;
|
||||
const cameraMin = typeof cameraConfig?.minAngle === 'number' ? cameraConfig.minAngle : -45;
|
||||
const cameraMax = typeof cameraConfig?.maxAngle === 'number' ? cameraConfig.maxAngle : 45;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Provides the mobile movement control pad and speed mode selector.
|
||||
// Scope: Converts touch pad cells into keyboard-style drive vectors; movement column owns drive/dock placement.
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import { normalizeKeymapEntries } from '../../controls/keymapUtils.js';
|
||||
import {
|
||||
computeKeyboardDriveVector,
|
||||
@@ -29,10 +29,8 @@ function getSpeedModeConfig(speedMode) {
|
||||
}
|
||||
|
||||
export default function ControlPadPanel({ disabled = false }) {
|
||||
const {
|
||||
state: { keymap: rawKeymap },
|
||||
actions: { setDriveVector, registerInputState },
|
||||
} = useControlSystem();
|
||||
const rawKeymap = useControlSelector((control) => control.state.keymap);
|
||||
const { setDriveVector, registerInputState } = useControlActions();
|
||||
const { value: inputSettings } = useSettingsNamespace('inputs', INPUT_SETTINGS_DEFAULTS);
|
||||
const [speedMode, setSpeedMode] = useState('normal');
|
||||
const [activeInputLabel, setActiveInputLabel] = useState('stop');
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// Movement Column
|
||||
// Purpose: Assembles the mobile movement column, which is the right column by default.
|
||||
// Scope: Integrates drive/dock actions with the mobile control pad without hiding that dependency inside the pad.
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import DriveDockAction, { useDriveDockState } from '../DriveDockAction/index.jsx';
|
||||
import ControlPadPanel from './ControlPadPanel.jsx';
|
||||
|
||||
function MovementColumnContent({ layout }) {
|
||||
const {
|
||||
state: { roverId },
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const driveDockState = useDriveDockState(roverId);
|
||||
const dockedNotDriving = driveDockState.docked && !driveDockState.driving;
|
||||
const expandAction = dockedNotDriving || driveDockState.dockingInProgress;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Defines the Overcurrent Limiter Panel module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useMemo } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import { OVERCURRENT_GROUPS } from '../../controls/overcurrentLimiter.js';
|
||||
import CardFrame from '../CardFrame/index.jsx';
|
||||
|
||||
@@ -26,10 +26,8 @@ function ProgressBar({ value, color = 'bg-emerald-500' }) {
|
||||
}
|
||||
|
||||
export default function OvercurrentLimiterPanel() {
|
||||
const {
|
||||
state: { roverId },
|
||||
overcurrentLimiter,
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const overcurrentLimiter = useControlSelector((control) => control.overcurrentLimiter);
|
||||
const groups = useMemo(() => OVERCURRENT_GROUPS.map((group) => group.key), []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlSelector } from '../../controls/index.js';
|
||||
import { formatKeyLabel } from '../../controls/keymapUtils.js';
|
||||
import NicknameForm from '../NicknameForm/index.jsx';
|
||||
import SocialButton from '../SocialButton/index.jsx';
|
||||
@@ -53,9 +53,9 @@ export default function QuickstartOverlay({
|
||||
onOpenHelp,
|
||||
onClose,
|
||||
}) {
|
||||
const { state } = useControlSystem();
|
||||
const rawKeymap = useControlSelector((control) => control.state.keymap);
|
||||
const isDesktop = layout === 'desktop';
|
||||
const keymap = useMemo(() => state?.keymap || {}, [state?.keymap]);
|
||||
const keymap = useMemo(() => rawKeymap || {}, [rawKeymap]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import Tabs, { Tab, TabList, TabPanel, TabPanels } from '../Tabs/index.jsx';
|
||||
import TopDownMap from '../TopDownMap/index.jsx';
|
||||
import DriveDockAction, { useDriveDockState } from '../DriveDockAction/index.jsx';
|
||||
import { useTelemetryFrame } from '../../context/TelemetryContext.jsx';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import RoverQueuesPanel from '../RoverQueuesPanel/index.jsx';
|
||||
import RawUserPilePanel from '../RawUserPilePanel/index.jsx';
|
||||
import { formatKeyLabel } from '../../controls/keymapUtils.js';
|
||||
@@ -36,9 +36,7 @@ const CHAT_DOCK_MAX_HEIGHT = 300;
|
||||
const CHAT_DOCK_BOTTOM_INSET = 8;
|
||||
|
||||
function TopDownMapPanel() {
|
||||
const {
|
||||
state: { roverId },
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const frame = useTelemetryFrame(roverId);
|
||||
const sensors = frame?.sensors || {};
|
||||
|
||||
@@ -54,20 +52,22 @@ function TopDownMapPanel() {
|
||||
}
|
||||
|
||||
function DriveDockPanel() {
|
||||
const {
|
||||
state: { roverId, keymap, camera, horn },
|
||||
pipeline,
|
||||
actions: { setServoAngle, setNightVision, startHorn, stopHorn },
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const camera = useControlSelector((control) => control.state.camera);
|
||||
const horn = useControlSelector((control) => control.state.horn);
|
||||
const nightVision = useControlSelector((control) => control.pipeline?.nightVision);
|
||||
const nightVisionState = useControlSelector((control) => control.pipeline?.nightVisionState);
|
||||
const pipelineHorn = useControlSelector((control) => control.pipeline?.horn);
|
||||
const { setServoAngle, setNightVision, startHorn, stopHorn } = useControlActions();
|
||||
const dockAssist = useManualDockAssist();
|
||||
const driveDockState = useDriveDockState(roverId);
|
||||
const hideInlineControls = driveDockState.docked && !driveDockState.driving;
|
||||
|
||||
const config = camera?.config;
|
||||
const cameraEnabled = Boolean(roverId && camera?.enabled && config);
|
||||
const nightVisionAvailable = Boolean(roverId && pipeline?.nightVision);
|
||||
const nightVisionState = pipeline?.nightVisionState;
|
||||
const hornAvailable = Boolean(roverId && pipeline?.horn);
|
||||
const nightVisionAvailable = Boolean(roverId && nightVision);
|
||||
const hornAvailable = Boolean(roverId && pipelineHorn);
|
||||
const hornBlocked = horn?.overheated;
|
||||
const min = typeof config?.minAngle === 'number' ? config.minAngle : -30;
|
||||
const max = typeof config?.maxAngle === 'number' ? config.maxAngle : 30;
|
||||
@@ -146,10 +146,9 @@ export default function RightPaneTabs({ layout, onOpenHelpOverlay }) {
|
||||
const roverId = String(state.session?.assignment?.roverId || '').trim();
|
||||
return roverId ? state.session?.audioForward?.[roverId] || null : null;
|
||||
});
|
||||
const { state: controlState } = useControlSystem();
|
||||
const pttActive = useControlSelector((control) => Boolean(control.state.mic?.pttActive));
|
||||
const { value: vipAudio } = useSettingsNamespace('vipAudio', { openMicEnabled: false, pttMode: 'live' });
|
||||
const vipDotClass = isVerified ? 'bg-emerald-400' : 'bg-red-600';
|
||||
const pttActive = Boolean(controlState?.mic?.pttActive);
|
||||
const openMicEnabled = Boolean(vipAudio?.openMicEnabled);
|
||||
const pttMode = vipAudio?.pttMode === 'clip' ? 'clip' : 'live';
|
||||
const vipMicActive = Boolean(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Purpose: Defines the Settings Panel module and the local helpers/components used in this file.
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useMemo } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import AuthPanel from '../AuthPanel/index.jsx';
|
||||
import AdminPanel from '../AdminPanel/index.jsx';
|
||||
import KeymapSettings from '../KeymapSettings/index.jsx';
|
||||
@@ -91,10 +91,9 @@ function RangeSetting({ label, value, disabled = false, onChange }) {
|
||||
}
|
||||
|
||||
export default function SettingsPanel() {
|
||||
const {
|
||||
state: { keymap, roverId },
|
||||
actions: { sendOiCommand, setSensorStream },
|
||||
} = useControlSystem();
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const { sendOiCommand, setSensorStream } = useControlActions();
|
||||
const canControl = Boolean(roverId);
|
||||
const [hudMapDesktop, setHudMapDesktop] = useHudMapSetting();
|
||||
const socket = useSocket();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { fieldClass } from '../constants.js';
|
||||
import { useControlSystem } from '../../../controls/index.js';
|
||||
import { useControlSelector } from '../../../controls/index.js';
|
||||
import { formatKeyLabel } from '../../../controls/keymapUtils.js';
|
||||
import { useSettingsNamespace } from '../../../settings/index.js';
|
||||
import { MAX_UPLOAD_BYTES, TARGET_SAMPLE_RATE, RTC_CONFIG } from './constants.js';
|
||||
@@ -28,7 +28,8 @@ export default function VipAudioUploadCard({
|
||||
readyMicWhip,
|
||||
stopMicWhip,
|
||||
}) {
|
||||
const { state: controlState } = useControlSystem();
|
||||
const keymap = useControlSelector((control) => control.state.keymap);
|
||||
const pttActive = useControlSelector((control) => Boolean(control.state.mic?.pttActive));
|
||||
const { value: vipAudio, save: saveVipAudio } = useSettingsNamespace('vipAudio', {
|
||||
openMicEnabled: false,
|
||||
pttMode: 'live',
|
||||
@@ -60,7 +61,6 @@ export default function VipAudioUploadCard({
|
||||
const clipRecordingRef = useRef(false);
|
||||
const clipSampleRateRef = useRef(TARGET_SAMPLE_RATE);
|
||||
|
||||
const pttActive = Boolean(controlState?.mic?.pttActive);
|
||||
|
||||
const selectedForwardState = useMemo(
|
||||
() => (roverId ? audioForwardByRover?.[roverId] || null : null),
|
||||
@@ -81,7 +81,7 @@ export default function VipAudioUploadCard({
|
||||
const whipLinkActive = !clipMode && (micState === 'live' || micState === 'starting');
|
||||
const clipRecording = clipMode && clipState === 'recording';
|
||||
const clipSending = clipMode && clipState === 'sending';
|
||||
const pttKeyLabel = formatKeyLabel(controlState?.keymap?.micPtt?.[0]) || 'M';
|
||||
const pttKeyLabel = formatKeyLabel(keymap?.micPtt?.[0]) || 'M';
|
||||
|
||||
const setPttMode = useCallback(
|
||||
(nextMode) => {
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
// Control Context Provider
|
||||
// Purpose: Exposes control-system state/actions to control-capable components. Scope: Owns reducer wiring, pipeline integration, and top-level provider hooks.
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef } from 'react';
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { controlReducer, initialControlState } from './controlReducer.js';
|
||||
import { computeDifferentialSpeeds, clamp } from './controlMath.js';
|
||||
import { useCommandPipeline } from './commandPipeline.js';
|
||||
@@ -27,6 +38,35 @@ import {
|
||||
|
||||
const ControlSystemContext = createContext(null);
|
||||
|
||||
function normalizeSelector(selector) {
|
||||
return typeof selector === 'function' ? selector : (snapshot) => snapshot;
|
||||
}
|
||||
|
||||
const CONTROL_ACTION_NAMES = [
|
||||
'setMode',
|
||||
'setDriveVector',
|
||||
'setAuxMotors',
|
||||
'setServoAngle',
|
||||
'nudgeServo',
|
||||
'goServoHome',
|
||||
'runMacro',
|
||||
'stopAllMotion',
|
||||
'sendOiCommand',
|
||||
'setSensorStream',
|
||||
'setNightVision',
|
||||
'toggleNightVision',
|
||||
'updateKeyBinding',
|
||||
'resetKeyBindings',
|
||||
'registerInputState',
|
||||
'setManualDockAssistActive',
|
||||
'toggleManualDockAssist',
|
||||
'setSongNote',
|
||||
'sendSong',
|
||||
'startHorn',
|
||||
'stopHorn',
|
||||
'setMicPttActive',
|
||||
];
|
||||
|
||||
function cloneKeymap(map) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(map || {}).map(([key, values]) => [key, Array.isArray(values) ? [...values] : []]),
|
||||
@@ -59,6 +99,53 @@ function removeDriveSequenceBackoff(steps = []) {
|
||||
|
||||
export function ControlSystemProvider({ children }) {
|
||||
const [state, dispatch] = useReducer(controlReducer, initialControlState);
|
||||
const snapshotRef = useRef(null);
|
||||
const subscribersRef = useRef(new Set());
|
||||
const actionImplementationsRef = useRef({});
|
||||
const [stableActions] = useState(() => {
|
||||
/*
|
||||
Public action functions intentionally keep stable identities. Each wrapper
|
||||
reads the current implementation at call time, so consumers can depend on
|
||||
actions without re-rendering just because the real implementation now
|
||||
closes over a new state slice, pipeline object, or settings value.
|
||||
*/
|
||||
return Object.fromEntries(
|
||||
CONTROL_ACTION_NAMES.map((name) => [
|
||||
name,
|
||||
(...args) => actionImplementationsRef.current[name]?.(...args),
|
||||
]),
|
||||
);
|
||||
}, []);
|
||||
const getControlSnapshot = useCallback(() => snapshotRef.current, []);
|
||||
const subscribeControlSnapshot = useCallback((selector, listener, equalityFn = Object.is) => {
|
||||
const normalizedSelector = normalizeSelector(selector);
|
||||
const currentSnapshot = snapshotRef.current;
|
||||
const subscriber = {
|
||||
selector: normalizedSelector,
|
||||
equalityFn,
|
||||
listener,
|
||||
current: normalizedSelector(currentSnapshot),
|
||||
};
|
||||
subscribersRef.current.add(subscriber);
|
||||
return () => {
|
||||
subscribersRef.current.delete(subscriber);
|
||||
};
|
||||
}, []);
|
||||
const notifyControlSubscribers = useCallback((nextSnapshot) => {
|
||||
/*
|
||||
The provider context value below is stable, so React will not fan out an
|
||||
update to every consumer automatically. This loop is the replacement: it
|
||||
asks each subscribed component whether the exact value it selected changed
|
||||
and only wakes that component when its selected value is different.
|
||||
*/
|
||||
subscribersRef.current.forEach((subscriber) => {
|
||||
const nextSelected = subscriber.selector(nextSnapshot);
|
||||
if (!subscriber.equalityFn(subscriber.current, nextSelected)) {
|
||||
subscriber.current = nextSelected;
|
||||
subscriber.listener(nextSelected);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const prevModeRef = useRef(null);
|
||||
const pendingLightsRef = useRef(false);
|
||||
const servoAngleRef = useRef(initialControlState.camera.angle);
|
||||
@@ -166,7 +253,7 @@ export function ControlSystemProvider({ children }) {
|
||||
if (pipeline.roverId) {
|
||||
pipeline.enableSensorStream();
|
||||
}
|
||||
}, [pipeline.roverId, pipeline.enableSensorStream]);
|
||||
}, [pipeline]);
|
||||
|
||||
const setMode = useCallback(
|
||||
(mode) => {
|
||||
@@ -430,6 +517,8 @@ export function ControlSystemProvider({ children }) {
|
||||
return { waveform, freqs: normalized };
|
||||
}, [hornSettings]);
|
||||
|
||||
const stopHornRef = useRef(null);
|
||||
|
||||
const startHorn = useCallback(() => {
|
||||
if (!pipeline.horn) return;
|
||||
if (state.horn?.overheated) return false;
|
||||
@@ -445,7 +534,7 @@ export function ControlSystemProvider({ children }) {
|
||||
hornAutoStopRef.current = null;
|
||||
}
|
||||
hornAutoStopRef.current = setTimeout(() => {
|
||||
stopHorn();
|
||||
stopHornRef.current?.();
|
||||
}, HORN_MAX_MS);
|
||||
recordControlIntent();
|
||||
return true;
|
||||
@@ -474,15 +563,13 @@ export function ControlSystemProvider({ children }) {
|
||||
}
|
||||
dispatch({ type: 'control/set-horn-heat', payload: { heat: nextHeat, overheated: nextOverheated } });
|
||||
}
|
||||
}, [dispatch, pipeline, state.horn?.heat, state.horn?.overheated, HORN_HEAT_UP_PER_SEC]);
|
||||
}, [dispatch, pipeline, state.horn?.heat, state.horn?.overheated]);
|
||||
|
||||
const hornStateRef = useRef({
|
||||
active: Boolean(state.horn?.active),
|
||||
heat: state.horn?.heat ?? 0,
|
||||
overheated: Boolean(state.horn?.overheated),
|
||||
});
|
||||
const stopHornRef = useRef(stopHorn);
|
||||
|
||||
useEffect(() => {
|
||||
hornStateRef.current = {
|
||||
active: Boolean(state.horn?.active),
|
||||
@@ -525,7 +612,7 @@ export function ControlSystemProvider({ children }) {
|
||||
}
|
||||
}, tickMs);
|
||||
return () => clearInterval(interval);
|
||||
}, [dispatch, hornNeedsTick, HORN_HEAT_COOL_PER_SEC, HORN_HEAT_RESUME_THRESHOLD, HORN_HEAT_UP_PER_SEC]);
|
||||
}, [dispatch, hornNeedsTick]);
|
||||
|
||||
const setManualDockAssistActive = useCallback(
|
||||
(active) => {
|
||||
@@ -561,41 +648,32 @@ export function ControlSystemProvider({ children }) {
|
||||
dispatch({ type: 'control/set-mic-ptt', payload: Boolean(active) });
|
||||
}, []);
|
||||
|
||||
const contextValue = useMemo(
|
||||
const actionImplementations = useMemo(
|
||||
() => ({
|
||||
state,
|
||||
dispatch,
|
||||
pipeline,
|
||||
overcurrentLimiter,
|
||||
actions: {
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
setServoAngle,
|
||||
nudgeServo,
|
||||
goServoHome,
|
||||
runMacro,
|
||||
stopAllMotion,
|
||||
sendOiCommand,
|
||||
setSensorStream,
|
||||
setNightVision,
|
||||
toggleNightVision,
|
||||
updateKeyBinding,
|
||||
resetKeyBindings,
|
||||
registerInputState,
|
||||
setManualDockAssistActive,
|
||||
toggleManualDockAssist,
|
||||
setSongNote,
|
||||
sendSong,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setMicPttActive,
|
||||
},
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
setServoAngle,
|
||||
nudgeServo,
|
||||
goServoHome,
|
||||
runMacro,
|
||||
stopAllMotion,
|
||||
sendOiCommand,
|
||||
setSensorStream,
|
||||
setNightVision,
|
||||
toggleNightVision,
|
||||
updateKeyBinding,
|
||||
resetKeyBindings,
|
||||
registerInputState,
|
||||
setManualDockAssistActive,
|
||||
toggleManualDockAssist,
|
||||
setSongNote,
|
||||
sendSong,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setMicPttActive,
|
||||
}),
|
||||
[
|
||||
state,
|
||||
pipeline,
|
||||
overcurrentLimiter,
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
@@ -621,13 +699,106 @@ export function ControlSystemProvider({ children }) {
|
||||
],
|
||||
);
|
||||
|
||||
return <ControlSystemContext.Provider value={contextValue}>{children}</ControlSystemContext.Provider>;
|
||||
const snapshot = useMemo(
|
||||
() => ({
|
||||
state,
|
||||
dispatch,
|
||||
pipeline,
|
||||
overcurrentLimiter,
|
||||
actions: stableActions,
|
||||
}),
|
||||
[state, pipeline, overcurrentLimiter, stableActions],
|
||||
);
|
||||
|
||||
if (snapshotRef.current == null) {
|
||||
/*
|
||||
The first render has to make a snapshot available synchronously because
|
||||
descendants can call selector hooks during that same render pass. Later
|
||||
renders publish updates from the layout effect below, after React has
|
||||
committed the provider's new state.
|
||||
*/
|
||||
snapshotRef.current = snapshot;
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
actionImplementationsRef.current = actionImplementations;
|
||||
}, [actionImplementations]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (snapshotRef.current === snapshot) return;
|
||||
snapshotRef.current = snapshot;
|
||||
notifyControlSubscribers(snapshot);
|
||||
}, [notifyControlSubscribers, snapshot]);
|
||||
|
||||
const store = useMemo(
|
||||
() => ({
|
||||
getSnapshot: getControlSnapshot,
|
||||
subscribe: subscribeControlSnapshot,
|
||||
actions: stableActions,
|
||||
}),
|
||||
[getControlSnapshot, stableActions, subscribeControlSnapshot],
|
||||
);
|
||||
|
||||
return <ControlSystemContext.Provider value={store}>{children}</ControlSystemContext.Provider>;
|
||||
}
|
||||
|
||||
export function useControlSelector(selector, equalityFn = Object.is) {
|
||||
const store = useContext(ControlSystemContext);
|
||||
if (!store) {
|
||||
throw new Error('useControlSelector must be used within ControlSystemProvider');
|
||||
}
|
||||
const selectorRef = useRef(selector);
|
||||
const equalityRef = useRef(equalityFn);
|
||||
|
||||
const [selected, setSelected] = useState(() => selector(store.getSnapshot()));
|
||||
|
||||
useEffect(() => {
|
||||
/*
|
||||
Selector functions are often declared inline at the call site. Refreshing
|
||||
these refs from an effect keeps the subscription callback pointed at the
|
||||
newest selector/equality pair without making render mutate refs.
|
||||
*/
|
||||
selectorRef.current = selector;
|
||||
equalityRef.current = equalityFn;
|
||||
}, [equalityFn, selector]);
|
||||
|
||||
useEffect(() => {
|
||||
/*
|
||||
Recheck once after subscribing because the provider may have published a
|
||||
newer snapshot between this component's render and its effect. The equality
|
||||
guard keeps that synchronization from causing a redundant render.
|
||||
*/
|
||||
setSelected((prev) => {
|
||||
const next = selectorRef.current(store.getSnapshot());
|
||||
return equalityRef.current(prev, next) ? prev : next;
|
||||
});
|
||||
|
||||
return store.subscribe(
|
||||
(snapshot) => selectorRef.current(snapshot),
|
||||
(nextSelected) => {
|
||||
setSelected((prev) => (equalityRef.current(prev, nextSelected) ? prev : nextSelected));
|
||||
},
|
||||
(a, b) => equalityRef.current(a, b),
|
||||
);
|
||||
}, [store]);
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
export function useControlActions() {
|
||||
const store = useContext(ControlSystemContext);
|
||||
if (!store) {
|
||||
throw new Error('useControlActions must be used within ControlSystemProvider');
|
||||
}
|
||||
return store.actions;
|
||||
}
|
||||
|
||||
export function useControlSystem() {
|
||||
const context = useContext(ControlSystemContext);
|
||||
if (!context) {
|
||||
throw new Error('useControlSystem must be used within ControlSystemProvider');
|
||||
}
|
||||
return context;
|
||||
/*
|
||||
This compatibility hook intentionally selects the whole snapshot, so it has
|
||||
the same broad update behavior as the old context API. New and migrated
|
||||
consumers should prefer useControlSelector/useControlActions so they only
|
||||
re-render for data they actually read.
|
||||
*/
|
||||
return useControlSelector((snapshot) => snapshot);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// Control Module Exports
|
||||
// Purpose: Re-exports control context/providers and input managers from one entrypoint. Scope: Keeps control imports stable and concise for app/module consumers.
|
||||
export { ControlSystemProvider, useControlSystem } from './ControlContext.jsx';
|
||||
export {
|
||||
ControlSystemProvider,
|
||||
useControlActions,
|
||||
useControlSelector,
|
||||
useControlSystem,
|
||||
} from './ControlContext.jsx';
|
||||
export { default as KeyboardInputManager } from './inputs/KeyboardInputManager.jsx';
|
||||
export { default as GamepadInputManager } from './inputs/GamepadInputManager.jsx';
|
||||
export { useOvercurrentLimiter } from './overcurrentLimiter.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Gamepad Input Manager
|
||||
// Purpose: Converts polled gamepad state into normalized control actions/commands. Scope: Integrates bindings, deadzone math, and dispatch callbacks for driving.
|
||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import { useControlSystem } from '../ControlContext.jsx';
|
||||
import { useControlActions, useControlSelector } from '../ControlContext.jsx';
|
||||
import { useSettingsNamespace } from '../../settings/index.js';
|
||||
import { GAMEPAD_SETTINGS_DEFAULTS, GAMEPAD_PROFILE_DEFAULT } from '../../settings/namespaces.js';
|
||||
import {
|
||||
@@ -48,17 +48,16 @@ function pickActivePad(pads, activeSignature) {
|
||||
|
||||
export default function GamepadInputManager() {
|
||||
const {
|
||||
state,
|
||||
actions: {
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
setServoAngle,
|
||||
runMacro,
|
||||
toggleNightVision,
|
||||
registerInputState,
|
||||
},
|
||||
} = useControlSystem();
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
setServoAngle,
|
||||
runMacro,
|
||||
toggleNightVision,
|
||||
registerInputState,
|
||||
} = useControlActions();
|
||||
const cameraAngle = useControlSelector((control) => control.state.camera?.angle);
|
||||
const cameraConfig = useControlSelector((control) => control.state.camera?.config);
|
||||
const dockAssist = useManualDockAssist();
|
||||
const { value: gamepadSettings, save: saveGamepadSettings } = useSettingsNamespace(
|
||||
'gamepad',
|
||||
@@ -162,8 +161,8 @@ export default function GamepadInputManager() {
|
||||
// with the newest settings and control actions without resubscribing to the hub.
|
||||
latestRef.current = {
|
||||
activeSignature,
|
||||
cameraAngle: state.camera?.angle,
|
||||
cameraConfig: state.camera?.config,
|
||||
cameraAngle,
|
||||
cameraConfig,
|
||||
dockAssist,
|
||||
gamepadSettings,
|
||||
registerInputState,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Keyboard Input Manager
|
||||
// Purpose: Captures and translates keyboard events into normalized control intents. Scope: Owns keydown/keyup listeners and dispatch coordination for drive controls.
|
||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import { useControlSystem } from '../ControlContext.jsx';
|
||||
import { useControlActions, useControlSelector } from '../ControlContext.jsx';
|
||||
import { useChat } from '../../context/ChatContext.jsx';
|
||||
import { useSessionActions, useSessionSelector } from '../../context/SessionContext.jsx';
|
||||
import { normalizeKeymapEntries, tokensForEvent } from '../keymapUtils.js';
|
||||
@@ -83,30 +83,32 @@ function shouldIgnoreEvent(event) {
|
||||
|
||||
export default function KeyboardInputManager() {
|
||||
const {
|
||||
state,
|
||||
actions: {
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
nudgeServo,
|
||||
runMacro,
|
||||
stopAllMotion,
|
||||
registerInputState,
|
||||
toggleNightVision,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setMicPttActive,
|
||||
setSongNote,
|
||||
sendSong,
|
||||
},
|
||||
} = useControlSystem();
|
||||
setMode,
|
||||
setDriveVector,
|
||||
setAuxMotors,
|
||||
nudgeServo,
|
||||
runMacro,
|
||||
stopAllMotion,
|
||||
registerInputState,
|
||||
toggleNightVision,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setMicPttActive,
|
||||
setSongNote,
|
||||
sendSong,
|
||||
} = useControlActions();
|
||||
const rawKeymap = useControlSelector((control) => control.state.keymap);
|
||||
const cameraNudgeDegrees = useControlSelector((control) => control.state.camera?.config?.nudgeDegrees);
|
||||
const songNote = useControlSelector((control) => control.state.song?.note);
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const hornActive = useControlSelector((control) => Boolean(control.state.horn?.active));
|
||||
const homeAssistant = useSessionSelector((state) => state.session?.homeAssistant || null);
|
||||
const dockAssist = useManualDockAssist();
|
||||
const { homeAssistantSetState } = useSessionActions();
|
||||
const { focusChat, isChatFocused } = useChat();
|
||||
const { value: inputSettings } = useSettingsNamespace('inputs', INPUT_SETTINGS_DEFAULTS);
|
||||
const { save: saveVideoSettings } = useSettingsNamespace('video', VIDEO_SETTINGS_DEFAULTS);
|
||||
const keymap = useMemo(() => normalizeKeymapEntries(state.keymap), [state.keymap]);
|
||||
const keymap = useMemo(() => normalizeKeymapEntries(rawKeymap), [rawKeymap]);
|
||||
const actionTokens = useMemo(() => {
|
||||
const tokens = new Set();
|
||||
Object.values(keymap).forEach((bindingSet) => {
|
||||
@@ -132,8 +134,8 @@ export default function KeyboardInputManager() {
|
||||
return mapTiltSpeedToInterval(tiltSpeed);
|
||||
}, [inputSettings?.keyboard]);
|
||||
const servoStep = useMemo(
|
||||
() => Math.abs(state.camera?.config?.nudgeDegrees || 1),
|
||||
[state.camera?.config?.nudgeDegrees],
|
||||
() => Math.abs(cameraNudgeDegrees || 1),
|
||||
[cameraNudgeDegrees],
|
||||
);
|
||||
|
||||
const activeTokensRef = useRef(new Set());
|
||||
@@ -352,7 +354,7 @@ export default function KeyboardInputManager() {
|
||||
setMicPttActive,
|
||||
setMode,
|
||||
setSongNote,
|
||||
songNote: state.song?.note,
|
||||
songNote,
|
||||
startHorn,
|
||||
stopAllMotion,
|
||||
stopHorn,
|
||||
@@ -455,11 +457,11 @@ export default function KeyboardInputManager() {
|
||||
|
||||
useEffect(() => {
|
||||
latestResetAllRef.current();
|
||||
}, [state.roverId]);
|
||||
}, [roverId]);
|
||||
|
||||
useEffect(() => {
|
||||
hornActiveRef.current = Boolean(state.horn?.active);
|
||||
}, [state.horn?.active]);
|
||||
hornActiveRef.current = hornActive;
|
||||
}, [hornActive]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useControlSystem } from '../../controls/index.js';
|
||||
import { useControlActions, useControlSelector } from '../../controls/index.js';
|
||||
import { useTelemetryFrame } from '../../context/TelemetryContext.jsx';
|
||||
|
||||
export function useManualDockAssist(options = {}) {
|
||||
const { manageLifecycle = false } = options;
|
||||
const {
|
||||
state: { roverId, manualDockAssist },
|
||||
actions,
|
||||
} = useControlSystem();
|
||||
const roverId = useControlSelector((control) => control.state.roverId);
|
||||
const active = useControlSelector((control) => Boolean(control.state.manualDockAssist?.active));
|
||||
const actions = useControlActions();
|
||||
const frame = useTelemetryFrame(roverId);
|
||||
const sensors = frame?.sensors || {};
|
||||
const chargingLabel = sensors?.chargingState?.label || '';
|
||||
const docked = Boolean(sensors?.chargingSources?.homeBase);
|
||||
const charging = docked && chargingLabel.toLowerCase() !== 'not charging' && chargingLabel !== '';
|
||||
const active = Boolean(manualDockAssist?.active);
|
||||
const wasDockedRef = useRef(false);
|
||||
|
||||
const enterAssist = useCallback(() => {
|
||||
|
||||
Reference in New Issue
Block a user