test(studio): an edit accuracy benchmark for manual editing (#4760)

* test(studio): start an edit accuracy benchmark for manual editing (work in progress)

* test(studio): an edit accuracy benchmark for manual editing

Drives real pointer and keyboard gestures in the built CLI Studio on generated one-element projects and scores tracking, drop jump, reload drift, undo fidelity and smoothness in composition px.

* test(studio): move render drift out of the first benchmark PR

Render drift against a producer frame ships in the stacked follow-up so this PR stays near the size budget.

* test(studio): keep the edit accuracy bench clean under fallow

Builds the grid as a product of its axes, drops unused exports and marks the harness functions that fallow scores as complex.

* test(studio): report edit accuracy with the Studio and bench commits it measured

Moves scoring and the report files into report.mjs, stamps both commits at start, counts undo byte failures apart from the worst box, and survives Studio swapping the preview iframe mid-read.

* test(studio): bank the edit accuracy baseline measured on main

660 cases on main ae914334f: 0 pass all six checks, 304 pass everything but smoothness. Five cases that hit a harness error in the full run were rerun and spliced in.

* test(studio): state the edit accuracy build prerequisite in the runner header

* test(studio): keep the edit accuracy baseline one line per case under the formatter

* test(studio): store edit accuracy baseline values rounded up

Rounding to the nearest 0.01 stored seven 0.502 px tracking results as 0.5, which reads as a pass at the 0.5 px limit.

* test(studio): score edit smoothness on dropped frames and main-thread work per frame

* test(studio): measure edit accuracy on a still preview and score press jump

Snapshots wait for the preview frames and the box to hold still for 1 s, so Studio's asynchronous reload after a save is measured, not raced. A preview that never settles fails the metrics it feeds instead of erroring.

Adds press jump (box at press against the box before it, 0.5 px). Smoothness counts only dropped frames beyond a blank-page control driven the same way in the same Chrome; unknown trace data fails smoothness alone.

The runner takes the suite lock per chunk of 8 cases (--lock), reads the port Studio announces, keeps undo history and tmp projects inside the case dir and removes them on a signal, and stamps the CLI tree's commit and bundle hash.

* test(studio): stamp the edit accuracy build with the Studio bundle as well as the CLI

The CLI bundle hashed the same for two different Studio builds; Studio's index.html names its hashed assets, so the stamp now covers it.

* test(studio): regenerate the edit accuracy baseline on main after the settle fix

Full grid on main 14e87005d with the settle fix, press jump and the smoothness control: 70/660 pass, 314/660 pass everything but smoothness, 0 harness errors, 0 unsettled. Scored without render, which #4764 adds.

* test(studio): wait for each edit accuracy undo write before sending redo

Undo and redo each wait up to 15 s for their own write, like the settle; redo is sent only once undo landed, and a write that never lands fails undo with undoTimeout instead of scoring an untested redo. The reload waits for the files to hold still. The headline is now the accuracy count, with smoothness on its own line against the control. The settle compares each read with the window's first read, and a CLI outside a git tree no longer stops the run.
This commit is contained in:
Miguel Ángel
2026-09-30 17:07:51 +00:00
committed by GitHub
parent d572fe3baf
commit 0c6f5fd80e
8 changed files with 1961 additions and 0 deletions
+3
View File
@@ -9,6 +9,9 @@ packages/gcp-cloud-run/terraform/workflow.yaml
# toMatchFileSnapshot golden files — vitest writes these; oxfmt must not reformat them.
packages/**/__goldens__/
# Edit accuracy baseline, written by the bench one line per case so a diff reads case by case.
packages/studio/tests/e2e/edit-accuracy/baseline.json
# vendored third-party bundles inside skills — never reformat
skills/**/assets/vendor/
skills/**/*.min.js
+1
View File
@@ -75,6 +75,7 @@
"build": "vite build && tsup",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:edit-accuracy": "bun tests/e2e/edit-accuracy/run.mjs",
"test:webmcp-edit-loop": "node tests/e2e/webmcp-edit-loop.mjs",
"test:timeline-virtualization": "TIMELINE_ROW_VIRTUALIZATION=on TIMELINE_ELEMENT_COUNT=50000 node tests/e2e/timeline-virtualization.mjs",
"test:watch": "vitest",
@@ -0,0 +1,668 @@
{
"studio": "14e87005d",
"build": "a0104a7ce975",
"bench": "1f83860ed",
"grid": "full, re-scored by f1797b5c2 without render",
"cases": {
"crop-hold-center-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":20,"controlDropped":13,"work":5.2,"frameP95":60.6},
"crop-hold-center-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":17,"controlDropped":13,"work":5.84,"frameP95":59.6},
"crop-hold-center-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":true,"dropped":19,"controlDropped":13,"work":5.18,"frameP95":56.6},
"crop-hold-center-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":false,"dropped":10,"controlDropped":2,"work":5.89,"frameP95":52.71},
"crop-hold-center-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":false,"dropped":20,"controlDropped":7,"work":5.68,"frameP95":58},
"crop-hold-center-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":false,"dropped":8,"controlDropped":10,"work":6.22,"frameP95":36.3},
"crop-hold-center-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":21,"controlDropped":16,"work":5.06,"frameP95":57.3},
"crop-hold-center-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":15,"controlDropped":12,"work":6.5,"frameP95":56.5},
"crop-hold-center-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":true,"dropped":22,"controlDropped":15,"work":6.21,"frameP95":60.4},
"crop-hold-center-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":false,"dropped":24,"controlDropped":15,"work":5.34,"frameP95":63.5},
"crop-hold-center-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":false,"dropped":25,"controlDropped":15,"work":5.23,"frameP95":63.6},
"crop-hold-center-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":false,"dropped":19,"controlDropped":12,"work":5.53,"frameP95":64.3},
"crop-hold-pct-r0-nested-z100": {"pass":true,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":4,"controlDropped":4,"work":5.57,"frameP95":39.5},
"crop-hold-pct-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":6,"controlDropped":1,"work":5.74,"frameP95":42},
"crop-hold-pct-r0-nested-z50": {"pass":true,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.07,"undo":true,"dropped":5,"controlDropped":6,"work":6.35,"frameP95":37.9},
"crop-hold-pct-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":false,"dropped":2,"controlDropped":6,"work":5.62,"frameP95":21.3},
"crop-hold-pct-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.03,"reload":0.04,"undo":false,"dropped":2,"controlDropped":3,"work":5.56,"frameP95":18.2},
"crop-hold-pct-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.05,"undo":false,"dropped":5,"controlDropped":1,"work":5.68,"frameP95":35.8},
"crop-hold-pct-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":7,"controlDropped":3,"work":5.61,"frameP95":48.71},
"crop-hold-pct-r30-nested-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":7,"controlDropped":9,"work":6.1,"frameP95":48.91},
"crop-hold-pct-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.14,"reload":0.05,"undo":true,"dropped":11,"controlDropped":8,"work":5.58,"frameP95":46.61},
"crop-hold-pct-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":false,"dropped":4,"controlDropped":6,"work":5.53,"frameP95":42.61},
"crop-hold-pct-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":false,"dropped":8,"controlDropped":9,"work":5.64,"frameP95":45.71},
"crop-hold-pct-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.07,"undo":false,"dropped":12,"controlDropped":0,"work":5.6,"frameP95":60.5},
"crop-hold-px-r0-nested-z100": {"pass":true,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":8,"controlDropped":11,"work":6.28,"frameP95":40.41},
"crop-hold-px-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":16,"controlDropped":15,"work":5.84,"frameP95":59.1},
"crop-hold-px-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.07,"undo":true,"dropped":13,"controlDropped":12,"work":5.94,"frameP95":54.5},
"crop-hold-px-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":false,"dropped":15,"controlDropped":13,"work":6.21,"frameP95":65.71},
"crop-hold-px-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.03,"reload":0.04,"undo":false,"dropped":17,"controlDropped":10,"work":5.78,"frameP95":55.21},
"crop-hold-px-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.05,"undo":false,"dropped":16,"controlDropped":13,"work":5.55,"frameP95":63.5},
"crop-hold-px-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":15,"controlDropped":6,"work":6.14,"frameP95":64.41},
"crop-hold-px-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":5,"controlDropped":3,"work":5.88,"frameP95":45.7},
"crop-hold-px-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.14,"reload":0.05,"undo":true,"dropped":12,"controlDropped":10,"work":5.78,"frameP95":63.4},
"crop-hold-px-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":false,"dropped":15,"controlDropped":8,"work":5.33,"frameP95":46.41},
"crop-hold-px-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":false,"dropped":16,"controlDropped":7,"work":5.42,"frameP95":49.91},
"crop-hold-px-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.07,"undo":false,"dropped":10,"controlDropped":9,"work":6.28,"frameP95":44},
"crop-hold-xpercent-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":19,"controlDropped":10,"work":5.85,"frameP95":63},
"crop-hold-xpercent-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":16,"controlDropped":8,"work":6.31,"frameP95":63.41},
"crop-hold-xpercent-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":true,"dropped":13,"controlDropped":10,"work":6.16,"frameP95":60.11},
"crop-hold-xpercent-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":false,"dropped":5,"controlDropped":9,"work":5.95,"frameP95":42.91},
"crop-hold-xpercent-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":false,"dropped":10,"controlDropped":3,"work":6.11,"frameP95":59.8},
"crop-hold-xpercent-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":false,"dropped":21,"controlDropped":11,"work":4.87,"frameP95":57},
"crop-hold-xpercent-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":21,"controlDropped":13,"work":5.28,"frameP95":57.3},
"crop-hold-xpercent-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":21,"controlDropped":11,"work":5.69,"frameP95":61.5},
"crop-hold-xpercent-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":true,"dropped":21,"controlDropped":14,"work":6.25,"frameP95":57.71},
"crop-hold-xpercent-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":false,"dropped":12,"controlDropped":14,"work":6.35,"frameP95":51.81},
"crop-hold-xpercent-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":false,"dropped":18,"controlDropped":10,"work":5.66,"frameP95":53.7},
"crop-hold-xpercent-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":false,"dropped":14,"controlDropped":12,"work":6.47,"frameP95":51.41},
"crop-none-center-r0-nested-z100": {"pass":true,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":9,"controlDropped":13,"work":5.59,"frameP95":61.11},
"crop-none-center-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":16,"controlDropped":12,"work":6.68,"frameP95":63.71},
"crop-none-center-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.11,"reload":0.05,"undo":true,"dropped":14,"controlDropped":13,"work":6.54,"frameP95":60.4},
"crop-none-center-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":7,"controlDropped":3,"work":5.97,"frameP95":55.41},
"crop-none-center-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.03,"undo":true,"dropped":17,"controlDropped":10,"work":5.88,"frameP95":61.71},
"crop-none-center-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.11,"reload":0.05,"undo":true,"dropped":15,"controlDropped":10,"work":6,"frameP95":56.7},
"crop-none-center-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":6,"controlDropped":2,"work":6.32,"frameP95":45.5},
"crop-none-center-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":11,"controlDropped":2,"work":6.09,"frameP95":59.41},
"crop-none-center-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.08,"reload":0.07,"undo":true,"dropped":3,"controlDropped":2,"work":5.74,"frameP95":37.61},
"crop-none-center-r30-root-z100": {"pass":true,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":5,"controlDropped":11,"work":6.61,"frameP95":50.91},
"crop-none-center-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":9,"controlDropped":5,"work":6.47,"frameP95":55.3},
"crop-none-center-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.08,"reload":0.07,"undo":true,"dropped":21,"controlDropped":8,"work":5.57,"frameP95":60},
"crop-none-pct-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":20,"controlDropped":11,"work":6.1,"frameP95":63.8},
"crop-none-pct-r0-nested-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.02,"undo":true,"dropped":12,"controlDropped":14,"work":6.21,"frameP95":59.31},
"crop-none-pct-r0-nested-z50": {"pass":true,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":true,"dropped":8,"controlDropped":9,"work":6.53,"frameP95":59.21},
"crop-none-pct-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":12,"controlDropped":7,"work":6.65,"frameP95":55.1},
"crop-none-pct-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.03,"reload":0.03,"undo":true,"dropped":15,"controlDropped":12,"work":5.9,"frameP95":55.21},
"crop-none-pct-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.11,"reload":0.07,"undo":true,"dropped":17,"controlDropped":14,"work":5.99,"frameP95":53.8},
"crop-none-pct-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":true,"dropped":13,"controlDropped":6,"work":5.58,"frameP95":54.5},
"crop-none-pct-r30-nested-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.05,"undo":true,"dropped":5,"controlDropped":8,"work":6.04,"frameP95":39.8},
"crop-none-pct-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":true,"dropped":12,"controlDropped":0,"work":6.17,"frameP95":51.6},
"crop-none-pct-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":22,"controlDropped":14,"work":6.15,"frameP95":67.3},
"crop-none-pct-r30-root-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.04,"undo":true,"dropped":4,"controlDropped":9,"work":5.57,"frameP95":47},
"crop-none-pct-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.11,"reload":0.09,"undo":true,"dropped":20,"controlDropped":14,"work":5.71,"frameP95":64.61},
"crop-none-px-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":3,"controlDropped":0,"work":5.57,"frameP95":35.3},
"crop-none-px-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":9,"controlDropped":6,"work":6.2,"frameP95":55.1},
"crop-none-px-r0-nested-z50": {"pass":true,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.07,"undo":true,"dropped":0,"controlDropped":0,"work":5.46,"frameP95":17.5},
"crop-none-px-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":true,"dropped":4,"controlDropped":1,"work":6.66,"frameP95":32},
"crop-none-px-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":6,"controlDropped":0,"work":6.32,"frameP95":47.71},
"crop-none-px-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.13,"reload":0.05,"undo":true,"dropped":6,"controlDropped":0,"work":5.93,"frameP95":45.71},
"crop-none-px-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":14,"controlDropped":11,"work":6.64,"frameP95":63.91},
"crop-none-px-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":8,"controlDropped":4,"work":6.11,"frameP95":69.8},
"crop-none-px-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.14,"reload":0.07,"undo":true,"dropped":17,"controlDropped":9,"work":5.92,"frameP95":63.21},
"crop-none-px-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":17,"controlDropped":7,"work":6.33,"frameP95":58.91},
"crop-none-px-r30-root-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":true,"dropped":2,"controlDropped":10,"work":5.85,"frameP95":24.8},
"crop-none-px-r30-root-z50": {"pass":true,"tracking":0.05,"pressJump":0,"drop":0.14,"reload":0.07,"undo":true,"dropped":8,"controlDropped":9,"work":6.12,"frameP95":39.3},
"crop-tween-center-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":true,"dropped":10,"controlDropped":9,"work":5.82,"frameP95":52.71},
"crop-tween-center-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":20,"controlDropped":10,"work":6,"frameP95":56},
"crop-tween-center-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.13,"reload":0.07,"undo":true,"dropped":14,"controlDropped":10,"work":5.4,"frameP95":52},
"crop-tween-center-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":false,"dropped":4,"controlDropped":12,"work":6.27,"frameP95":45.41},
"crop-tween-center-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":false,"dropped":9,"controlDropped":6,"work":6.4,"frameP95":49.61},
"crop-tween-center-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.13,"reload":0.07,"undo":false,"dropped":9,"controlDropped":9,"work":5.83,"frameP95":46.8},
"crop-tween-center-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":19,"controlDropped":12,"work":5.49,"frameP95":62.8},
"crop-tween-center-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":true,"dropped":21,"controlDropped":14,"work":5.93,"frameP95":64.3},
"crop-tween-center-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.08,"undo":true,"dropped":15,"controlDropped":9,"work":5.8,"frameP95":60},
"crop-tween-center-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":false,"dropped":17,"controlDropped":12,"work":5.69,"frameP95":57.6},
"crop-tween-center-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":false,"dropped":18,"controlDropped":12,"work":5.71,"frameP95":59.1},
"crop-tween-center-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.08,"undo":false,"dropped":13,"controlDropped":14,"work":5.93,"frameP95":55.41},
"crop-tween-pct-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":true,"dropped":25,"controlDropped":13,"work":5.76,"frameP95":66.9},
"crop-tween-pct-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.03,"reload":0.01,"undo":true,"dropped":17,"controlDropped":14,"work":5.97,"frameP95":55.6},
"crop-tween-pct-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.07,"undo":true,"dropped":26,"controlDropped":13,"work":5.65,"frameP95":59.1},
"crop-tween-pct-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":false,"dropped":21,"controlDropped":15,"work":4.65,"frameP95":65.3},
"crop-tween-pct-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.03,"reload":0.03,"undo":false,"dropped":18,"controlDropped":14,"work":6.51,"frameP95":65.3},
"crop-tween-pct-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.1,"reload":0.05,"undo":false,"dropped":23,"controlDropped":15,"work":5.11,"frameP95":62.91},
"crop-tween-pct-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":true,"dropped":6,"controlDropped":5,"work":5.8,"frameP95":26.81},
"crop-tween-pct-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":true,"dropped":11,"controlDropped":4,"work":5.82,"frameP95":45.71},
"crop-tween-pct-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.08,"reload":0.06,"undo":true,"dropped":8,"controlDropped":3,"work":5.94,"frameP95":43.1},
"crop-tween-pct-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.05,"reload":0,"undo":false,"dropped":8,"controlDropped":5,"work":6.08,"frameP95":58.6},
"crop-tween-pct-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":false,"dropped":5,"controlDropped":4,"work":6.68,"frameP95":40.5},
"crop-tween-pct-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":false,"dropped":8,"controlDropped":8,"work":5.51,"frameP95":52.61},
"crop-tween-px-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.09,"reload":0,"undo":true,"dropped":15,"controlDropped":11,"work":5.59,"frameP95":50.91},
"crop-tween-px-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":true,"dropped":7,"controlDropped":4,"work":6.16,"frameP95":49.91},
"crop-tween-px-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.07,"undo":true,"dropped":8,"controlDropped":5,"work":6.2,"frameP95":49.41},
"crop-tween-px-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":false,"dropped":11,"controlDropped":1,"work":5.99,"frameP95":46.8},
"crop-tween-px-r0-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0,"reload":0.02,"undo":false,"dropped":14,"controlDropped":7,"work":5.75,"frameP95":58.7},
"crop-tween-px-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":false,"dropped":12,"controlDropped":8,"work":6.37,"frameP95":61.71},
"crop-tween-px-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.08,"reload":0,"undo":true,"dropped":9,"controlDropped":3,"work":5.74,"frameP95":41},
"crop-tween-px-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.05,"undo":true,"dropped":21,"controlDropped":10,"work":5.36,"frameP95":60.21},
"crop-tween-px-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.08,"reload":0.05,"undo":true,"dropped":15,"controlDropped":7,"work":5.67,"frameP95":58.41},
"crop-tween-px-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.06,"reload":0,"undo":false,"dropped":13,"controlDropped":1,"work":5.66,"frameP95":54.41},
"crop-tween-px-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.04,"undo":false,"dropped":6,"controlDropped":6,"work":5.5,"frameP95":40},
"crop-tween-px-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.07,"reload":0.05,"undo":false,"dropped":12,"controlDropped":7,"work":6.06,"frameP95":53.5},
"crop-tween-xpercent-r0-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":true,"dropped":5,"controlDropped":2,"work":5.78,"frameP95":38},
"crop-tween-xpercent-r0-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":8,"controlDropped":6,"work":5.81,"frameP95":54.21},
"crop-tween-xpercent-r0-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.13,"reload":0.07,"undo":true,"dropped":5,"controlDropped":2,"work":5.16,"frameP95":51.5},
"crop-tween-xpercent-r0-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.03,"reload":0,"undo":true,"dropped":10,"controlDropped":6,"work":6.37,"frameP95":52.1},
"crop-tween-xpercent-r0-root-z200": {"pass":true,"tracking":0.02,"pressJump":0,"drop":0.04,"reload":0.04,"undo":true,"dropped":5,"controlDropped":6,"work":6.83,"frameP95":34.71},
"crop-tween-xpercent-r0-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.13,"reload":0.07,"undo":true,"dropped":11,"controlDropped":9,"work":5.89,"frameP95":50.1},
"crop-tween-xpercent-r30-nested-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":true,"dropped":18,"controlDropped":15,"work":5.74,"frameP95":64.1},
"crop-tween-xpercent-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":true,"dropped":23,"controlDropped":12,"work":5.39,"frameP95":65.71},
"crop-tween-xpercent-r30-nested-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.08,"undo":true,"dropped":18,"controlDropped":8,"work":7.12,"frameP95":62.61},
"crop-tween-xpercent-r30-root-z100": {"pass":false,"tracking":0.04,"pressJump":0,"drop":0.07,"reload":0,"undo":false,"dropped":2,"controlDropped":0,"work":4.98,"frameP95":17.6},
"crop-tween-xpercent-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":0,"drop":0.02,"reload":0.03,"undo":false,"dropped":4,"controlDropped":2,"work":5.42,"frameP95":44.6},
"crop-tween-xpercent-r30-root-z50": {"pass":false,"tracking":0.05,"pressJump":0,"drop":0.12,"reload":0.08,"undo":false,"dropped":7,"controlDropped":2,"work":6.8,"frameP95":40.91},
"move-hold-center-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":15,"controlDropped":11,"work":7,"frameP95":58.1},
"move-hold-center-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":19,"controlDropped":10,"work":7.35,"frameP95":60.21},
"move-hold-center-r0-nested-z50": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":17,"controlDropped":12,"work":6.75,"frameP95":56.1},
"move-hold-center-r0-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":5,"work":7.17,"frameP95":54.11},
"move-hold-center-r0-root-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":4,"work":8.57,"frameP95":66.61},
"move-hold-center-r0-root-z50": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":13,"controlDropped":9,"work":7.03,"frameP95":64.6},
"move-hold-center-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":23,"controlDropped":13,"work":7.68,"frameP95":67.9},
"move-hold-center-r30-nested-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":17,"controlDropped":11,"work":9.47,"frameP95":63.3},
"move-hold-center-r30-nested-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":19,"controlDropped":15,"work":8.62,"frameP95":67},
"move-hold-center-r30-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":23,"controlDropped":11,"work":7.15,"frameP95":71.91},
"move-hold-center-r30-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":22,"controlDropped":14,"work":8.54,"frameP95":65.41},
"move-hold-center-r30-root-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":17,"controlDropped":11,"work":7.52,"frameP95":64.81},
"move-hold-pct-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":6.05,"frameP95":17.91},
"move-hold-pct-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":7,"controlDropped":1,"work":8,"frameP95":41.21},
"move-hold-pct-r0-nested-z50": {"pass":false,"tracking":0.54,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":1,"work":7.81,"frameP95":53.81},
"move-hold-pct-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":1,"work":6.88,"frameP95":54},
"move-hold-pct-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.01,"undo":true,"dropped":5,"controlDropped":1,"work":8.18,"frameP95":52.21},
"move-hold-pct-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":0,"controlDropped":0,"work":6.9,"frameP95":17.5},
"move-hold-pct-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":3,"work":8.23,"frameP95":49.1},
"move-hold-pct-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":12,"controlDropped":0,"work":6.91,"frameP95":50.41},
"move-hold-pct-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":7,"controlDropped":3,"work":7.75,"frameP95":42.7},
"move-hold-pct-r30-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":6,"controlDropped":5,"work":6.22,"frameP95":42.6},
"move-hold-pct-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":9,"controlDropped":5,"work":7.57,"frameP95":45.5},
"move-hold-pct-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":12,"controlDropped":2,"work":7.81,"frameP95":59.4},
"move-hold-px-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":9,"controlDropped":11,"work":7.99,"frameP95":57},
"move-hold-px-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":11,"work":8.84,"frameP95":61.1},
"move-hold-px-r0-nested-z50": {"pass":false,"tracking":0.54,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":12,"controlDropped":12,"work":8.89,"frameP95":57.41},
"move-hold-px-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":19,"controlDropped":13,"work":6.91,"frameP95":59.5},
"move-hold-px-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.01,"undo":true,"dropped":15,"controlDropped":11,"work":8.57,"frameP95":67.11},
"move-hold-px-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":14,"controlDropped":14,"work":9.39,"frameP95":66.41},
"move-hold-px-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":11,"work":6.89,"frameP95":53.3},
"move-hold-px-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":3,"work":8.38,"frameP95":57.21},
"move-hold-px-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":13,"controlDropped":2,"work":8.98,"frameP95":64.11},
"move-hold-px-r30-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":8,"work":8.02,"frameP95":58.21},
"move-hold-px-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":11,"controlDropped":10,"work":6.42,"frameP95":51},
"move-hold-px-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":15,"controlDropped":12,"work":8.41,"frameP95":64.6},
"move-hold-xpercent-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":18,"controlDropped":10,"work":6.84,"frameP95":64.8},
"move-hold-xpercent-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":12,"controlDropped":12,"work":8.82,"frameP95":63.3},
"move-hold-xpercent-r0-nested-z50": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":13,"controlDropped":1,"work":8.67,"frameP95":59.6},
"move-hold-xpercent-r0-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":9,"work":7.88,"frameP95":57.8},
"move-hold-xpercent-r0-root-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":12,"controlDropped":1,"work":9.03,"frameP95":59.2},
"move-hold-xpercent-r0-root-z50": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":14,"controlDropped":10,"work":7.76,"frameP95":56.5},
"move-hold-xpercent-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":16,"controlDropped":13,"work":7.27,"frameP95":60.1},
"move-hold-xpercent-r30-nested-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":17,"controlDropped":11,"work":7.03,"frameP95":58.8},
"move-hold-xpercent-r30-nested-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":19,"controlDropped":11,"work":8.44,"frameP95":66.2},
"move-hold-xpercent-r30-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":6,"work":6.89,"frameP95":61},
"move-hold-xpercent-r30-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":10,"controlDropped":5,"work":7.42,"frameP95":52.71},
"move-hold-xpercent-r30-root-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":13,"controlDropped":11,"work":7.05,"frameP95":64.91},
"move-none-center-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":108.19,"reload":0,"undo":true,"dropped":15,"controlDropped":10,"work":8.93,"frameP95":65},
"move-none-center-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.17,"reload":0.03,"undo":true,"dropped":15,"controlDropped":9,"work":7,"frameP95":64.71},
"move-none-center-r0-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":108.23,"reload":0.05,"undo":true,"dropped":12,"controlDropped":11,"work":7.39,"frameP95":63},
"move-none-center-r0-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":10,"work":7.05,"frameP95":57.9},
"move-none-center-r0-root-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":13,"controlDropped":5,"work":7.09,"frameP95":58.91},
"move-none-center-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":7,"controlDropped":7,"work":7.23,"frameP95":53.31},
"move-none-center-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.19,"reload":0,"undo":true,"dropped":11,"controlDropped":2,"work":8.08,"frameP95":56.41},
"move-none-center-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":108.18,"reload":0.04,"undo":true,"dropped":12,"controlDropped":9,"work":8.97,"frameP95":60.21},
"move-none-center-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":108.15,"reload":0.07,"undo":true,"dropped":7,"controlDropped":4,"work":7.18,"frameP95":55},
"move-none-center-r30-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":11,"work":7.3,"frameP95":53.5},
"move-none-center-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":11,"controlDropped":6,"work":8.28,"frameP95":54.71},
"move-none-center-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":14,"controlDropped":11,"work":8.36,"frameP95":58.3},
"move-none-pct-r0-nested-z100": {"pass":false,"tracking":0.53,"pressJump":0,"drop":108.15,"reload":0,"undo":true,"dropped":15,"controlDropped":8,"work":8.31,"frameP95":61.8},
"move-none-pct-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.19,"reload":0.02,"undo":true,"dropped":17,"controlDropped":14,"work":7.51,"frameP95":61},
"move-none-pct-r0-nested-z50": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.23,"reload":0.05,"undo":true,"dropped":13,"controlDropped":5,"work":8.97,"frameP95":55.5},
"move-none-pct-r0-root-z100": {"pass":false,"tracking":0.53,"pressJump":0,"drop":72.11,"reload":0,"undo":true,"dropped":12,"controlDropped":12,"work":7.83,"frameP95":67.91},
"move-none-pct-r0-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":72.14,"reload":0.04,"undo":true,"dropped":12,"controlDropped":5,"work":7.67,"frameP95":54.5},
"move-none-pct-r0-root-z50": {"pass":false,"tracking":0.52,"pressJump":0,"drop":72.16,"reload":0.07,"undo":true,"dropped":12,"controlDropped":12,"work":7.33,"frameP95":52},
"move-none-pct-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.23,"reload":0,"undo":true,"dropped":9,"controlDropped":6,"work":8.45,"frameP95":54},
"move-none-pct-r30-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.16,"reload":0.06,"undo":true,"dropped":12,"controlDropped":9,"work":8.12,"frameP95":55.81},
"move-none-pct-r30-nested-z50": {"pass":false,"tracking":0.52,"pressJump":0,"drop":108.23,"reload":0.05,"undo":true,"dropped":7,"controlDropped":7,"work":6.43,"frameP95":50.5},
"move-none-pct-r30-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":72.14,"reload":0,"undo":true,"dropped":21,"controlDropped":11,"work":9.1,"frameP95":66.4},
"move-none-pct-r30-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":72.11,"reload":0.04,"undo":true,"dropped":12,"controlDropped":9,"work":8.86,"frameP95":65.4},
"move-none-pct-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":72.11,"reload":0.07,"undo":true,"dropped":14,"controlDropped":11,"work":8.82,"frameP95":62},
"move-none-px-r0-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":108.19,"reload":0,"undo":true,"dropped":5,"controlDropped":0,"work":8.17,"frameP95":34.9},
"move-none-px-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.17,"reload":0.04,"undo":true,"dropped":13,"controlDropped":11,"work":8.29,"frameP95":69.9},
"move-none-px-r0-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":108.23,"reload":0.07,"undo":true,"dropped":9,"controlDropped":7,"work":7.67,"frameP95":50.5},
"move-none-px-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":50.03,"reload":0,"undo":true,"dropped":8,"controlDropped":2,"work":8.56,"frameP95":46.91},
"move-none-px-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":50.01,"reload":0.04,"undo":true,"dropped":6,"controlDropped":6,"work":7.79,"frameP95":33.91},
"move-none-px-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":50.09,"reload":0.07,"undo":true,"dropped":6,"controlDropped":0,"work":7.05,"frameP95":33.21},
"move-none-px-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":108.19,"reload":0,"undo":true,"dropped":12,"controlDropped":5,"work":8.44,"frameP95":61.5},
"move-none-px-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":108.2,"reload":0.05,"undo":true,"dropped":14,"controlDropped":2,"work":7.79,"frameP95":54},
"move-none-px-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":108.23,"reload":0.07,"undo":true,"dropped":12,"controlDropped":2,"work":6.95,"frameP95":59.8},
"move-none-px-r30-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":50.03,"reload":0,"undo":true,"dropped":11,"controlDropped":7,"work":8.19,"frameP95":57.61},
"move-none-px-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":50.01,"reload":0.04,"undo":true,"dropped":13,"controlDropped":0,"work":6.89,"frameP95":59.8},
"move-none-px-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":50.04,"reload":0.07,"undo":true,"dropped":9,"controlDropped":3,"work":7.37,"frameP95":54.4},
"move-tween-center-r0-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":7,"work":8.33,"frameP95":54},
"move-tween-center-r0-nested-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":13,"controlDropped":3,"work":7.87,"frameP95":54.61},
"move-tween-center-r0-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":12,"controlDropped":10,"work":7.3,"frameP95":53.6},
"move-tween-center-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":2,"work":7.1,"frameP95":48.1},
"move-tween-center-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":1,"work":7.79,"frameP95":65},
"move-tween-center-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":7,"controlDropped":8,"work":6.42,"frameP95":46},
"move-tween-center-r30-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":18,"controlDropped":11,"work":8.17,"frameP95":66.1},
"move-tween-center-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":13,"work":8.45,"frameP95":63.3},
"move-tween-center-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":17,"controlDropped":11,"work":8.49,"frameP95":61.6},
"move-tween-center-r30-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":11,"work":7.44,"frameP95":60.11},
"move-tween-center-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":14,"controlDropped":11,"work":8.66,"frameP95":61.1},
"move-tween-center-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":13,"controlDropped":13,"work":7.49,"frameP95":59.3},
"move-tween-pct-r0-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":20,"controlDropped":12,"work":7.98,"frameP95":64.4},
"move-tween-pct-r0-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":21,"controlDropped":10,"work":8.04,"frameP95":68.5},
"move-tween-pct-r0-nested-z50": {"pass":false,"tracking":0.54,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":16,"controlDropped":13,"work":8.14,"frameP95":67},
"move-tween-pct-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":20,"controlDropped":11,"work":7.39,"frameP95":65.9},
"move-tween-pct-r0-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":0,"reload":0.02,"undo":true,"dropped":14,"controlDropped":14,"work":8.12,"frameP95":64.8},
"move-tween-pct-r0-root-z50": {"pass":false,"tracking":0.54,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":18,"controlDropped":12,"work":7.99,"frameP95":62.41},
"move-tween-pct-r30-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":6,"controlDropped":3,"work":6.98,"frameP95":27},
"move-tween-pct-r30-nested-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":8,"controlDropped":2,"work":7.17,"frameP95":59.91},
"move-tween-pct-r30-nested-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":10,"controlDropped":2,"work":7.14,"frameP95":59.3},
"move-tween-pct-r30-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":5,"controlDropped":2,"work":7.83,"frameP95":41},
"move-tween-pct-r30-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":8,"controlDropped":2,"work":8.37,"frameP95":42.6},
"move-tween-pct-r30-root-z50": {"pass":false,"tracking":0.56,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":12,"controlDropped":6,"work":7.9,"frameP95":55.4},
"move-tween-px-r0-nested-z100": {"pass":false,"tracking":0.75,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":10,"work":7.33,"frameP95":51.1},
"move-tween-px-r0-nested-z200": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":9,"controlDropped":9,"work":8.06,"frameP95":51.8},
"move-tween-px-r0-nested-z50": {"pass":false,"tracking":0.76,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":11,"controlDropped":3,"work":8.35,"frameP95":48.8},
"move-tween-px-r0-root-z100": {"pass":false,"tracking":0.75,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":9,"controlDropped":7,"work":7.97,"frameP95":46.4},
"move-tween-px-r0-root-z200": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":10,"controlDropped":0,"work":7.69,"frameP95":46.9},
"move-tween-px-r0-root-z50": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":5,"work":8.29,"frameP95":44.91},
"move-tween-px-r30-nested-z100": {"pass":false,"tracking":0.71,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":5,"work":7.72,"frameP95":57.1},
"move-tween-px-r30-nested-z200": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":12,"controlDropped":7,"work":7.97,"frameP95":58.41},
"move-tween-px-r30-nested-z50": {"pass":false,"tracking":0.73,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":8,"controlDropped":1,"work":7.16,"frameP95":56.6},
"move-tween-px-r30-root-z100": {"pass":false,"tracking":0.71,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":1,"work":7.99,"frameP95":54.5},
"move-tween-px-r30-root-z200": {"pass":false,"tracking":0.71,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":9,"controlDropped":6,"work":7.12,"frameP95":54.41},
"move-tween-px-r30-root-z50": {"pass":false,"tracking":0.73,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":4,"work":8.01,"frameP95":52.71},
"move-tween-xpercent-r0-nested-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":144.24,"reload":0,"undo":true,"dropped":9,"controlDropped":6,"work":8.15,"frameP95":53.8},
"move-tween-xpercent-r0-nested-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":144.22,"reload":0.04,"undo":true,"dropped":8,"controlDropped":2,"work":7.98,"frameP95":51.8},
"move-tween-xpercent-r0-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":144.22,"reload":0.05,"undo":true,"dropped":9,"controlDropped":4,"work":7.62,"frameP95":52.61},
"move-tween-xpercent-r0-root-z100": {"pass":false,"tracking":0.51,"pressJump":0,"drop":144.24,"reload":0,"undo":true,"dropped":12,"controlDropped":6,"work":8.11,"frameP95":55.2},
"move-tween-xpercent-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":0,"drop":144.22,"reload":0.04,"undo":true,"dropped":10,"controlDropped":1,"work":7.68,"frameP95":50.3},
"move-tween-xpercent-r0-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":144.22,"reload":0.05,"undo":true,"dropped":15,"controlDropped":12,"work":9.2,"frameP95":65.71},
"move-tween-xpercent-r30-nested-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":144.24,"reload":0,"undo":true,"dropped":17,"controlDropped":10,"work":6.74,"frameP95":61.91},
"move-tween-xpercent-r30-nested-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":144.22,"reload":0.03,"undo":true,"dropped":16,"controlDropped":12,"work":10.79,"frameP95":65.91},
"move-tween-xpercent-r30-nested-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":144.27,"reload":0.07,"undo":true,"dropped":13,"controlDropped":2,"work":7.28,"frameP95":61.5},
"move-tween-xpercent-r30-root-z100": {"pass":false,"tracking":0.52,"pressJump":0,"drop":144.24,"reload":0,"undo":true,"dropped":8,"controlDropped":2,"work":7.97,"frameP95":56.61},
"move-tween-xpercent-r30-root-z200": {"pass":false,"tracking":0.52,"pressJump":0,"drop":144.22,"reload":0.03,"undo":true,"dropped":11,"controlDropped":0,"work":8.35,"frameP95":58.8},
"move-tween-xpercent-r30-root-z50": {"pass":false,"tracking":0.53,"pressJump":0,"drop":144.27,"reload":0.07,"undo":true,"dropped":13,"controlDropped":1,"work":7.32,"frameP95":58.81},
"nudge-hold-center-r0-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":13.14,"frameP95":59.4},
"nudge-hold-center-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":5,"controlDropped":2,"work":7.98,"frameP95":99.21},
"nudge-hold-center-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":3,"controlDropped":2,"work":7.21,"frameP95":56.3},
"nudge-hold-center-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":0,"work":7.55,"frameP95":55.9},
"nudge-hold-center-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":2,"controlDropped":3,"work":10.52,"frameP95":57},
"nudge-hold-center-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":2,"controlDropped":1,"work":10.44,"frameP95":49.61},
"nudge-hold-center-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":9.95,"frameP95":71.3},
"nudge-hold-center-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":3,"controlDropped":2,"work":8.43,"frameP95":52.3},
"nudge-hold-center-r30-nested-z50": {"pass":false,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":2,"controlDropped":2,"work":9.12,"frameP95":58.2},
"nudge-hold-center-r30-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":6.6,"frameP95":68.31},
"nudge-hold-center-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":7,"controlDropped":4,"work":11.98,"frameP95":78.91},
"nudge-hold-center-r30-root-z50": {"pass":false,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":5,"controlDropped":2,"work":6.43,"frameP95":63.9},
"nudge-hold-pct-r0-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":0,"controlDropped":1,"work":10.02,"frameP95":17.8},
"nudge-hold-pct-r0-nested-z200": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":0,"controlDropped":0,"work":7.79,"frameP95":18},
"nudge-hold-pct-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":2,"controlDropped":0,"work":6.66,"frameP95":56.71},
"nudge-hold-pct-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":10.28,"frameP95":54.4},
"nudge-hold-pct-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":2,"controlDropped":0,"work":9.31,"frameP95":54.11},
"nudge-hold-pct-r0-root-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":0,"controlDropped":1,"work":7.33,"frameP95":18.11},
"nudge-hold-pct-r30-nested-z100": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":0,"controlDropped":0,"work":7.27,"frameP95":18},
"nudge-hold-pct-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":2,"controlDropped":2,"work":8.44,"frameP95":54.6},
"nudge-hold-pct-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":1,"controlDropped":0,"work":5.93,"frameP95":31.5},
"nudge-hold-pct-r30-root-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":0,"work":7.21,"frameP95":25.6},
"nudge-hold-pct-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":1,"controlDropped":0,"work":7.52,"frameP95":31.5},
"nudge-hold-pct-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":3,"controlDropped":2,"work":6.17,"frameP95":60.11},
"nudge-hold-px-r0-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":7.87,"frameP95":56.3},
"nudge-hold-px-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":3,"controlDropped":2,"work":9.17,"frameP95":65.41},
"nudge-hold-px-r0-nested-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":2,"controlDropped":2,"work":7,"frameP95":55.3},
"nudge-hold-px-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":4,"controlDropped":3,"work":6.96,"frameP95":66.71},
"nudge-hold-px-r0-root-z200": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":1,"controlDropped":2,"work":6.98,"frameP95":38.71},
"nudge-hold-px-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":3,"controlDropped":3,"work":9.2,"frameP95":68.5},
"nudge-hold-px-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":0,"work":12.82,"frameP95":65.31},
"nudge-hold-px-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":0,"controlDropped":1,"work":8.33,"frameP95":20.8},
"nudge-hold-px-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":3,"controlDropped":1,"work":9.61,"frameP95":67.1},
"nudge-hold-px-r30-root-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":1,"work":10.11,"frameP95":62.4},
"nudge-hold-px-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":3,"controlDropped":1,"work":9.93,"frameP95":64},
"nudge-hold-px-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":1,"controlDropped":1,"work":8.15,"frameP95":25.1},
"nudge-hold-xpercent-r0-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":7.72,"frameP95":63.41},
"nudge-hold-xpercent-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":2,"controlDropped":3,"work":9.44,"frameP95":52.8},
"nudge-hold-xpercent-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":3,"controlDropped":2,"work":7.38,"frameP95":44},
"nudge-hold-xpercent-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":11.76,"frameP95":58.21},
"nudge-hold-xpercent-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":3,"controlDropped":1,"work":9.58,"frameP95":51.11},
"nudge-hold-xpercent-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":2,"controlDropped":0,"work":5.77,"frameP95":58.1},
"nudge-hold-xpercent-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":2,"work":9.91,"frameP95":62.8},
"nudge-hold-xpercent-r30-nested-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":6,"controlDropped":2,"work":13.55,"frameP95":59.61},
"nudge-hold-xpercent-r30-nested-z50": {"pass":false,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":3,"controlDropped":2,"work":8.69,"frameP95":59},
"nudge-hold-xpercent-r30-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":1,"work":10.73,"frameP95":55.8},
"nudge-hold-xpercent-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":2,"controlDropped":2,"work":8.66,"frameP95":52.21},
"nudge-hold-xpercent-r30-root-z50": {"pass":false,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":2,"controlDropped":1,"work":9.21,"frameP95":50},
"nudge-none-center-r0-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":5.01,"reload":0,"undo":true,"dropped":3,"controlDropped":1,"work":10.23,"frameP95":50.1},
"nudge-none-center-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0.03,"undo":true,"dropped":2,"controlDropped":1,"work":8.89,"frameP95":43.2},
"nudge-none-center-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.05,"undo":true,"dropped":2,"controlDropped":2,"work":6.99,"frameP95":47.91},
"nudge-none-center-r0-root-z100": {"pass":true,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":1,"work":7.43,"frameP95":41.91},
"nudge-none-center-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":4,"controlDropped":0,"work":7.8,"frameP95":59.4},
"nudge-none-center-r0-root-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":2,"controlDropped":2,"work":7.54,"frameP95":39.9},
"nudge-none-center-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":5.99,"frameP95":45.91},
"nudge-none-center-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0.04,"undo":true,"dropped":2,"controlDropped":1,"work":6.76,"frameP95":47.21},
"nudge-none-center-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.07,"undo":true,"dropped":2,"controlDropped":0,"work":6.74,"frameP95":57.61},
"nudge-none-center-r30-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":0,"work":7.39,"frameP95":39.21},
"nudge-none-center-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":3,"controlDropped":2,"work":7.34,"frameP95":56.1},
"nudge-none-center-r30-root-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":2,"controlDropped":2,"work":7.79,"frameP95":39.1},
"nudge-none-pct-r0-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":5.01,"reload":0,"undo":true,"dropped":4,"controlDropped":2,"work":9.98,"frameP95":60.41},
"nudge-none-pct-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0.02,"undo":true,"dropped":3,"controlDropped":2,"work":9.27,"frameP95":63.6},
"nudge-none-pct-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.05,"undo":true,"dropped":2,"controlDropped":0,"work":5.65,"frameP95":41.21},
"nudge-none-pct-r0-root-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":72.11,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":10.73,"frameP95":53.5},
"nudge-none-pct-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":72.12,"reload":0.02,"undo":true,"dropped":1,"controlDropped":2,"work":7.1,"frameP95":54.21},
"nudge-none-pct-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":72.16,"reload":0.07,"undo":true,"dropped":4,"controlDropped":2,"work":10.85,"frameP95":68.31},
"nudge-none-pct-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0,"undo":true,"dropped":3,"controlDropped":0,"work":6.63,"frameP95":54.4},
"nudge-none-pct-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0.06,"undo":true,"dropped":0,"controlDropped":2,"work":7.29,"frameP95":17.91},
"nudge-none-pct-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.05,"undo":true,"dropped":1,"controlDropped":1,"work":5.77,"frameP95":37.91},
"nudge-none-pct-r30-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":72.14,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":6.91,"frameP95":47.91},
"nudge-none-pct-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":72.12,"reload":0.04,"undo":true,"dropped":0,"controlDropped":2,"work":6.81,"frameP95":17.91},
"nudge-none-pct-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":72.16,"reload":0.05,"undo":true,"dropped":5,"controlDropped":2,"work":9.33,"frameP95":67.71},
"nudge-none-px-r0-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":5.01,"reload":0,"undo":true,"dropped":0,"controlDropped":0,"work":6.36,"frameP95":17.81},
"nudge-none-px-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0.04,"undo":true,"dropped":2,"controlDropped":1,"work":6.4,"frameP95":38},
"nudge-none-px-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.07,"undo":true,"dropped":0,"controlDropped":0,"work":6.06,"frameP95":17.6},
"nudge-none-px-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":49.99,"reload":0,"undo":true,"dropped":1,"controlDropped":1,"work":6.95,"frameP95":31.8},
"nudge-none-px-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":50.03,"reload":0.02,"undo":true,"dropped":2,"controlDropped":0,"work":9.65,"frameP95":50.5},
"nudge-none-px-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":50.09,"reload":0.07,"undo":true,"dropped":2,"controlDropped":0,"work":11.42,"frameP95":33.4},
"nudge-none-px-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.01,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":7.65,"frameP95":34.2},
"nudge-none-px-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.04,"reload":0.05,"undo":true,"dropped":2,"controlDropped":1,"work":7.1,"frameP95":50.8},
"nudge-none-px-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":5.06,"reload":0.07,"undo":true,"dropped":2,"controlDropped":2,"work":6.1,"frameP95":43},
"nudge-none-px-r30-root-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":50.03,"reload":0,"undo":true,"dropped":3,"controlDropped":3,"work":7.22,"frameP95":60.6},
"nudge-none-px-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":50.01,"reload":0.04,"undo":true,"dropped":0,"controlDropped":2,"work":10.58,"frameP95":17.91},
"nudge-none-px-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":50.09,"reload":0.05,"undo":true,"dropped":1,"controlDropped":1,"work":8.13,"frameP95":37.91},
"nudge-tween-center-r0-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":1,"work":8.59,"frameP95":54.21},
"nudge-tween-center-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":3,"controlDropped":3,"work":8.91,"frameP95":62.21},
"nudge-tween-center-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":2,"controlDropped":1,"work":10.65,"frameP95":60.3},
"nudge-tween-center-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":10.74,"frameP95":63.5},
"nudge-tween-center-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":0,"controlDropped":1,"work":8.52,"frameP95":19},
"nudge-tween-center-r0-root-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":0,"controlDropped":1,"work":6.9,"frameP95":17.8},
"nudge-tween-center-r30-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":5,"controlDropped":2,"work":8.49,"frameP95":62.91},
"nudge-tween-center-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":4,"controlDropped":3,"work":11.46,"frameP95":64.91},
"nudge-tween-center-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.1,"undo":true,"dropped":4,"controlDropped":2,"work":7.17,"frameP95":62},
"nudge-tween-center-r30-root-z100": {"pass":true,"tracking":0.02,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":5.69,"frameP95":57.3},
"nudge-tween-center-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":3,"controlDropped":2,"work":8.93,"frameP95":61.2},
"nudge-tween-center-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.1,"undo":true,"dropped":3,"controlDropped":2,"work":8.84,"frameP95":56.8},
"nudge-tween-pct-r0-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":4,"controlDropped":4,"work":10.85,"frameP95":67.4},
"nudge-tween-pct-r0-nested-z200": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.01,"undo":true,"dropped":0,"controlDropped":2,"work":7.32,"frameP95":17.9},
"nudge-tween-pct-r0-nested-z50": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":3,"controlDropped":3,"work":7,"frameP95":65.61},
"nudge-tween-pct-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":1,"work":6.94,"frameP95":63.2},
"nudge-tween-pct-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":4,"controlDropped":2,"work":9.04,"frameP95":67.21},
"nudge-tween-pct-r0-root-z50": {"pass":false,"tracking":0.04,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":4,"controlDropped":2,"work":7.15,"frameP95":60.61},
"nudge-tween-pct-r30-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":7.81,"frameP95":59.8},
"nudge-tween-pct-r30-nested-z200": {"pass":true,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":1,"controlDropped":1,"work":6.13,"frameP95":46},
"nudge-tween-pct-r30-nested-z50": {"pass":false,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":2,"controlDropped":0,"work":6.28,"frameP95":59.6},
"nudge-tween-pct-r30-root-z100": {"pass":true,"tracking":0.01,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":1,"work":7.35,"frameP95":26.1},
"nudge-tween-pct-r30-root-z200": {"pass":false,"tracking":0.02,"pressJump":null,"drop":0,"reload":0.03,"undo":true,"dropped":1,"controlDropped":0,"work":6.84,"frameP95":38.9},
"nudge-tween-pct-r30-root-z50": {"pass":true,"tracking":0.06,"pressJump":null,"drop":0,"reload":0.11,"undo":true,"dropped":0,"controlDropped":0,"work":6.85,"frameP95":20.71},
"nudge-tween-px-r0-nested-z100": {"pass":true,"tracking":0.5,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":7.23,"frameP95":34.21},
"nudge-tween-px-r0-nested-z200": {"pass":false,"tracking":0.51,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":2,"controlDropped":2,"work":9.64,"frameP95":37.21},
"nudge-tween-px-r0-nested-z50": {"pass":false,"tracking":0.55,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":2,"controlDropped":0,"work":11,"frameP95":34.41},
"nudge-tween-px-r0-root-z100": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":11.01,"frameP95":50.21},
"nudge-tween-px-r0-root-z200": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0.04,"undo":true,"dropped":3,"controlDropped":0,"work":6.9,"frameP95":64.6},
"nudge-tween-px-r0-root-z50": {"pass":false,"tracking":0.55,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":1,"controlDropped":0,"work":6.41,"frameP95":29},
"nudge-tween-px-r30-nested-z100": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":8.39,"frameP95":58.61},
"nudge-tween-px-r30-nested-z200": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":3,"controlDropped":2,"work":8.55,"frameP95":63.8},
"nudge-tween-px-r30-nested-z50": {"pass":true,"tracking":0.5,"pressJump":null,"drop":0,"reload":0.07,"undo":true,"dropped":0,"controlDropped":0,"work":7.09,"frameP95":18.11},
"nudge-tween-px-r30-root-z100": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":0,"work":7.1,"frameP95":37.71},
"nudge-tween-px-r30-root-z200": {"pass":false,"tracking":0.51,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":3,"controlDropped":0,"work":10.24,"frameP95":56.71},
"nudge-tween-px-r30-root-z50": {"pass":false,"tracking":0.5,"pressJump":null,"drop":0,"reload":0.05,"undo":true,"dropped":2,"controlDropped":1,"work":7.51,"frameP95":39.71},
"nudge-tween-xpercent-r0-nested-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.27,"reload":0,"undo":true,"dropped":0,"controlDropped":1,"work":7.97,"frameP95":21.5},
"nudge-tween-xpercent-r0-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.22,"reload":0.04,"undo":true,"dropped":0,"controlDropped":0,"work":8.16,"frameP95":17.4},
"nudge-tween-xpercent-r0-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.22,"reload":0.07,"undo":true,"dropped":3,"controlDropped":1,"work":8.23,"frameP95":54.3},
"nudge-tween-xpercent-r0-root-z100": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.27,"reload":0,"undo":true,"dropped":0,"controlDropped":0,"work":7.42,"frameP95":17.91},
"nudge-tween-xpercent-r0-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.22,"reload":0.04,"undo":true,"dropped":0,"controlDropped":1,"work":8.04,"frameP95":18.21},
"nudge-tween-xpercent-r0-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.22,"reload":0.07,"undo":true,"dropped":2,"controlDropped":1,"work":7.99,"frameP95":46.41},
"nudge-tween-xpercent-r30-nested-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":144.24,"reload":0,"undo":true,"dropped":4,"controlDropped":2,"work":13.2,"frameP95":60.41},
"nudge-tween-xpercent-r30-nested-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.24,"reload":0.03,"undo":true,"dropped":3,"controlDropped":3,"work":8.32,"frameP95":64.4},
"nudge-tween-xpercent-r30-nested-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.32,"reload":0.05,"undo":true,"dropped":1,"controlDropped":3,"work":5.81,"frameP95":44.31},
"nudge-tween-xpercent-r30-root-z100": {"pass":false,"tracking":0.02,"pressJump":null,"drop":144.24,"reload":0,"undo":true,"dropped":0,"controlDropped":0,"work":6.9,"frameP95":17.1},
"nudge-tween-xpercent-r30-root-z200": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.24,"reload":0.03,"undo":true,"dropped":0,"controlDropped":2,"work":6.81,"frameP95":17.81},
"nudge-tween-xpercent-r30-root-z50": {"pass":false,"tracking":0.01,"pressJump":null,"drop":144.32,"reload":0.05,"undo":true,"dropped":1,"controlDropped":1,"work":8.72,"frameP95":40.41},
"resize-hold-center-r0-nested-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":16,"controlDropped":13,"work":9.05,"frameP95":65.6},
"resize-hold-center-r0-nested-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":0.01,"undo":true,"dropped":17,"controlDropped":11,"work":9.05,"frameP95":60.71},
"resize-hold-center-r0-nested-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":20,"controlDropped":15,"work":9.32,"frameP95":70.3},
"resize-hold-center-r0-root-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":10,"controlDropped":11,"work":10.72,"frameP95":52.6},
"resize-hold-center-r0-root-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":18,"controlDropped":7,"work":9.88,"frameP95":68.8},
"resize-hold-center-r0-root-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":60.21,"undo":false,"dropped":11,"controlDropped":11,"work":10.49,"frameP95":51},
"resize-hold-center-r30-nested-z100": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":24,"controlDropped":14,"work":10.7,"frameP95":70},
"resize-hold-center-r30-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":17,"controlDropped":14,"work":8.7,"frameP95":67.5},
"resize-hold-center-r30-nested-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":28,"controlDropped":15,"work":9.4,"frameP95":75.8},
"resize-hold-center-r30-root-z100": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":19,"controlDropped":11,"work":7.57,"frameP95":73.11},
"resize-hold-center-r30-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":60.19,"undo":false,"dropped":18,"controlDropped":13,"work":8.3,"frameP95":68.1},
"resize-hold-center-r30-root-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":0,"reload":60.24,"undo":false,"dropped":18,"controlDropped":13,"work":9.53,"frameP95":61.1},
"resize-hold-pct-r0-nested-z100": {"pass":false,"tracking":0.65,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":4,"controlDropped":3,"work":7.91,"frameP95":38.2},
"resize-hold-pct-r0-nested-z200": {"pass":false,"tracking":0.67,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":13,"controlDropped":0,"work":8.11,"frameP95":59.61},
"resize-hold-pct-r0-nested-z50": {"pass":false,"tracking":0.99,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":7,"controlDropped":5,"work":9.05,"frameP95":56.1},
"resize-hold-pct-r0-root-z100": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.41,"undo":false,"dropped":11,"controlDropped":1,"work":8.35,"frameP95":53.8},
"resize-hold-pct-r0-root-z200": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.39,"undo":false,"dropped":2,"controlDropped":3,"work":10.21,"frameP95":20.4},
"resize-hold-pct-r0-root-z50": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.37,"undo":false,"dropped":8,"controlDropped":8,"work":7.68,"frameP95":51.1},
"resize-hold-pct-r30-nested-z100": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":2,"work":10.1,"frameP95":50.5},
"resize-hold-pct-r30-nested-z200": {"pass":false,"tracking":0.89,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":10,"controlDropped":8,"work":8.12,"frameP95":49.2},
"resize-hold-pct-r30-nested-z50": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":10,"controlDropped":9,"work":8.5,"frameP95":60.5},
"resize-hold-pct-r30-root-z100": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":116.27,"undo":false,"dropped":7,"controlDropped":9,"work":9.65,"frameP95":45.6},
"resize-hold-pct-r30-root-z200": {"pass":false,"tracking":0.9,"pressJump":0,"drop":0,"reload":116.29,"undo":false,"dropped":10,"controlDropped":3,"work":8.58,"frameP95":45.4},
"resize-hold-pct-r30-root-z50": {"pass":false,"tracking":0.97,"pressJump":0,"drop":0,"reload":116.27,"undo":false,"dropped":8,"controlDropped":6,"work":8.92,"frameP95":59.3},
"resize-hold-px-r0-nested-z100": {"pass":false,"tracking":0.65,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":16,"controlDropped":12,"work":8.15,"frameP95":59.5},
"resize-hold-px-r0-nested-z200": {"pass":false,"tracking":0.67,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":20,"controlDropped":11,"work":8.23,"frameP95":63.8},
"resize-hold-px-r0-nested-z50": {"pass":false,"tracking":0.99,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":16,"controlDropped":11,"work":11.86,"frameP95":70.31},
"resize-hold-px-r0-root-z100": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.41,"undo":false,"dropped":15,"controlDropped":13,"work":9.47,"frameP95":53.21},
"resize-hold-px-r0-root-z200": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.39,"undo":false,"dropped":16,"controlDropped":12,"work":9.99,"frameP95":68.91},
"resize-hold-px-r0-root-z50": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":120.37,"undo":false,"dropped":14,"controlDropped":13,"work":11.3,"frameP95":66.21},
"resize-hold-px-r30-nested-z100": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":13,"work":8.89,"frameP95":58.91},
"resize-hold-px-r30-nested-z200": {"pass":false,"tracking":0.89,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":12,"controlDropped":9,"work":8.56,"frameP95":51.3},
"resize-hold-px-r30-nested-z50": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":11,"controlDropped":9,"work":8.88,"frameP95":61.91},
"resize-hold-px-r30-root-z100": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":116.27,"undo":false,"dropped":11,"controlDropped":6,"work":9.24,"frameP95":59.1},
"resize-hold-px-r30-root-z200": {"pass":false,"tracking":0.9,"pressJump":0,"drop":0,"reload":116.29,"undo":false,"dropped":8,"controlDropped":10,"work":7.69,"frameP95":65.81},
"resize-hold-px-r30-root-z50": {"pass":false,"tracking":0.97,"pressJump":0,"drop":0,"reload":116.27,"undo":false,"dropped":15,"controlDropped":11,"work":10.29,"frameP95":69.6},
"resize-hold-xpercent-r0-nested-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":11,"work":8.8,"frameP95":65.6},
"resize-hold-xpercent-r0-nested-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":0.01,"undo":true,"dropped":10,"controlDropped":12,"work":8.88,"frameP95":49.9},
"resize-hold-xpercent-r0-nested-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":14,"controlDropped":1,"work":9.39,"frameP95":61.71},
"resize-hold-xpercent-r0-root-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":10,"controlDropped":9,"work":8.99,"frameP95":57.61},
"resize-hold-xpercent-r0-root-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":11,"controlDropped":11,"work":7.22,"frameP95":58.61},
"resize-hold-xpercent-r0-root-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":60.21,"undo":false,"dropped":14,"controlDropped":8,"work":10.36,"frameP95":54.9},
"resize-hold-xpercent-r30-nested-z100": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":19,"controlDropped":13,"work":9.8,"frameP95":68.41},
"resize-hold-xpercent-r30-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":19,"controlDropped":12,"work":8.67,"frameP95":64.9},
"resize-hold-xpercent-r30-nested-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":16,"controlDropped":13,"work":10.32,"frameP95":67.11},
"resize-hold-xpercent-r30-root-z100": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":60.2,"undo":false,"dropped":16,"controlDropped":6,"work":9.28,"frameP95":67.4},
"resize-hold-xpercent-r30-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":60.19,"undo":false,"dropped":9,"controlDropped":3,"work":7.77,"frameP95":35.71},
"resize-hold-xpercent-r30-root-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":0,"reload":60.24,"undo":false,"dropped":14,"controlDropped":10,"work":10.3,"frameP95":65.5},
"resize-none-center-r0-nested-z100": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.17,"reload":0,"undo":true,"dropped":12,"controlDropped":12,"work":9.44,"frameP95":63},
"resize-none-center-r0-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.19,"reload":0.03,"undo":true,"dropped":13,"controlDropped":15,"work":7.74,"frameP95":63.4},
"resize-none-center-r0-nested-z50": {"pass":false,"tracking":0.23,"pressJump":0,"drop":60.17,"reload":0.05,"undo":true,"dropped":14,"controlDropped":11,"work":7.71,"frameP95":61.71},
"resize-none-center-r0-root-z100": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.17,"reload":0,"undo":true,"dropped":12,"controlDropped":8,"work":7.98,"frameP95":60.8},
"resize-none-center-r0-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.19,"reload":0.03,"undo":true,"dropped":13,"controlDropped":6,"work":9.13,"frameP95":61.11},
"resize-none-center-r0-root-z50": {"pass":false,"tracking":0.23,"pressJump":0,"drop":60.17,"reload":0.05,"undo":true,"dropped":12,"controlDropped":3,"work":7.38,"frameP95":57.5},
"resize-none-center-r30-nested-z100": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.2,"reload":0,"undo":true,"dropped":10,"controlDropped":11,"work":8.1,"frameP95":58.5},
"resize-none-center-r30-nested-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":60.19,"reload":0.04,"undo":true,"dropped":7,"controlDropped":6,"work":7.16,"frameP95":42.91},
"resize-none-center-r30-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.18,"reload":0.07,"undo":true,"dropped":9,"controlDropped":5,"work":8.35,"frameP95":52.5},
"resize-none-center-r30-root-z100": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.2,"reload":0,"undo":true,"dropped":16,"controlDropped":10,"work":9.13,"frameP95":52.4},
"resize-none-center-r30-root-z200": {"pass":false,"tracking":0.23,"pressJump":0,"drop":60.19,"reload":0.04,"undo":true,"dropped":5,"controlDropped":6,"work":7.77,"frameP95":36.91},
"resize-none-center-r30-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":60.18,"reload":0.07,"undo":true,"dropped":10,"controlDropped":10,"work":8.5,"frameP95":56.4},
"resize-none-pct-r0-nested-z100": {"pass":false,"tracking":0.8,"pressJump":0,"drop":60.32,"reload":0,"undo":true,"dropped":18,"controlDropped":14,"work":8.77,"frameP95":61.21},
"resize-none-pct-r0-nested-z200": {"pass":false,"tracking":1,"pressJump":0,"drop":60.32,"reload":0.02,"undo":true,"dropped":16,"controlDropped":12,"work":9.32,"frameP95":61.11},
"resize-none-pct-r0-nested-z50": {"pass":false,"tracking":1,"pressJump":0,"drop":60.32,"reload":0.05,"undo":true,"dropped":5,"controlDropped":7,"work":7.94,"frameP95":47.8},
"resize-none-pct-r0-root-z100": {"pass":false,"tracking":0.97,"pressJump":0,"drop":222.56,"reload":0,"undo":true,"dropped":14,"controlDropped":5,"work":9.26,"frameP95":64.61},
"resize-none-pct-r0-root-z200": {"pass":false,"tracking":0.96,"pressJump":0,"drop":222.59,"reload":0.03,"undo":true,"dropped":8,"controlDropped":11,"work":8.32,"frameP95":52},
"resize-none-pct-r0-root-z50": {"pass":false,"tracking":0.99,"pressJump":0,"drop":222.61,"reload":0.07,"undo":true,"dropped":9,"controlDropped":7,"work":10.83,"frameP95":48.91},
"resize-none-pct-r30-nested-z100": {"pass":false,"tracking":0.94,"pressJump":0,"drop":60.46,"reload":0,"undo":true,"dropped":10,"controlDropped":2,"work":8.61,"frameP95":54.21},
"resize-none-pct-r30-nested-z200": {"pass":false,"tracking":0.91,"pressJump":0,"drop":60.41,"reload":0.06,"undo":true,"dropped":12,"controlDropped":10,"work":8.62,"frameP95":56.5},
"resize-none-pct-r30-nested-z50": {"pass":false,"tracking":0.94,"pressJump":0,"drop":60.46,"reload":0.05,"undo":true,"dropped":8,"controlDropped":5,"work":7.63,"frameP95":51.8},
"resize-none-pct-r30-root-z100": {"pass":false,"tracking":0.94,"pressJump":0,"drop":216.64,"reload":0,"undo":true,"dropped":21,"controlDropped":11,"work":8.17,"frameP95":68.71},
"resize-none-pct-r30-root-z200": {"pass":false,"tracking":0.89,"pressJump":0,"drop":216.58,"reload":0.05,"undo":true,"dropped":11,"controlDropped":10,"work":8.05,"frameP95":52.8},
"resize-none-pct-r30-root-z50": {"pass":false,"tracking":0.94,"pressJump":0,"drop":216.54,"reload":0.11,"undo":true,"dropped":15,"controlDropped":8,"work":8.19,"frameP95":62.8},
"resize-none-px-r0-nested-z100": {"pass":false,"tracking":0.89,"pressJump":0,"drop":60.45,"reload":0,"undo":true,"dropped":5,"controlDropped":0,"work":7.9,"frameP95":48.5},
"resize-none-px-r0-nested-z200": {"pass":false,"tracking":0.67,"pressJump":0,"drop":60.46,"reload":0.04,"undo":true,"dropped":13,"controlDropped":13,"work":9.41,"frameP95":55.8},
"resize-none-px-r0-nested-z50": {"pass":false,"tracking":0.89,"pressJump":0,"drop":60.48,"reload":0.07,"undo":true,"dropped":1,"controlDropped":0,"work":6.85,"frameP95":19.1},
"resize-none-px-r0-root-z100": {"pass":false,"tracking":0.92,"pressJump":0,"drop":170.31,"reload":0,"undo":true,"dropped":8,"controlDropped":5,"work":9,"frameP95":50.21},
"resize-none-px-r0-root-z200": {"pass":false,"tracking":0.9,"pressJump":0,"drop":170.32,"reload":0.03,"undo":true,"dropped":3,"controlDropped":4,"work":9.55,"frameP95":30.41},
"resize-none-px-r0-root-z50": {"pass":false,"tracking":0.83,"pressJump":0,"drop":170.3,"reload":0.05,"undo":true,"dropped":6,"controlDropped":0,"work":10.09,"frameP95":30.71},
"resize-none-px-r30-nested-z100": {"pass":false,"tracking":0.89,"pressJump":0,"drop":60.62,"reload":0,"undo":true,"dropped":13,"controlDropped":9,"work":9.19,"frameP95":64.4},
"resize-none-px-r30-nested-z200": {"pass":false,"tracking":0.88,"pressJump":0,"drop":60.66,"reload":0.05,"undo":true,"dropped":14,"controlDropped":0,"work":8.95,"frameP95":51.71},
"resize-none-px-r30-nested-z50": {"pass":false,"tracking":0.89,"pressJump":0,"drop":60.62,"reload":0.07,"undo":true,"dropped":14,"controlDropped":10,"work":8.11,"frameP95":62},
"resize-none-px-r30-root-z100": {"pass":false,"tracking":0.92,"pressJump":0,"drop":165.53,"reload":0,"undo":true,"dropped":10,"controlDropped":7,"work":8.1,"frameP95":58.61},
"resize-none-px-r30-root-z200": {"pass":false,"tracking":0.89,"pressJump":0,"drop":165.51,"reload":0.06,"undo":true,"dropped":12,"controlDropped":2,"work":9.68,"frameP95":58.11},
"resize-none-px-r30-root-z50": {"pass":false,"tracking":0.93,"pressJump":0,"drop":165.59,"reload":0.1,"undo":true,"dropped":10,"controlDropped":5,"work":9.07,"frameP95":54.71},
"resize-tween-center-r0-nested-z100": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":16,"controlDropped":12,"work":9.2,"frameP95":64.21},
"resize-tween-center-r0-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":17,"controlDropped":11,"work":11.44,"frameP95":62.11},
"resize-tween-center-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":14,"controlDropped":3,"work":9.62,"frameP95":57},
"resize-tween-center-r0-root-z100": {"pass":false,"tracking":0.27,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":18,"controlDropped":2,"work":9.21,"frameP95":65.21},
"resize-tween-center-r0-root-z200": {"pass":true,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":10,"controlDropped":11,"work":7.85,"frameP95":50.21},
"resize-tween-center-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":5,"work":8.54,"frameP95":46.61},
"resize-tween-center-r30-nested-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":11,"work":10.58,"frameP95":62.5},
"resize-tween-center-r30-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":23,"controlDropped":11,"work":8.9,"frameP95":66.3},
"resize-tween-center-r30-nested-z50": {"pass":false,"tracking":0.38,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":18,"controlDropped":11,"work":8.62,"frameP95":62.91},
"resize-tween-center-r30-root-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":15,"controlDropped":9,"work":8.14,"frameP95":59.61},
"resize-tween-center-r30-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":13,"controlDropped":12,"work":9.62,"frameP95":59.1},
"resize-tween-center-r30-root-z50": {"pass":false,"tracking":0.38,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":16,"controlDropped":11,"work":9.45,"frameP95":66.31},
"resize-tween-pct-r0-nested-z100": {"pass":false,"tracking":0.92,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":17,"controlDropped":11,"work":8.5,"frameP95":66.61},
"resize-tween-pct-r0-nested-z200": {"pass":false,"tracking":0.84,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":21,"controlDropped":11,"work":9.78,"frameP95":71.71},
"resize-tween-pct-r0-nested-z50": {"pass":false,"tracking":0.76,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":18,"controlDropped":11,"work":11.23,"frameP95":73.3},
"resize-tween-pct-r0-root-z100": {"pass":false,"tracking":0.86,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":20,"controlDropped":12,"work":8.62,"frameP95":68},
"resize-tween-pct-r0-root-z200": {"pass":false,"tracking":0.84,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":16,"controlDropped":13,"work":8.35,"frameP95":64.5},
"resize-tween-pct-r0-root-z50": {"pass":false,"tracking":0.88,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":20,"controlDropped":13,"work":9.4,"frameP95":68},
"resize-tween-pct-r30-nested-z100": {"pass":false,"tracking":0.9,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":3,"work":9.02,"frameP95":57.6},
"resize-tween-pct-r30-nested-z200": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":13,"controlDropped":7,"work":8.72,"frameP95":61.9},
"resize-tween-pct-r30-nested-z50": {"pass":false,"tracking":1,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":6,"controlDropped":2,"work":7.93,"frameP95":42.5},
"resize-tween-pct-r30-root-z100": {"pass":false,"tracking":0.89,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":2,"work":10.04,"frameP95":53.21},
"resize-tween-pct-r30-root-z200": {"pass":false,"tracking":0.91,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":12,"controlDropped":2,"work":8.26,"frameP95":57.5},
"resize-tween-pct-r30-root-z50": {"pass":false,"tracking":0.93,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":10,"work":9.08,"frameP95":38.9},
"resize-tween-px-r0-nested-z100": {"pass":false,"tracking":0.74,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":4,"work":8.99,"frameP95":48.91},
"resize-tween-px-r0-nested-z200": {"pass":false,"tracking":0.71,"pressJump":0,"drop":0,"reload":0.02,"undo":true,"dropped":11,"controlDropped":5,"work":9.21,"frameP95":53.5},
"resize-tween-px-r0-nested-z50": {"pass":false,"tracking":0.73,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":13,"controlDropped":4,"work":8.97,"frameP95":51.41},
"resize-tween-px-r0-root-z100": {"pass":false,"tracking":0.75,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":0,"work":8.68,"frameP95":62},
"resize-tween-px-r0-root-z200": {"pass":false,"tracking":0.76,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":9,"controlDropped":6,"work":7.84,"frameP95":49.4},
"resize-tween-px-r0-root-z50": {"pass":false,"tracking":0.73,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":5,"controlDropped":8,"work":8.52,"frameP95":43.61},
"resize-tween-px-r30-nested-z100": {"pass":false,"tracking":0.76,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":4,"controlDropped":9,"work":9.04,"frameP95":39.8},
"resize-tween-px-r30-nested-z200": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":15,"controlDropped":12,"work":8.33,"frameP95":62.6},
"resize-tween-px-r30-nested-z50": {"pass":false,"tracking":0.78,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":11,"controlDropped":5,"work":7.9,"frameP95":55.71},
"resize-tween-px-r30-root-z100": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":4,"work":8.37,"frameP95":52.9},
"resize-tween-px-r30-root-z200": {"pass":false,"tracking":0.69,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":6,"controlDropped":0,"work":7.45,"frameP95":53.1},
"resize-tween-px-r30-root-z50": {"pass":false,"tracking":0.72,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":11,"controlDropped":4,"work":9.73,"frameP95":55.4},
"resize-tween-xpercent-r0-nested-z100": {"pass":false,"tracking":0.27,"pressJump":0,"drop":204.41,"reload":0,"undo":true,"dropped":4,"controlDropped":0,"work":8.81,"frameP95":35.9},
"resize-tween-xpercent-r0-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":11,"controlDropped":7,"work":9.64,"frameP95":55.61},
"resize-tween-xpercent-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":204.44,"reload":0.07,"undo":true,"dropped":10,"controlDropped":3,"work":8.56,"frameP95":53.11},
"resize-tween-xpercent-r0-root-z100": {"pass":false,"tracking":0.27,"pressJump":0,"drop":204.41,"reload":0,"undo":true,"dropped":11,"controlDropped":1,"work":10.12,"frameP95":51},
"resize-tween-xpercent-r0-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":11,"controlDropped":6,"work":9.49,"frameP95":53},
"resize-tween-xpercent-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":204.44,"reload":0.07,"undo":true,"dropped":13,"controlDropped":10,"work":9.43,"frameP95":63.6},
"resize-tween-xpercent-r30-nested-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":204.44,"reload":0,"undo":true,"dropped":16,"controlDropped":7,"work":8.18,"frameP95":64.2},
"resize-tween-xpercent-r30-nested-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":204.4,"reload":0.04,"undo":true,"dropped":15,"controlDropped":12,"work":11.5,"frameP95":65.11},
"resize-tween-xpercent-r30-nested-z50": {"pass":false,"tracking":0.38,"pressJump":0,"drop":204.44,"reload":0.07,"undo":true,"dropped":12,"controlDropped":8,"work":8.83,"frameP95":58.91},
"resize-tween-xpercent-r30-root-z100": {"pass":false,"tracking":0.26,"pressJump":0,"drop":204.44,"reload":0,"undo":true,"dropped":6,"controlDropped":7,"work":7.05,"frameP95":40.7},
"resize-tween-xpercent-r30-root-z200": {"pass":false,"tracking":0.24,"pressJump":0,"drop":204.4,"reload":0.04,"undo":true,"dropped":9,"controlDropped":8,"work":9.52,"frameP95":56.91},
"resize-tween-xpercent-r30-root-z50": {"pass":false,"tracking":0.38,"pressJump":0,"drop":204.44,"reload":0.07,"undo":true,"dropped":6,"controlDropped":4,"work":7.76,"frameP95":54.41},
"rotate-hold-center-r0-nested-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":15,"controlDropped":13,"work":5.63,"frameP95":58.31},
"rotate-hold-center-r0-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":12,"controlDropped":12,"work":5.47,"frameP95":61.3},
"rotate-hold-center-r0-nested-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":12,"controlDropped":11,"work":7.03,"frameP95":57.3},
"rotate-hold-center-r0-root-z100": {"pass":true,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":6,"work":4.07,"frameP95":19.2},
"rotate-hold-center-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":14,"controlDropped":12,"work":6.18,"frameP95":55.91},
"rotate-hold-center-r0-root-z50": {"pass":true,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":8,"controlDropped":10,"work":5.4,"frameP95":49.4},
"rotate-hold-center-r30-nested-z100": {"pass":false,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":17,"controlDropped":13,"work":5.6,"frameP95":68.8},
"rotate-hold-center-r30-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":11,"controlDropped":11,"work":5.3,"frameP95":57.9},
"rotate-hold-center-r30-nested-z50": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":21,"controlDropped":17,"work":6.22,"frameP95":68.9},
"rotate-hold-center-r30-root-z100": {"pass":false,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":15,"controlDropped":13,"work":5.62,"frameP95":63.61},
"rotate-hold-center-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":17,"controlDropped":15,"work":5.12,"frameP95":66.4},
"rotate-hold-center-r30-root-z50": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":15,"controlDropped":12,"work":6.01,"frameP95":64.2},
"rotate-hold-pct-r0-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":6,"controlDropped":3,"work":4.54,"frameP95":42.1},
"rotate-hold-pct-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":10,"controlDropped":2,"work":6.06,"frameP95":57.8},
"rotate-hold-pct-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":6,"controlDropped":0,"work":4.5,"frameP95":38.5},
"rotate-hold-pct-r0-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":6,"controlDropped":5,"work":4.45,"frameP95":53.8},
"rotate-hold-pct-r0-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.08,"undo":true,"dropped":2,"controlDropped":6,"work":4.15,"frameP95":21.5},
"rotate-hold-pct-r0-root-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":4,"controlDropped":0,"work":4.28,"frameP95":34.3},
"rotate-hold-pct-r30-nested-z100": {"pass":true,"tracking":0.13,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":2,"work":3.87,"frameP95":18.1},
"rotate-hold-pct-r30-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":10,"controlDropped":11,"work":5.41,"frameP95":63.71},
"rotate-hold-pct-r30-nested-z50": {"pass":false,"tracking":0.29,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":2,"work":5.25,"frameP95":46.91},
"rotate-hold-pct-r30-root-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":5,"work":3.85,"frameP95":46.91},
"rotate-hold-pct-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":9,"controlDropped":3,"work":5.15,"frameP95":60},
"rotate-hold-pct-r30-root-z50": {"pass":false,"tracking":0.23,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":5,"work":6.15,"frameP95":60.91},
"rotate-hold-px-r0-nested-z100": {"pass":true,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":11,"work":5.43,"frameP95":58.41},
"rotate-hold-px-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":12,"controlDropped":11,"work":5.84,"frameP95":60.7},
"rotate-hold-px-r0-nested-z50": {"pass":true,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":9,"controlDropped":13,"work":5.31,"frameP95":54},
"rotate-hold-px-r0-root-z100": {"pass":true,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":13,"work":5.33,"frameP95":53.91},
"rotate-hold-px-r0-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.08,"undo":true,"dropped":14,"controlDropped":14,"work":5.79,"frameP95":68.61},
"rotate-hold-px-r0-root-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":18,"controlDropped":14,"work":5.44,"frameP95":68},
"rotate-hold-px-r30-nested-z100": {"pass":true,"tracking":0.13,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":12,"work":5.71,"frameP95":52.41},
"rotate-hold-px-r30-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":7,"controlDropped":8,"work":4.51,"frameP95":48.91},
"rotate-hold-px-r30-nested-z50": {"pass":false,"tracking":0.29,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":2,"work":4.02,"frameP95":49.9},
"rotate-hold-px-r30-root-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":9,"controlDropped":8,"work":6.03,"frameP95":57.3},
"rotate-hold-px-r30-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":0,"controlDropped":11,"work":5.78,"frameP95":20.7},
"rotate-hold-px-r30-root-z50": {"pass":true,"tracking":0.23,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":11,"work":5.06,"frameP95":46.11},
"rotate-hold-xpercent-r0-nested-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":11,"work":4.84,"frameP95":51.31},
"rotate-hold-xpercent-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":11,"controlDropped":3,"work":5.1,"frameP95":63.21},
"rotate-hold-xpercent-r0-nested-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":9,"controlDropped":8,"work":5.19,"frameP95":61},
"rotate-hold-xpercent-r0-root-z100": {"pass":true,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":9,"controlDropped":12,"work":5.04,"frameP95":58.8},
"rotate-hold-xpercent-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":6,"controlDropped":2,"work":4.7,"frameP95":41.7},
"rotate-hold-xpercent-r0-root-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":13,"controlDropped":5,"work":6.38,"frameP95":56.91},
"rotate-hold-xpercent-r30-nested-z100": {"pass":true,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":15,"controlDropped":15,"work":7.12,"frameP95":70.91},
"rotate-hold-xpercent-r30-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":14,"controlDropped":12,"work":6.04,"frameP95":64.31},
"rotate-hold-xpercent-r30-nested-z50": {"pass":true,"tracking":0.26,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":13,"controlDropped":13,"work":5.9,"frameP95":60},
"rotate-hold-xpercent-r30-root-z100": {"pass":true,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":15,"work":6.54,"frameP95":68},
"rotate-hold-xpercent-r30-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":11,"controlDropped":17,"work":4.5,"frameP95":54.5},
"rotate-hold-xpercent-r30-root-z50": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":15,"controlDropped":12,"work":6.2,"frameP95":65.21},
"rotate-none-center-r0-nested-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":62.46,"reload":0,"undo":true,"dropped":14,"controlDropped":12,"work":7.2,"frameP95":65.1},
"rotate-none-center-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":62.44,"reload":0.03,"undo":true,"dropped":12,"controlDropped":10,"work":6.01,"frameP95":63.3},
"rotate-none-center-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":62.43,"reload":0.05,"undo":true,"dropped":12,"controlDropped":10,"work":6.33,"frameP95":60.41},
"rotate-none-center-r0-root-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":9,"controlDropped":8,"work":5.58,"frameP95":56.6},
"rotate-none-center-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":11,"controlDropped":10,"work":5.38,"frameP95":59.9},
"rotate-none-center-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":9,"controlDropped":3,"work":4.18,"frameP95":56.21},
"rotate-none-center-r30-nested-z100": {"pass":false,"tracking":0.14,"pressJump":0,"drop":62.46,"reload":0,"undo":true,"dropped":6,"controlDropped":9,"work":5.3,"frameP95":55.91},
"rotate-none-center-r30-nested-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":62.43,"reload":0.04,"undo":true,"dropped":4,"controlDropped":6,"work":4.46,"frameP95":42.5},
"rotate-none-center-r30-nested-z50": {"pass":false,"tracking":0.28,"pressJump":0,"drop":62.47,"reload":0.07,"undo":true,"dropped":4,"controlDropped":1,"work":4.86,"frameP95":39.5},
"rotate-none-center-r30-root-z100": {"pass":false,"tracking":0.14,"pressJump":0,"drop":74.67,"reload":0,"undo":true,"dropped":11,"controlDropped":3,"work":5.28,"frameP95":54.5},
"rotate-none-center-r30-root-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":74.66,"reload":0.03,"undo":true,"dropped":4,"controlDropped":5,"work":7,"frameP95":37.8},
"rotate-none-center-r30-root-z50": {"pass":false,"tracking":0.28,"pressJump":0,"drop":74.73,"reload":0.07,"undo":true,"dropped":12,"controlDropped":12,"work":6.5,"frameP95":52.31},
"rotate-none-pct-r0-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":62.43,"reload":0,"undo":true,"dropped":12,"controlDropped":11,"work":5.51,"frameP95":64},
"rotate-none-pct-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":62.44,"reload":0.02,"undo":true,"dropped":14,"controlDropped":12,"work":5.01,"frameP95":64.11},
"rotate-none-pct-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":62.49,"reload":0.05,"undo":true,"dropped":11,"controlDropped":11,"work":5.06,"frameP95":57.9},
"rotate-none-pct-r0-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":11,"work":5.44,"frameP95":56.61},
"rotate-none-pct-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":11,"controlDropped":6,"work":6.01,"frameP95":54.91},
"rotate-none-pct-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":14,"controlDropped":7,"work":6.35,"frameP95":67.5},
"rotate-none-pct-r30-nested-z100": {"pass":false,"tracking":0.14,"pressJump":0,"drop":62.47,"reload":0,"undo":true,"dropped":8,"controlDropped":0,"work":5.23,"frameP95":51.7},
"rotate-none-pct-r30-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":62.44,"reload":0.06,"undo":true,"dropped":0,"controlDropped":9,"work":6.07,"frameP95":21.41},
"rotate-none-pct-r30-nested-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":62.45,"reload":0.05,"undo":true,"dropped":6,"controlDropped":4,"work":4.92,"frameP95":46.6},
"rotate-none-pct-r30-root-z100": {"pass":false,"tracking":0.17,"pressJump":0,"drop":74.71,"reload":0,"undo":true,"dropped":14,"controlDropped":12,"work":4.55,"frameP95":65.31},
"rotate-none-pct-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":74.66,"reload":0.03,"undo":true,"dropped":5,"controlDropped":9,"work":4.26,"frameP95":47.41},
"rotate-none-pct-r30-root-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":74.77,"reload":0.05,"undo":true,"dropped":15,"controlDropped":10,"work":5.5,"frameP95":59.11},
"rotate-none-px-r0-nested-z100": {"pass":false,"tracking":0.16,"pressJump":0,"drop":62.43,"reload":0,"undo":true,"dropped":0,"controlDropped":0,"work":5.5,"frameP95":17.8},
"rotate-none-px-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":62.44,"reload":0.04,"undo":true,"dropped":3,"controlDropped":10,"work":4.13,"frameP95":38.7},
"rotate-none-px-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":62.43,"reload":0.07,"undo":true,"dropped":0,"controlDropped":5,"work":4.32,"frameP95":17.8},
"rotate-none-px-r0-root-z100": {"pass":true,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":7,"controlDropped":8,"work":6.24,"frameP95":48.21},
"rotate-none-px-r0-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.08,"undo":true,"dropped":4,"controlDropped":6,"work":4.29,"frameP95":32.41},
"rotate-none-px-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":5,"controlDropped":0,"work":4.93,"frameP95":29},
"rotate-none-px-r30-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":62.45,"reload":0,"undo":true,"dropped":4,"controlDropped":13,"work":3.9,"frameP95":46.6},
"rotate-none-px-r30-nested-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":62.43,"reload":0.05,"undo":true,"dropped":9,"controlDropped":4,"work":5.14,"frameP95":45.8},
"rotate-none-px-r30-nested-z50": {"pass":false,"tracking":0.27,"pressJump":0,"drop":62.47,"reload":0.07,"undo":true,"dropped":8,"controlDropped":0,"work":4.71,"frameP95":59.71},
"rotate-none-px-r30-root-z100": {"pass":false,"tracking":0.13,"pressJump":0,"drop":74.68,"reload":0,"undo":true,"dropped":10,"controlDropped":6,"work":4.94,"frameP95":56.3},
"rotate-none-px-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":74.71,"reload":0.08,"undo":true,"dropped":5,"controlDropped":9,"work":4.66,"frameP95":45.8},
"rotate-none-px-r30-root-z50": {"pass":false,"tracking":0.26,"pressJump":0,"drop":74.65,"reload":0.05,"undo":true,"dropped":5,"controlDropped":9,"work":4.96,"frameP95":53.3},
"rotate-tween-center-r0-nested-z100": {"pass":true,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":11,"controlDropped":12,"work":6.08,"frameP95":53},
"rotate-tween-center-r0-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":11,"controlDropped":11,"work":5.7,"frameP95":52.21},
"rotate-tween-center-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":13,"controlDropped":6,"work":4.94,"frameP95":52.1},
"rotate-tween-center-r0-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":10,"work":4.98,"frameP95":48.91},
"rotate-tween-center-r0-root-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":4,"controlDropped":7,"work":4.46,"frameP95":33.11},
"rotate-tween-center-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":7,"controlDropped":5,"work":4.62,"frameP95":46.5},
"rotate-tween-center-r30-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":12,"work":4.93,"frameP95":63.8},
"rotate-tween-center-r30-nested-z200": {"pass":true,"tracking":0.12,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":13,"controlDropped":15,"work":4.89,"frameP95":65.3},
"rotate-tween-center-r30-nested-z50": {"pass":true,"tracking":0.3,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":11,"controlDropped":11,"work":4.44,"frameP95":62.1},
"rotate-tween-center-r30-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":7,"work":5.54,"frameP95":56},
"rotate-tween-center-r30-root-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":13,"controlDropped":12,"work":5.5,"frameP95":64.2},
"rotate-tween-center-r30-root-z50": {"pass":false,"tracking":0.3,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":13,"controlDropped":10,"work":4.9,"frameP95":59.91},
"rotate-tween-pct-r0-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":13,"controlDropped":11,"work":6.07,"frameP95":58.9},
"rotate-tween-pct-r0-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":13,"controlDropped":13,"work":6.5,"frameP95":55.1},
"rotate-tween-pct-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":14,"controlDropped":13,"work":6.72,"frameP95":64.71},
"rotate-tween-pct-r0-root-z100": {"pass":true,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":14,"controlDropped":15,"work":5.91,"frameP95":63},
"rotate-tween-pct-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":14,"controlDropped":11,"work":5.86,"frameP95":67.5},
"rotate-tween-pct-r0-root-z50": {"pass":false,"tracking":0.25,"pressJump":0,"drop":0,"reload":0.1,"undo":true,"dropped":16,"controlDropped":14,"work":5.31,"frameP95":65.3},
"rotate-tween-pct-r30-nested-z100": {"pass":true,"tracking":0.14,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":1,"controlDropped":6,"work":4.32,"frameP95":18.5},
"rotate-tween-pct-r30-nested-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":0,"reload":0.06,"undo":true,"dropped":10,"controlDropped":5,"work":6.39,"frameP95":61},
"rotate-tween-pct-r30-nested-z50": {"pass":false,"tracking":0.26,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":3,"controlDropped":0,"work":4.16,"frameP95":25.11},
"rotate-tween-pct-r30-root-z100": {"pass":false,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":8,"controlDropped":6,"work":3.87,"frameP95":59.71},
"rotate-tween-pct-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":10,"controlDropped":2,"work":4.3,"frameP95":56.21},
"rotate-tween-pct-r30-root-z50": {"pass":true,"tracking":0.28,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":0,"controlDropped":0,"work":4.43,"frameP95":22.1},
"rotate-tween-px-r0-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":7,"controlDropped":4,"work":5.67,"frameP95":49.6},
"rotate-tween-px-r0-nested-z200": {"pass":true,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.04,"undo":true,"dropped":5,"controlDropped":6,"work":6.45,"frameP95":52.8},
"rotate-tween-px-r0-nested-z50": {"pass":true,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":0,"controlDropped":11,"work":4.59,"frameP95":18.3},
"rotate-tween-px-r0-root-z100": {"pass":true,"tracking":0.16,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":7,"controlDropped":9,"work":5.28,"frameP95":31.21},
"rotate-tween-px-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.02,"undo":true,"dropped":10,"controlDropped":1,"work":4.38,"frameP95":47.8},
"rotate-tween-px-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.05,"undo":true,"dropped":7,"controlDropped":4,"work":3.65,"frameP95":44.1},
"rotate-tween-px-r30-nested-z100": {"pass":true,"tracking":0.17,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":3,"controlDropped":7,"work":4.29,"frameP95":25.6},
"rotate-tween-px-r30-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":11,"controlDropped":10,"work":6,"frameP95":60.4},
"rotate-tween-px-r30-nested-z50": {"pass":true,"tracking":0.27,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":6,"controlDropped":7,"work":6.19,"frameP95":54.71},
"rotate-tween-px-r30-root-z100": {"pass":false,"tracking":0.14,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":4,"controlDropped":2,"work":3.84,"frameP95":36.5},
"rotate-tween-px-r30-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.08,"undo":true,"dropped":7,"controlDropped":3,"work":3.77,"frameP95":55.91},
"rotate-tween-px-r30-root-z50": {"pass":false,"tracking":0.31,"pressJump":0,"drop":0,"reload":0.11,"undo":true,"dropped":9,"controlDropped":2,"work":5.11,"frameP95":52.21},
"rotate-tween-xpercent-r0-nested-z100": {"pass":true,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":5,"controlDropped":5,"work":4.72,"frameP95":52.5},
"rotate-tween-xpercent-r0-nested-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":4,"work":4.59,"frameP95":39.7},
"rotate-tween-xpercent-r0-nested-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":4,"controlDropped":2,"work":7.08,"frameP95":36.1},
"rotate-tween-xpercent-r0-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":10,"controlDropped":0,"work":4.29,"frameP95":50.71},
"rotate-tween-xpercent-r0-root-z200": {"pass":false,"tracking":0.11,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":8,"controlDropped":7,"work":6.12,"frameP95":53.5},
"rotate-tween-xpercent-r0-root-z50": {"pass":false,"tracking":0.24,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":6,"controlDropped":5,"work":4.28,"frameP95":48},
"rotate-tween-xpercent-r30-nested-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":12,"controlDropped":11,"work":6.33,"frameP95":62.91},
"rotate-tween-xpercent-r30-nested-z200": {"pass":false,"tracking":0.12,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":16,"controlDropped":14,"work":6.19,"frameP95":66.91},
"rotate-tween-xpercent-r30-nested-z50": {"pass":false,"tracking":0.3,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":10,"controlDropped":8,"work":5.44,"frameP95":61},
"rotate-tween-xpercent-r30-root-z100": {"pass":false,"tracking":0.15,"pressJump":0,"drop":0,"reload":0,"undo":true,"dropped":2,"controlDropped":0,"work":4.89,"frameP95":23},
"rotate-tween-xpercent-r30-root-z200": {"pass":true,"tracking":0.12,"pressJump":0,"drop":0,"reload":0.03,"undo":true,"dropped":9,"controlDropped":12,"work":5.69,"frameP95":57.91},
"rotate-tween-xpercent-r30-root-z50": {"pass":false,"tracking":0.3,"pressJump":0,"drop":0,"reload":0.07,"undo":true,"dropped":5,"controlDropped":4,"work":5.37,"frameP95":41.61}
}
}
@@ -0,0 +1,704 @@
/** Drives one edit accuracy case in the built Studio and measures it. All distances are composition px. */
import { spawn } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { COMPOSITION, PLAYHEAD } from "./grid.mjs";
import {
angleOf,
centre,
compositionMapper,
dist,
localToQuad,
mid,
normalizeAngle,
parseInset,
percentile,
quadDistance,
quadToLocal,
toPoints,
visibleQuad,
} from "./geometry.mjs";
const VIEWPORT = { width: 1600, height: 900 };
const STEPS = 20;
const MOVE_BY = [90, 60];
const RESIZE_BY = 60;
const ROTATE_BY = (25 * Math.PI) / 180;
const CROP_BY = 40;
const NUDGES = 5;
const ZOOM_SENSITIVITY = 0.007; // previewZoom.ts: one wheel unit scales zoom by exp(0.007)
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const up = (port) =>
fetch(`http://127.0.0.1:${port}/api/projects`).then(
(r) => r.ok,
() => false,
);
const liveServers = new Set();
/** Signals the server's process group; a group that already exited is not an error. */
function signalGroup(child, signal) {
try {
process.kill(-child.pid, signal);
} catch (error) {
if (error.code !== "ESRCH") throw error;
}
}
/** Signal-safe cleanup: servers run in their own process group so the CLI's children go with them. */
export function killServers() {
for (const child of liveServers) signalGroup(child, "SIGKILL");
}
const announcedPort = (log) => /http:\/\/localhost:(\d+)/.exec(log.join(""))?.[1];
// fallow-ignore-next-line complexity
export async function startServer(cli, dir, port, log, home) {
// The CLI quietly takes the next free port when asked for a busy one, so only the port it announces counts.
if (await up(port)) throw new Error(`port ${port} is already serving`);
const child = spawn(
"node",
[cli, "preview", dir, "--port", String(port), "--no-open", "--foreground", "--force-new"],
{
stdio: ["ignore", "pipe", "pipe"],
detached: true,
// A per-case HOME keeps Studio's undo history inside the case's tmp dir.
env: {
...process.env,
HOME: home,
HYPERFRAMES_NO_TELEMETRY: "1",
HYPERFRAMES_NO_UPDATE_CHECK: "1",
},
},
);
liveServers.add(child);
child.once("exit", () => liveServers.delete(child));
child.stdout.on("data", (d) => log.push(String(d)));
child.stderr.on("data", (d) => log.push(String(d)));
for (const deadline = Date.now() + 60_000; Date.now() < deadline; await sleep(200)) {
if (child.exitCode !== null)
throw new Error(`studio exited ${child.exitCode}: ${log.join("").slice(-500)}`);
const announced = announcedPort(log);
if (announced && announced !== String(port)) {
await stopServer(child);
throw new Error(`studio moved from port ${port} to ${announced}`);
}
if (announced && (await up(port))) return child;
}
await stopServer(child);
throw new Error("studio did not start in 60s");
}
export async function stopServer(child) {
if (child.exitCode !== null) return;
const exited = new Promise((r) => child.once("exit", r));
signalGroup(child, "SIGTERM");
if (await Promise.race([exited.then(() => true), sleep(5000)])) return;
signalGroup(child, "SIGKILL");
await exited;
}
/** Runs in the top frame before Studio: the WebMCP host plus a frame-interval and long-task recorder. */
function instrumentPage() {
if (window.top !== window) return;
const tools = new Map();
Object.defineProperty(document, "modelContext", {
configurable: true,
value: { registerTool: async (tool) => void tools.set(tool.name, tool) },
});
const rec = { on: false, frames: [], long: [] };
const call = (name, input) =>
tools.get(name).execute(input, { signal: new AbortController().signal });
window.__editBench = { has: (name) => tools.has(name), call, rec };
// The callback's own clock: Chrome stamps a late frame with the vsync it missed, which hides a stall.
const loop = () => {
if (rec.on) rec.frames.push(performance.now());
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
new PerformanceObserver((list) => {
if (rec.on) for (const e of list.getEntries()) rec.long.push(e.duration);
}).observe({ type: "longtask" });
}
const nextFrame = (page, n = 1) =>
page.evaluate(
(count) =>
new Promise((r) => {
const tick = (left) => (left ? requestAnimationFrame(() => tick(left - 1)) : r());
tick(count);
}),
n,
);
function readFiles(dir, files) {
return Object.fromEntries(files.map((f) => [f, readFileSync(join(dir, f), "utf8")]));
}
const sameFiles = (a, b) => Object.keys(a).every((f) => a[f] === b[f]);
/** Waits until the files differ from `from` (or equal `want`, or just exist) and then hold still for 300 ms. */
// fallow-ignore-next-line complexity
async function waitForFiles(ctx, { from, want, timeout = 5000 }) {
const deadline = Date.now() + timeout;
let last = readFiles(ctx.dir, ctx.files);
let stableSince = Date.now();
for (; Date.now() < deadline; await sleep(50)) {
const now = readFiles(ctx.dir, ctx.files);
if (!sameFiles(now, last)) [last, stableSince] = [now, Date.now()];
const reached = want ? sameFiles(now, want) : !from || !sameFiles(now, from);
if (reached && Date.now() - stableSince >= 300) return { reached: true, files: now };
}
return { reached: false, files: last };
}
// fallow-ignore-next-line complexity
async function previewCandidate(frame) {
const target = await frame.$("#target");
const box = target && (await (await frame.frameElement())?.boundingBox());
return box && { area: box.width * box.height, frame, target };
}
/** The largest visible preview iframe holding the target; a frame Studio detaches mid-scan is skipped. */
async function findTarget(page) {
const previews = page.frames().filter((f) => f.url().includes("/preview"));
const found = await Promise.all(previews.map((f) => previewCandidate(f).catch(() => null)));
return found.filter(Boolean).reduce((a, b) => (!a || b.area > a.area ? b : a), null);
}
// The handle's own session: remote object ids do not resolve in any other CDP session.
async function contentQuad(handle) {
const { quads } = await handle.client.send("DOM.getContentQuads", {
objectId: handle.remoteObject().objectId,
});
if (!quads.length) throw new Error("element has no rendered box");
return toPoints(quads[0]);
}
async function findHandles(ctx) {
const found = await findTarget(ctx.page);
if (!found) throw new Error("target not found in preview");
ctx.handles = { target: found.target, root: await found.frame.$('[data-composition-id="main"]') };
}
async function readQuads({ handles }) {
return Promise.all([
contentQuad(handles.root),
contentQuad(handles.target),
handles.target.evaluate((e) => ({
width: e.offsetWidth,
height: e.offsetHeight,
clip: getComputedStyle(e).clipPath,
})),
]);
}
/** The target's rendered quad, visible (cropped) quad and the screen/composition mapping, from CDP quads. */
async function measure(ctx) {
// Studio can swap the preview into a fresh iframe; a cached handle then reads a hidden copy, so find it again.
let read = null;
for (let attempt = 0; !read; attempt++) {
read = await (ctx.handles ? readQuads(ctx) : Promise.reject(new Error("no handles"))).catch(
async (error) => {
if (attempt === 5) throw error;
await sleep(100);
await findHandles(ctx).catch(() => undefined);
return null;
},
);
}
const [rootQuad, targetQuad, box] = read;
const map = compositionMapper(rootQuad, COMPOSITION);
const quad = targetQuad.map(map.toComp);
const size = { width: box.width, height: box.height };
return { map, quad, size, visible: visibleQuad(quad, size, parseInset(box.clip)) };
}
const STILL_MS = 1000;
// Studio reloads an edited preview in a shadow iframe (`_t` in its URL) and swaps it in when painted.
const previewFrames = (page) =>
page
.frames()
.map((f) => f.url())
.filter((u) => u.includes("/preview"))
.join(" ");
/** Measures once the preview frames and the box have held still for STILL_MS; Studio updates both after a save. */
// fallow-ignore-next-line complexity
async function settled(ctx, timeout = 15_000) {
const deadline = Date.now() + timeout;
let start = { m: await measure(ctx), frames: previewFrames(ctx.page) };
let now = start;
// Compared with the window's first read, so a drift too slow to show read to read still restarts it.
for (let since = Date.now(); Date.now() - since < STILL_MS; ) {
// A preview that never holds still is a Studio defect: the metrics it feeds fail, the rest still count.
if (Date.now() > deadline) return { ...now.m, unsettled: true };
await nextFrame(ctx.page);
now = { m: await measure(ctx), frames: previewFrames(ctx.page) };
if (now.frames !== start.frames || quadDistance(now.m.visible, start.m.visible) >= 0.01)
[start, since] = [now, Date.now()];
}
return now.m;
}
/** Ready once Studio's own seek tool reports the composition and the playhead landed. */
// fallow-ignore-next-line complexity
async function openStudio(ctx) {
ctx.handles = null;
await ctx.page.waitForFunction(() => window.__editBench?.has("studio_seek"), { timeout: 90_000 });
let seek = null;
for (const deadline = Date.now() + 30_000; Date.now() < deadline; await sleep(250)) {
seek = await ctx.page
.evaluate((time) => window.__editBench.call("studio_seek", { time }), PLAYHEAD)
.catch(String);
if (seek?.ok && seek.duration > 0 && seek.playhead === PLAYHEAD && (await findTarget(ctx.page)))
break;
seek = null;
}
if (!seek) throw new Error("studio never reported a seekable composition");
await sleep(1000);
return settled(ctx);
}
/** Puppeteer presses one key at a time: hold the modifiers around the last key. */
async function chord(page, keys) {
const [key, ...mods] = keys.split("+").reverse();
for (const m of mods) await page.keyboard.down(m);
await page.keyboard.press(key);
for (const m of mods) await page.keyboard.up(m);
}
async function blurPreview(page) {
await page.evaluate(() => {
if (document.activeElement?.tagName === "IFRAME") document.activeElement.blur();
});
}
/** Snapping deliberately pulls the box off the pointer, so the bench turns it off with Studio's own toggle. */
async function disableSnap(page) {
const title = await page.$eval('[aria-label="Toggle snap"]', (b) => b.title);
if (/enabled/i.test(title)) await page.click('[aria-label="Toggle snap"]');
const after = await page.$eval('[aria-label="Toggle snap"]', (b) => b.title);
if (!/disabled/i.test(after)) throw new Error(`snap toggle did not turn off: ${after}`);
}
const zoomOf = (page) =>
page.$eval('[data-testid="preview-zoom-stage"]', (e) => {
const m = /scale\(([\d.]+)\)/.exec(e.style.transform);
return m ? Number(m[1]) * 100 : 100;
});
/** Ctrl+wheel over the target, as a person zooms; wheel units are solved exactly from the zoom law. */
async function setZoom(ctx, percent, anchor) {
if (percent === 100) return 100;
await ctx.page.mouse.move(anchor[0], anchor[1]);
await ctx.page.keyboard.down("Control");
let units = Math.log(percent / (await zoomOf(ctx.page))) / ZOOM_SENSITIVITY;
while (Math.abs(units) > 1e-9) {
const step = Math.max(-10, Math.min(10, units));
await ctx.page.mouse.wheel({ deltaY: -step });
units -= step;
}
await ctx.page.keyboard.up("Control");
await sleep(400);
const achieved = await zoomOf(ctx.page);
if (Math.abs(achieved - percent) > 0.5)
throw new Error(`zoom ${percent}% landed at ${achieved}%`);
return achieved;
}
const overlayRect = (page, selector) =>
page.$$eval(selector, (els) =>
els.map((e) => {
const r = e.getBoundingClientRect();
return {
x: r.left + r.width / 2,
y: r.top + r.height / 2,
w: r.width,
h: r.height,
label: e.getAttribute("aria-label"),
};
}),
);
async function selectTarget(ctx, m) {
const c = m.map.toScreen(centre(m.visible));
const want = m.visible.map(m.map.toScreen);
const isSelected = async () => {
const [box] = await overlayRect(ctx.page, "[data-dom-edit-selection-box]");
if (!box) return false;
const xs = want.map((p) => p[0]);
const ys = want.map((p) => p[1]);
const w = Math.max(...xs) - Math.min(...xs);
const h = Math.max(...ys) - Math.min(...ys);
return Math.abs(box.w - w) < 4 && Math.abs(box.h - h) < 4 && dist([box.x, box.y], c) < 4;
};
const waitSelected = async () => {
for (const deadline = Date.now() + 2000; Date.now() < deadline; await sleep(100))
if (await isSelected()) return true;
return false;
};
await ctx.page.mouse.click(c[0], c[1]);
if (await waitSelected()) return;
// A nested composition's child takes a second click to enter the composition.
await ctx.page.mouse.click(c[0], c[1], { count: 2 });
if (!(await waitSelected())) {
const boxes = await overlayRect(ctx.page, "[data-dom-edit-selection-box]");
throw new Error(
`could not select #target at ${c.map(Math.round)}; selection ${JSON.stringify(boxes)}`,
);
}
}
// fallow-ignore-next-line complexity
async function handlePoint(ctx, m, gesture) {
if (gesture === "move" || gesture === "nudge") return m.map.toScreen(centre(m.visible));
if (gesture === "rotate") {
const [h] = await overlayRect(ctx.page, '[aria-label="Rotate selection"]');
if (!h) throw new Error("no rotate handle");
return [h.x, h.y];
}
if (gesture === "crop") {
const [h] = await overlayRect(ctx.page, '[aria-label="Crop right"]');
if (!h) throw new Error("no crop right handle");
return [h.x, h.y];
}
const corner = m.map.toScreen(m.visible[2]);
const dots = await overlayRect(ctx.page, "div.pointer-events-auto.absolute.h-4.w-4");
if (!dots.length) throw new Error("no resize handles");
const dot = dots.reduce((a, b) => (dist([a.x, a.y], corner) <= dist([b.x, b.y], corner) ? a : b));
return [dot.x, dot.y];
}
async function cropOutline(ctx, map) {
const h = await ctx.page.$("[data-dom-edit-crop-frame] > div.border-dashed");
if (!h) throw new Error("no crop outline");
return (await contentQuad(h)).map(map.toComp);
}
/** Screen path (one point per frame) and the per-frame tracking error for each pointer gesture. */
function plan(gesture, pre, pressComp) {
const at = (p) => pre.map.toScreen(p);
const steps = Array.from({ length: STEPS }, (_, i) => (i + 1) / STEPS);
const follow = (point) => ({
point,
error: (s, s0) =>
dist([s.p[0] - s0.p[0], s.p[1] - s0.p[1]], [s.c[0] - s0.c[0], s.c[1] - s0.c[1]]),
});
if (gesture === "move") {
const local = quadToLocal(pre.quad, pre.size, pressComp);
return {
path: steps.map((k) => at([pressComp[0] + MOVE_BY[0] * k, pressComp[1] + MOVE_BY[1] * k])),
...follow((m) => localToQuad(m.quad, m.size, local)),
};
}
if (gesture === "resize") {
const c = centre(pre.visible);
const d = dist(pre.visible[2], c);
const u = [(pre.visible[2][0] - c[0]) / d, (pre.visible[2][1] - c[1]) / d];
return {
path: steps.map((k) =>
at([pressComp[0] + u[0] * RESIZE_BY * k, pressComp[1] + u[1] * RESIZE_BY * k]),
),
...follow((m) => m.visible[2]),
};
}
if (gesture === "crop") {
const n = [pre.quad[0][0] - pre.quad[1][0], pre.quad[0][1] - pre.quad[1][1]];
const len = Math.hypot(...n);
return {
path: steps.map((k) =>
at([pressComp[0] + (n[0] / len) * CROP_BY * k, pressComp[1] + (n[1] / len) * CROP_BY * k]),
),
...follow((m) => mid(m.outline[1], m.outline[2])),
};
}
const c = centre(pre.visible);
const r = dist(pressComp, c);
const a0 = Math.atan2(pressComp[1] - c[1], pressComp[0] - c[0]);
const angle = (p) => Math.atan2(p[1] - c[1], p[0] - c[0]);
return {
path: steps.map((k) =>
at([c[0] + r * Math.cos(a0 + ROTATE_BY * k), c[1] + r * Math.sin(a0 + ROTATE_BY * k)]),
),
point: (m) => [angleOf(m.quad), 0],
error: (s, s0) => Math.abs(normalizeAngle(s.p[0] - s0.p[0] - (angle(s.c) - angle(s0.c)))) * r,
};
}
async function sample(ctx, gesture, point, pointerScreen) {
const m = await measure(ctx);
if (gesture === "crop") m.outline = await cropOutline(ctx, m.map);
return { m, p: point(m), c: m.map.toComp(pointerScreen) };
}
const TRACE_CATEGORIES = ["toplevel", "devtools.timeline", "blink.user_timing"];
const TRACE_MARK = "edit-bench-end";
/** Frame stamps plus a main-thread trace of the drag; the end mark ties performance.now() to trace time. */
async function recording(page, on) {
if (on) await page.tracing.start({ categories: TRACE_CATEGORIES });
const rec = await page.evaluate(
(flag, mark) => {
const rec = window.__editBench.rec;
if (flag) [rec.frames, rec.long, rec.on] = [[], [], true];
else rec.on = false;
return {
frames: rec.frames,
long: rec.long,
mark: flag ? null : performance.mark(mark).startTime,
};
},
on,
TRACE_MARK,
);
if (on) return rec;
const trace = new TextDecoder().decode(await page.tracing.stop());
return { ...rec, trace: JSON.parse(trace).traceEvents };
}
const isRunTask = (e) =>
e.ph === "X" && (e.name === "RunTask" || e.name === "ThreadControllerImpl::RunTask");
/** Outermost tasks on one thread; nested RunTask events sit inside them. */
function topLevelTasks(trace, { pid, tid }) {
const runs = trace
.filter((e) => e.pid === pid && e.tid === tid && isRunTask(e))
.sort((a, b) => a.ts - b.ts || b.dur - a.dur);
const tops = [];
let end = -Infinity;
for (const e of runs) {
if (e.ts < end) continue;
tops.push(e);
end = e.ts + e.dur;
}
return tops;
}
// Thread CPU time, spread evenly over the task, so a loaded machine descheduling the thread does not count as work.
const cpuUs = (e, a, b) =>
(Math.max(0, Math.min(b, e.ts + e.dur) - Math.max(a, e.ts)) * e.tdur) / (e.dur || 1);
/** Main-thread CPU ms inside each frame interval, on the thread that ran the end mark; null when unknown. */
function mainThreadPerFrame({ frames, mark, trace }) {
const anchor = trace.find((e) => e.name === TRACE_MARK && e.cat.includes("user_timing"));
const tasks = anchor ? topLevelTasks(trace, anchor) : [];
// Without the mark or thread CPU time the work is unknown, which fails smoothness alone.
if (!anchor || tasks.some((e) => e.tdur === undefined)) return null;
const toTrace = (ms) => anchor.ts + (ms - mark) * 1000;
return frames.slice(1).map((t, i) => {
const [a, b] = [toTrace(frames[i]), toTrace(t)];
return tasks.reduce((sum, e) => sum + cpuUs(e, a, b), 0) / 1000;
});
}
const hundredth = (v) => Math.round(v * 100) / 100;
function smoothness(rec) {
const intervals = rec.frames.slice(1).map((t, i) => t - rec.frames[i]);
const work = mainThreadPerFrame(rec);
return {
p95: percentile(intervals, 95),
frames: intervals.length,
longTasks: rec.long.length,
intervals: intervals.map(hundredth),
work: work && work.map(hundredth),
};
}
const CONTROL_PAGE = `data:text/html,<body style="margin:0;background:%23202020"><div id="box"
style="position:absolute;left:600px;top:300px;width:240px;height:160px;background:%23f0c020"></div>`;
/** The case's drag schedule and per-frame reads on a blank page in the same Chrome: the machine's own frame drops. */
async function controlDrag(browser, gesture) {
const context = await browser.createBrowserContext();
try {
const page = await context.newPage();
await page.setViewport(VIEWPORT);
await page.evaluateOnNewDocument(instrumentPage);
await page.goto(CONTROL_PAGE);
const box = await page.$("#box");
const ctx = { page, handles: { target: box, root: box } };
const read = () => readQuads(ctx);
if (gesture === "nudge") {
await recording(page, true);
for (let i = 0; i < NUDGES; i++) {
await page.keyboard.press("ArrowRight");
await nextFrame(page);
}
await nextFrame(page, 2);
return smoothness(await recording(page, false));
}
await page.mouse.move(700, 380);
await page.mouse.down();
await nextFrame(page);
await read();
await recording(page, true);
for (let i = 1; i <= STEPS; i++) {
await page.mouse.move(700 + (MOVE_BY[0] * i) / STEPS, 380 + (MOVE_BY[1] * i) / STEPS);
await nextFrame(page);
await read();
}
const smooth = smoothness(await recording(page, false));
await page.mouse.up();
return smooth;
} finally {
await context.close().catch(() => undefined);
}
}
async function pointerGesture(ctx, gesture, pre) {
const press = await handlePoint(ctx, pre, gesture);
const pressComp = pre.map.toComp(press);
const g = plan(gesture, pre, pressComp);
const hit = await ctx.page.evaluate(([x, y]) => {
const e = document.elementFromPoint(x, y);
return e
? `${e.tagName.toLowerCase()}${e.getAttribute("aria-label") ? `[${e.getAttribute("aria-label")}]` : ""}`
: null;
}, press);
await ctx.page.mouse.move(press[0], press[1]);
await ctx.page.mouse.down();
await nextFrame(ctx.page);
const s0 = await sample(ctx, gesture, g.point, press);
await recording(ctx.page, true);
const errors = [];
let last = s0;
for (const p of g.path) {
await ctx.page.mouse.move(p[0], p[1]);
await nextFrame(ctx.page);
last = await sample(ctx, gesture, g.point, p);
errors.push(g.error(last, s0));
}
const rec = await recording(ctx.page, false);
const smooth = smoothness(rec);
await ctx.page.mouse.up();
const lastQuad = gesture === "crop" ? last.m.outline : last.m.visible;
return {
errors,
lastQuad,
pressJump: quadDistance(s0.m.visible, pre.visible),
smooth,
diag: {
hit,
grabOffset: gesture === "rotate" ? 0 : dist(s0.p, s0.c),
errors: errors.map((e) => Math.round(e * 1000) / 1000),
},
};
}
async function nudgeGesture(ctx, pre) {
await recording(ctx.page, true);
for (let i = 0; i < NUDGES; i++) {
await ctx.page.keyboard.press("ArrowRight");
await nextFrame(ctx.page);
}
await nextFrame(ctx.page, 2);
const smooth = smoothness(await recording(ctx.page, false));
const m = await measure(ctx);
const [a, b] = [centre(pre.visible), centre(m.visible)];
return {
errors: [dist([b[0] - a[0], b[1] - a[1]], [NUDGES, 0])],
lastQuad: m.visible,
pressJump: null,
smooth,
diag: {},
};
}
/** One case, end to end, in a fresh browser context against a Studio already serving `dir`. */
// fallow-ignore-next-line complexity
export async function runCase({ browser, spec, dir, files, url, evidence }) {
const control = await controlDrag(browser, spec.gesture);
const context = await browser.createBrowserContext();
const page = await context.newPage();
const ctx = { page, dir, files, handles: null };
const consoleErrors = [];
page.on("pageerror", (e) => consoleErrors.push(e.message));
evidence.shots = {};
const shoot = async (name) =>
(evidence.shots[name] = await page.screenshot({ type: "jpeg", quality: 70 }));
let committedFiles = null;
try {
await page.setViewport(VIEWPORT);
await page.evaluateOnNewDocument(instrumentPage);
await page.goto(url);
let pre = await openStudio(ctx);
await disableSnap(page);
const zoom = await setZoom(ctx, spec.zoom, pre.map.toScreen(centre(pre.visible)));
pre = await settled(ctx);
await selectTarget(ctx, pre);
pre = await settled(ctx);
const original = readFiles(dir, files);
const drive =
spec.gesture === "nudge"
? await nudgeGesture(ctx, pre)
: await pointerGesture(ctx, spec.gesture, pre);
await waitForFiles(ctx, { from: original, timeout: spec.gesture === "nudge" ? 6000 : 5000 });
await nextFrame(page, 2);
await blurPreview(page);
await page.keyboard.press("Escape");
const committed = await settled(ctx);
await shoot("committed");
committedFiles = readFiles(dir, files);
const saved = !sameFiles(committedFiles, original);
// Undo and redo run before any reload. Each waits up to 15 s for its own write; redo waits for undo.
const landed = (from) =>
saved ? waitForFiles(ctx, { from, timeout: 15_000 }) : { reached: true, files: from };
await chord(page, "Control+z");
const undo = await landed(committedFiles);
const undone = await settled(ctx);
await shoot("undone");
let [redo, redone] = [{ reached: false }, null];
if (undo.reached) {
await blurPreview(page);
await chord(page, "Control+Shift+z");
redo = await landed(undo.files);
redone = await settled(ctx);
}
// A late write must not land under the reload.
await waitForFiles(ctx, { timeout: 15_000 });
await page.reload();
const reloaded = await openStudio(ctx);
await shoot("reloaded");
const quads = Object.fromEntries(
Object.entries({ pre, committed, undone, redone, reloaded }).filter(([, m]) => m),
);
const round = (m) => m.visible.map((p) => p.map((v) => Math.round(v * 100) / 100));
return {
zoom,
saved,
tracking: {
max: Math.max(...drive.errors),
p95: percentile(drive.errors, 95),
frames: drive.errors.length,
},
pressJump: drive.pressJump,
drop: quadDistance(drive.lastQuad, committed.visible),
reload: quadDistance(committed.visible, reloaded.visible),
undo: {
bytes: saved && undo.reached && sameFiles(undo.files, original),
box: quadDistance(undone.visible, pre.visible),
redoBytes: saved && redo.reached && sameFiles(redo.files, committedFiles),
redoBox: redone && quadDistance(redone.visible, committed.visible),
},
// Which write never landed within 15 s; a redo that was never sent is untested, so undo fails.
undoTimeout: saved && !undo.reached ? "undo" : saved && !redo.reached ? "redo" : null,
smooth: { ...drive.smooth, control },
unsettled: Object.keys(quads).filter((k) => quads[k].unsettled),
diag: {
...drive.diag,
consoleErrors: consoleErrors.slice(0, 5),
quads: Object.fromEntries(Object.entries(quads).map(([k, m]) => [k, round(m)])),
},
};
} catch (error) {
await shoot("error").catch(() => undefined);
throw error;
} finally {
evidence.files = committedFiles;
await context.close().catch(() => undefined);
}
}
@@ -0,0 +1,74 @@
/** Pure geometry for the edit accuracy bench. Points are [x, y]; a quad is 4 points, clockwise from top-left. */
export const toPoints = (flat) => [0, 2, 4, 6].map((i) => [flat[i], flat[i + 1]]);
const sub = (a, b) => [a[0] - b[0], a[1] - b[1]];
const add = (a, b) => [a[0] + b[0], a[1] + b[1]];
const scale = (a, k) => [a[0] * k, a[1] * k];
export const dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1]);
export const mid = (a, b) => scale(add(a, b), 0.5);
export const centre = (q) => scale(q.reduce(add, [0, 0]), 0.25);
/** Affine frame of a quad: origin plus the two edge vectors for a box of `size` local px. */
function frameOf(q, size) {
return {
o: q[0],
ex: scale(sub(q[1], q[0]), 1 / size.width),
ey: scale(sub(q[3], q[0]), 1 / size.height),
};
}
export function localToQuad(q, size, [u, v]) {
const f = frameOf(q, size);
return add(f.o, add(scale(f.ex, u), scale(f.ey, v)));
}
export function quadToLocal(q, size, p) {
const { o, ex, ey } = frameOf(q, size);
const d = sub(p, o);
const det = ex[0] * ey[1] - ex[1] * ey[0];
return [(d[0] * ey[1] - d[1] * ey[0]) / det, (ex[0] * d[1] - ex[1] * d[0]) / det];
}
/** Screen to composition px through the root composition's rendered quad. */
export function compositionMapper(rootQuad, composition) {
return {
toComp: (p) => quadToLocal(rootQuad, composition, p),
toScreen: (p) => localToQuad(rootQuad, composition, p),
};
}
/** The visible quad: the element box shrunk by its clip-path insets, in the element's local frame. */
export function visibleQuad(q, size, inset) {
const r = size.width - inset.right;
const b = size.height - inset.bottom;
return [
[inset.left, inset.top],
[r, inset.top],
[r, b],
[inset.left, b],
].map((p) => localToQuad(q, size, p));
}
export const quadDistance = (a, b) => Math.max(...a.map((p, i) => dist(p, b[i])));
export const angleOf = (q) => Math.atan2(q[1][1] - q[0][1], q[1][0] - q[0][0]);
export const normalizeAngle = (a) => Math.atan2(Math.sin(a), Math.cos(a));
/** `inset(t r b l [round ...])` in px, as getComputedStyle reports it; none means no crop. */
export function parseInset(clipPath) {
const zero = { top: 0, right: 0, bottom: 0, left: 0 };
const m = /^inset\(([^)]*)\)/.exec(clipPath ?? "");
if (!m) return zero;
const v = m[1]
.split(/\s+round\s+/)[0]
.trim()
.split(/\s+/)
.map((s) => Number.parseFloat(s));
const [t, r = t, b = t, l = r] = v;
return { top: t, right: r, bottom: b, left: l };
}
export function percentile(values, p) {
if (!values.length) return null;
const s = [...values].sort((a, b) => a - b);
return s[Math.min(s.length - 1, Math.ceil((p / 100) * s.length) - 1)];
}
@@ -0,0 +1,122 @@
// The edit accuracy grid: one flat-coloured element in a generated project, crossed with one gesture.
// Projects are written to a tmp dir per case; nothing checked in is edited.
import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
export const COMPOSITION = { width: 1920, height: 1080 };
/** Frame-aligned at 30 fps, inside every tween, so preview and producer sample the same instant. */
export const PLAYHEAD = 1;
const TARGET = { width: 240, height: 160, color: "#f0c020" };
const BACKGROUND = "#202020";
const NESTED_HOST = { left: 160, top: 90, width: 1600, height: 900 };
const GSAP_CDN = "https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js";
// Studio has corner handles only (ResizeHandle is nw|ne|sw|se); its edge strips crop, so there is no edge resize.
const GESTURES = ["move", "resize", "rotate", "crop", "nudge"];
const AXES = {
gsap: ["none", "tween", "hold"],
placement: ["px", "pct", "center", "xpercent"],
rotation: [0, 30],
nesting: ["root", "nested"],
zoom: [50, 100, 200],
};
const product = (axes) =>
Object.entries(axes).reduce(
(rows, [key, values]) => rows.flatMap((row) => values.map((v) => ({ ...row, [key]: v }))),
[{}],
);
const caseId = (c) =>
[c.gesture, c.gsap, c.placement, `r${c.rotation}`, c.nesting, `z${c.zoom}`].join("-");
/** `pr` is a smaller slice for CI; its final size is still an open decision. */
export function buildGrid(kind = "full") {
return product({ ...AXES, gesture: GESTURES })
.filter((c) => c.placement !== "xpercent" || c.gsap !== "none") // xPercent only exists through GSAP
.filter((c) => kind !== "pr" || (c.zoom === 100 && c.nesting === "root"))
.map((c) => ({ id: caseId(c), ...c }));
}
const PLACEMENT_CSS = {
px: "left: 560px; top: 300px; translate: 40px 30px;",
pct: "left: 560px; top: 300px; translate: 25% 25%;",
center: "left: 50%; top: 50%; translate: -50% -50%;",
xpercent: "left: 50%; top: 50%;",
};
function targetCss(spec) {
const rotate = spec.rotation ? ` rotate: ${spec.rotation}deg;` : "";
return `#target { position: absolute; ${PLACEMENT_CSS[spec.placement]} width: ${TARGET.width}px; height: ${TARGET.height}px; background: ${TARGET.color};${rotate} }`;
}
function gsapLines(spec) {
const percent = spec.placement === "xpercent" ? ", xPercent: -50, yPercent: -50" : "";
if (spec.gsap === "hold") return [`gsap.set("#target", { x: 40, y: 20${percent} });`];
const lines = [`tl.to("#target", { x: 120, y: 60, duration: 4, ease: "none" }, 0);`];
if (percent) lines.unshift(`gsap.set("#target", { ${percent.slice(2)} });`);
return lines;
}
function timelineScript(id, lines) {
return `<script src="${GSAP_CDN}"></script>
<script>
(function () {
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
${lines.join("\n ")}
window.__timelines["${id}"] = tl;
})();
</script>`;
}
// fallow-ignore-next-line complexity
function rootHtml(spec) {
const nested = spec.nesting === "nested";
const body = nested
? `<div id="scene-sub" data-composition-id="sub" data-composition-src="compositions/sub.html" data-start="0" data-duration="4" data-track-index="1" style="position: absolute; left: ${NESTED_HOST.left}px; top: ${NESTED_HOST.top}px; width: ${NESTED_HOST.width}px; height: ${NESTED_HOST.height}px; overflow: hidden"></div>`
: `<div id="target" class="clip" data-start="0" data-duration="4" data-track-index="1"></div>`;
const script = spec.gsap === "none" ? "" : timelineScript("main", nested ? [] : gsapLines(spec));
return `<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<style>
html, body { margin: 0; width: ${COMPOSITION.width}px; height: ${COMPOSITION.height}px; overflow: hidden; background: ${BACKGROUND}; }
#root { position: relative; width: 100%; height: 100%; }
${nested ? "" : targetCss(spec)}
</style>
</head>
<body>
<div id="root" data-composition-id="main" data-start="0" data-duration="4" data-width="${COMPOSITION.width}" data-height="${COMPOSITION.height}">
${body}
</div>
${script}
</body>
</html>
`;
}
function subHtml(spec) {
const script = spec.gsap === "none" ? "" : timelineScript("sub", gsapLines(spec));
return `<template id="sub-template">
<div id="sub" data-composition-id="sub" data-width="${NESTED_HOST.width}" data-height="${NESTED_HOST.height}">
<div id="target"></div>
<style>
#sub { position: relative; width: ${NESTED_HOST.width}px; height: ${NESTED_HOST.height}px; background: ${BACKGROUND}; overflow: hidden; }
${targetCss(spec)}
</style>
${script}
</div>
</template>
`;
}
/** Writes the case's project into `dir` and returns the files a gesture may rewrite. */
export function writeFixture(spec, dir) {
mkdirSync(dir, { recursive: true });
writeFileSync(join(dir, "index.html"), rootHtml(spec));
if (spec.nesting !== "nested") return ["index.html"];
mkdirSync(join(dir, "compositions"), { recursive: true });
writeFileSync(join(dir, "compositions/sub.html"), subHtml(spec));
return ["index.html", "compositions/sub.html"];
}
@@ -0,0 +1,192 @@
/** Scoring and the three report files (results.json, table.md, baseline.json) for the edit accuracy bench. */
import { writeFileSync } from "node:fs";
import { join } from "node:path";
import { percentile } from "./geometry.mjs";
const LIMIT_PX = 0.5;
// A frame over 1.5 vsyncs is dropped; raw rAF p95 stays reported so a different rule re-scores without a re-run.
const DROPPED_FRAME_MS = 25;
const WORK_MS = 8;
export const METRICS = ["tracking", "press", "drop", "reload", "undo", "smooth"];
/** Worst-first value per metric; undo ranks by box distance, and its byte failures are counted apart. */
const worstValue = {
tracking: (r) => r.tracking.max,
press: (r) => r.pressJump ?? 0,
drop: (r) => r.drop,
reload: (r) => r.reload,
undo: (r) => Math.max(r.undo.box, r.undo.redoBox ?? 0),
smooth: (r) => r.smooth.dropped - r.smooth.control.dropped,
};
/** Dropped frames and main-thread ms per frame at p95, from the raw intervals and trace work a case stores. */
const frameBudget = (smooth) => ({
...smooth,
dropped: smooth.intervals.filter((d) => d > DROPPED_FRAME_MS).length,
workP95: smooth.work && percentile(smooth.work, 95),
});
/** The metrics each snapshot feeds; a snapshot whose preview never held still fails them. */
const FED_BY = {
pre: ["press", "undo"],
committed: ["drop", "reload", "undo"],
undone: ["undo"],
redone: ["undo"],
reloaded: ["reload"],
};
const unsettledMetrics = (r) => new Set(r.unsettled.flatMap((k) => FED_BY[k]));
// fallow-ignore-next-line complexity
export function score(spec, r) {
if (r.error)
return {
...spec,
...r,
pass: false,
checks: Object.fromEntries(METRICS.map((m) => [m, false])),
};
const smooth = { ...frameBudget(r.smooth), control: frameBudget(r.smooth.control) };
const checks = {
tracking: r.tracking.max <= LIMIT_PX,
press: r.pressJump === null || r.pressJump <= LIMIT_PX,
drop: r.drop <= LIMIT_PX,
reload: r.reload <= LIMIT_PX,
undo: r.undo.bytes && r.undo.redoBytes && Math.max(r.undo.box, r.undo.redoBox) <= LIMIT_PX,
// Only drops beyond the blank page's, driven the same way in the same Chrome, are the edit's.
smooth:
smooth.dropped <= smooth.control.dropped &&
smooth.workP95 !== null &&
smooth.workP95 <= WORK_MS,
};
for (const m of unsettledMetrics(r)) checks[m] = false;
return { ...spec, ...r, smooth, pass: Object.values(checks).every(Boolean), checks };
}
const round = (v) => (typeof v === "number" ? Math.round(v * 100) / 100 : v);
// Rounded up for baseline.json, so a stored value passes a limit only if the measured one did (to 1e-11).
const roundUp = (v) => (v === null ? null : Math.ceil(v * 100 - 1e-9) / 100);
const medianMax = (values) =>
values.length ? `${round(percentile(values, 50))}/${round(Math.max(...values))}` : "-";
function smoothSummary(measured) {
const s = measured.map((r) => r.smooth);
return {
unknown: s.filter((x) => x.workP95 === null).length,
dropped: medianMax(s.map((x) => x.dropped)),
control: medianMax(s.map((x) => x.control.dropped)),
p95: medianMax(s.map((x) => x.p95)),
controlP95: medianMax(s.map((x) => x.control.p95)),
};
}
function summarize(results, seconds) {
const passing = results.filter((r) => r.pass).length;
// Smoothness is still ungated in CI, so the score is also shown without it.
const accurate = results.filter((r) =>
METRICS.every((m) => m === "smooth" || r.checks[m]),
).length;
const measured = results.filter((r) => !r.error);
const perMetric = METRICS.map((m) => {
const worst = measured.reduce(
(a, r) => (!a || worstValue[m](r) > worstValue[m](a) ? r : a),
null,
);
return {
metric: m,
pass: results.filter((r) => r.checks[m]).length,
worst: worst && {
id: worst.id,
value: round(worstValue[m](worst)),
unsettled: unsettledMetrics(worst).has(m),
},
};
});
return {
passing,
accurate,
total: results.length,
errors: results.length - measured.length,
bytesDiffer: {
undo: measured.filter((r) => !r.undo.bytes).length,
redo: measured.filter((r) => !r.undo.redoBytes).length,
},
perMetric,
unsettled: measured.filter((r) => r.unsettled.length).length,
undoTimeouts: measured.filter((r) => r.undoTimeout).length,
smooth: smoothSummary(measured),
seconds: Math.round(seconds),
};
}
// fallow-ignore-next-line complexity
const metricRow = (m, total) =>
`| ${m.metric} | ${m.pass}/${total} | ${m.worst?.value ?? "-"}${m.worst?.unsettled ? " (unsettled)" : ""} | ${m.worst?.id ?? "-"} |`;
function table(summary, meta, results) {
const lines = [
`# Edit accuracy: ${summary.accurate}/${summary.total} cases pass`,
"",
`Every metric counts except smoothness, which is reported against the blank-page control: ${summary.perMetric.find((m) => m.metric === "smooth").pass}/${summary.total} pass it, and ${summary.passing}/${summary.total} pass everything including it.`,
"",
`Studio ${meta.studio} (build ${meta.build}), bench ${meta.bench}, grid \`${meta.grid}\`, ${meta.date}, ${summary.seconds}s with ${meta.jobs} jobs, ${summary.errors} harness errors, load ${meta.load}.`,
`Pass: tracking, press jump, drop and reload ≤ ${LIMIT_PX} px; undo and redo byte-identical with the box ≤ ${LIMIT_PX} px; no more frames over ${DROPPED_FRAME_MS} ms than the blank-page control, and main-thread work ≤ ${WORK_MS} ms per frame at p95.`,
"",
`Undo or redo left different bytes in ${summary.bytesDiffer.undo} undo and ${summary.bytesDiffer.redo} redo cases.`,
`The preview never held still for 1 s within 15 s in ${summary.unsettled} cases; the metrics that snapshot feeds fail.`,
`An undo or redo write never landed within 15 s in ${summary.undoTimeouts} cases; undo fails there.`,
`Smoothness: ${summary.smooth.unknown} cases with unknown work; dropped frames per case (median/max) ${summary.smooth.dropped}, blank-page control ${summary.smooth.control}; raw rAF p95 (median/max) ${summary.smooth.p95} ms, control ${summary.smooth.controlP95} ms.`,
"",
"| Metric | Pass | Worst | Worst case |",
"|---|---|---|---|",
...summary.perMetric.map((m) => metricRow(m, summary.total)),
"",
"| Gesture | Cases | Pass | " + METRICS.join(" | ") + " |",
"|---|---|---|" + METRICS.map(() => "---").join("|") + "|",
];
for (const g of [...new Set(results.map((r) => r.gesture))]) {
const rs = results.filter((r) => r.gesture === g);
lines.push(
`| ${g} | ${rs.length} | ${rs.filter((r) => r.pass).length} | ${METRICS.map((m) => rs.filter((r) => r.checks[m]).length).join(" | ")} |`,
);
}
return lines.join("\n") + "\n";
}
/** One line per case, so a baseline diff reads case by case. */
function baseline(meta, results) {
const entries = [...results]
.sort((a, b) => a.id.localeCompare(b.id))
.map((r) => {
const v = r.error
? { pass: false, error: true }
: {
pass: r.pass,
tracking: roundUp(r.tracking.max),
pressJump: roundUp(r.pressJump),
drop: roundUp(r.drop),
reload: roundUp(r.reload),
undo: r.checks.undo,
dropped: r.smooth.dropped,
controlDropped: r.smooth.control.dropped,
work: roundUp(r.smooth.workP95),
frameP95: roundUp(r.smooth.p95),
...(r.unsettled.length && { unsettled: r.unsettled }),
...(r.undoTimeout && { undoTimeout: r.undoTimeout }),
};
return ` ${JSON.stringify(r.id)}: ${JSON.stringify(v)}`;
});
return `{\n "studio": ${JSON.stringify(meta.studio)},\n "build": ${JSON.stringify(meta.build)},\n "bench": ${JSON.stringify(meta.bench)},\n "grid": ${JSON.stringify(meta.grid)},\n "cases": {\n${entries.join(",\n")}\n }\n}\n`;
}
/** Writes results.json, table.md and baseline.json into `out`; returns the table. */
export function writeReport(out, meta, results, seconds) {
const summary = summarize(results, seconds);
writeFileSync(
join(out, "results.json"),
JSON.stringify({ meta, summary, cases: results }, null, 1),
);
writeFileSync(join(out, "table.md"), table(summary, meta, results));
writeFileSync(join(out, "baseline.json"), baseline(meta, results));
return table(summary, meta, results);
}
@@ -0,0 +1,197 @@
#!/usr/bin/env bun
// Edit accuracy bench: real gestures in the built CLI Studio (build core, parsers, lint, studio-server first).
// bun run --cwd packages/studio test:edit-accuracy -- --grid full|pr --jobs N [--shard i/n] [--filter re] [--lock path]
import { createHash } from "node:crypto";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { loadavg, tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { parseArgs } from "node:util";
import { execSync, spawn } from "node:child_process";
import puppeteer from "puppeteer-core";
import { resolveHeadlessShellPath } from "../../../../engine/src/index.ts";
import { buildGrid, writeFixture } from "./grid.mjs";
import { killServers, runCase, startServer, stopServer } from "./case.mjs";
import { METRICS, score, writeReport } from "./report.mjs";
const HERE = dirname(fileURLToPath(import.meta.url));
const REPO = resolve(HERE, "../../../../..");
const { values: opt } = parseArgs({
options: {
grid: { type: "string", default: "full" },
shard: { type: "string", default: "1/1" },
jobs: { type: "string", default: "1" },
filter: { type: "string", default: "" },
out: { type: "string" },
port: { type: "string", default: "5800" },
cli: { type: "string", default: join(REPO, "packages/cli/dist/cli.js") },
lock: { type: "string" },
},
});
const [shard, shards] = opt.shard.split("/").map(Number);
const filter = new RegExp(opt.filter);
const cases = buildGrid(opt.grid).filter((c, i) => filter.test(c.id) && i % shards === shard - 1);
const runId = new Date().toISOString().replace(/[:.]/g, "-");
const out = resolve(opt.out ?? join(HERE, "../evidence/edit-accuracy", runId));
const chrome = resolveHeadlessShellPath();
if (!chrome) throw new Error("no chrome-headless-shell: run `npx hyperframes browser ensure`");
mkdirSync(out, { recursive: true });
/** Evidence for a failing case only: the Studio screens at each stage and the saved files. */
// fallow-ignore-next-line complexity
function saveEvidence(id, evidence) {
const caseDir = join(out, "cases", id);
mkdirSync(caseDir, { recursive: true });
for (const [name, jpeg] of Object.entries(evidence.shots ?? {}))
writeFileSync(join(caseDir, `${name}.jpg`), jpeg);
for (const [name, text] of Object.entries(evidence.files ?? {}))
writeFileSync(join(caseDir, `saved-${name.replace("/", "-")}`), text);
}
function verdict(r) {
const fails = r.error ? "ERROR" : METRICS.filter((m) => !r.checks[m]).join(",");
return `${r.pass ? "PASS" : "FAIL"} ${r.id} ${r.seconds.toFixed(1)}s ${fails}`;
}
// fallow-ignore-next-line complexity
const errorResult = (error, log) => ({
error: `${error?.message ?? error}\n${error?.stack ?? ""}`.slice(0, 1200),
serverLog: log.join("").slice(-600),
});
const liveRoots = new Set();
async function runOne(spec, browser, port) {
const started = Date.now();
const root = mkdtempSync(join(tmpdir(), "hf-edit-accuracy-"));
liveRoots.add(root);
const dir = join(root, "case");
const files = writeFixture(spec, dir);
const evidence = {};
const log = [];
let result;
let server;
try {
server = await startServer(opt.cli, dir, port, log, join(root, "home"));
result = await runCase({
browser,
spec,
dir,
files,
url: `http://127.0.0.1:${port}/#project/case`,
evidence,
});
} catch (error) {
result = errorResult(error, log);
} finally {
if (server) await stopServer(server);
}
const scored = { ...score(spec, result), seconds: (Date.now() - started) / 1000 };
if (!scored.pass) saveEvidence(spec.id, evidence);
rmSync(root, { recursive: true, force: true });
liveRoots.delete(root);
console.log(verdict(scored));
return scored;
}
/** Holds an flock on `path` until the returned release is called; flock(1) owns the lock, so it dies with us. */
function acquireLock(path) {
const child = spawn("flock", [path, "-c", "echo locked; exec cat"], {
stdio: ["pipe", "pipe", "inherit"],
});
return new Promise((resolve, reject) => {
child.once("error", reject);
child.once("exit", (code) => reject(new Error(`flock ${path} exited ${code}`)));
child.stdout.once("data", () => resolve(() => child.stdin.end()));
});
}
// The suite lock is taken per chunk, so a full grid never holds it for its whole run.
const LOCK_CHUNK = 8;
// fallow-ignore-next-line complexity
async function runChunks(queue, browsers, results) {
for (let start = 0; start < queue.length; start += opt.lock ? LOCK_CHUNK : queue.length) {
const chunk = queue.slice(start, opt.lock ? start + LOCK_CHUNK : queue.length);
const release = opt.lock ? await acquireLock(opt.lock) : () => undefined;
try {
await Promise.all(
browsers.map(async (browser, i) => {
for (let spec = chunk.shift(); spec; spec = chunk.shift())
results.push(await runOne(spec, browser, Number(opt.port) + i));
}),
);
} finally {
release();
}
}
}
function cleanup() {
killServers();
for (const root of liveRoots) rmSync(root, { recursive: true, force: true });
}
process.on("exit", cleanup);
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
process.on(signal, () => {
cleanup();
process.exit(130);
});
}
// Stamped at start from the CLI that runs: its tree's commit and a hash of the CLI and Studio bundles.
// cli.js alone does not change with Studio; the Studio index.html names its hashed assets.
const git = (args) => execSync(`git ${args}`, { cwd: REPO }).toString().trim();
const studio = (() => {
try {
return execSync("git rev-parse --short HEAD", { cwd: dirname(opt.cli), stdio: "pipe" })
.toString()
.trim();
} catch {
return "outside git"; // An extracted CLI artifact; the build hash still identifies it.
}
})();
const build = createHash("sha256")
.update(readFileSync(opt.cli))
.update(readFileSync(join(dirname(opt.cli), "studio/index.html")))
.digest("hex")
.slice(0, 12);
const bench = git("rev-parse --short HEAD");
const load = loadavg()
.map((v) => v.toFixed(1))
.join(" ");
const started = Date.now();
const results = [];
const jobs = Math.max(1, Math.min(Number(opt.jobs), cases.length));
console.log(`edit accuracy: ${cases.length} cases, ${jobs} jobs, chrome ${chrome}, out ${out}`);
const browsers = await Promise.all(
Array.from({ length: jobs }, () =>
puppeteer.launch({
executablePath: chrome,
headless: true,
args: ["--no-sandbox", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"],
}),
),
);
try {
await runChunks([...cases], browsers, results);
} finally {
await Promise.all(browsers.map((b) => b.close()));
}
results.sort((a, b) => a.id.localeCompare(b.id));
const meta = {
studio,
build,
bench,
grid:
opt.grid +
(opt.filter ? ` filter ${opt.filter}` : "") +
(shards > 1 ? ` shard ${opt.shard}` : ""),
date: new Date().toISOString(),
jobs,
chrome,
load: `${load} to ${loadavg()
.map((v) => v.toFixed(1))
.join(" ")}`,
};
console.log(writeReport(out, meta, results, (Date.now() - started) / 1000));