diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef1f49dd1f8..4a979d6b222 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -850,6 +850,8 @@ jobs: packages/studio/data/projects/fade-handles cp -R packages/studio/tests/e2e/fixtures/inline-text-caret \ packages/studio/data/projects/inline-text-caret + cp -R packages/studio/tests/e2e/fixtures/undo-socket-pool \ + packages/studio/data/projects/undo-socket-pool - name: Read the base branch's work-count ceilings # A ceiling may not disappear, or rise without a new reason, against the branch this PR merges into. if: github.event_name == 'pull_request' @@ -1000,6 +1002,28 @@ jobs: STUDIO_URL="http://localhost:5317/#project/inline-text-caret" \ EVIDENCE_DIR=/tmp/inline-text-caret \ node packages/studio/tests/e2e/inline-text-caret.mjs + - name: Install ffmpeg for the paused-video fixture + if: success() || failure() + uses: ./.github/actions/install-ffmpeg-linux + - name: Undo while paused videos hold the preview's sockets + # Counts the undo's wait for a socket, not its total time: unpinned it is 0 ms. + if: success() || failure() + run: | + set -euo pipefail + NODE_ENV=production bun run --cwd packages/studio dev -- --port 5318 --strictPort & + SERVER_PID=$! + trap 'kill "$SERVER_PID" 2>/dev/null || true' EXIT + for i in $(seq 1 60); do + if curl -sf "http://localhost:5318/" >/dev/null 2>&1; then break; fi + sleep 1 + done + if ! curl -sf "http://localhost:5318/" >/dev/null 2>&1; then + echo "FAIL: studio dev server did not start on port 5318" + exit 1 + fi + STUDIO_URL="http://localhost:5318/#project/undo-socket-pool" \ + STUDIO_PROJECT_DIR="$PWD/packages/studio/data/projects/undo-socket-pool" \ + node packages/studio/tests/e2e/undo-socket-pool.mjs | tee /tmp/undo-socket-pool.json - name: Upload gate evidence # The gate's whole output is machine-readable evidence, and a red run is # exactly when someone needs to read it. Keep it on failure too. @@ -1011,6 +1035,7 @@ jobs: /tmp/timeline-gate-*.json /tmp/studio-open-counts.json /tmp/inline-text-caret/*.png + /tmp/undo-socket-pool.json if-no-files-found: error # Manual editing accuracy in the built Studio, gated against the base branch's baseline.json. diff --git a/.oxlintrc.json b/.oxlintrc.json index c9ef018f3f6..243863419b8 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -45,6 +45,45 @@ "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" } + }, + { + "files": ["packages/studio/src/**/*.ts", "packages/studio/src/**/*.tsx"], + "excludeFiles": [ + "**/*.test.ts", + "**/*.test.tsx", + "**/*TestUtils.ts", + "**/*TestUtils.tsx", + "**/*TestHarness.ts", + "**/*TestHarness.tsx", + "packages/studio/src/utils/studioApiFetch.ts" + ], + "rules": { + "no-restricted-globals": [ + "error", + { + "name": "fetch", + "message": "Use studioApiFetch (utils/studioApiFetch.ts): it keeps Studio's requests off the preview media's sockets." + } + ], + "no-restricted-properties": [ + "error", + { + "object": "window", + "property": "fetch", + "message": "Use studioApiFetch (utils/studioApiFetch.ts): it keeps Studio's requests off the preview media's sockets." + }, + { + "object": "globalThis", + "property": "fetch", + "message": "Use studioApiFetch (utils/studioApiFetch.ts): it keeps Studio's requests off the preview media's sockets." + }, + { + "object": "self", + "property": "fetch", + "message": "Use studioApiFetch (utils/studioApiFetch.ts): it keeps Studio's requests off the preview media's sockets." + } + ] + } } ] } diff --git a/docs/packages/studio-server.mdx b/docs/packages/studio-server.mdx index b8d4f9765e0..640e199f276 100644 --- a/docs/packages/studio-server.mdx +++ b/docs/packages/studio-server.mdx @@ -35,6 +35,18 @@ export function mountStudioApi( } ``` +When it is served from loopback (`localhost`, `127.0.0.1` or `[::1]`), Studio +sends its API requests without cookies, so they don't queue behind the +preview's media. On any other origin it sends them as usual, so remote and +proxied setups (Codespaces, tunnels, an access proxy) keep their cookies by +default. A loopback host that authenticates its mounted API with same-origin +cookies sets `VITE_STUDIO_API_SAME_ORIGIN_CREDENTIALS=true`, at build time or at +runtime in `window.__HF_STUDIO_ENV__`; it costs that host the connection +speedup. +Studio reads the flag once, when its modules load, so set +`window.__HF_STUDIO_ENV__` before loading Studio; the CLI injects it, but a host +that mounts the API itself must inject it too. + A `StudioApiAdapter` supplies: - project listing and resolution; diff --git a/packages/parsers/src/gsapParserAcorn.ts b/packages/parsers/src/gsapParserAcorn.ts index f4d1f3956cb..7ca9187384b 100644 --- a/packages/parsers/src/gsapParserAcorn.ts +++ b/packages/parsers/src/gsapParserAcorn.ts @@ -1903,7 +1903,7 @@ export function parseGsapScriptAcornForWrite(script: string): ParsedGsapAcornFor tweenCallToAnimation(call, scope, script, identifierBindings), ); applyTimelineDefaults(rawAnims, detection.defaults); - resolveTimelinePositions(rawAnims); + resolveTimelinePositions(rawAnims, collectAddLabelDefs(ast, ref, scope, calls)); const animations = assignStableIds(rawAnims); const located = calls.map((call, i) => ({ id: animations[i]!.id, diff --git a/packages/parsers/src/gsapWriter.acorn.test.ts b/packages/parsers/src/gsapWriter.acorn.test.ts index d32cf2f00e5..880bb17dd3e 100644 --- a/packages/parsers/src/gsapWriter.acorn.test.ts +++ b/packages/parsers/src/gsapWriter.acorn.test.ts @@ -13,6 +13,7 @@ import { copyAnimationsInScript, removeAnimationFromScript, removeKeyframeFromScript, + replaceTweenWithKeyframesInScript, updateAnimationInScript, updateKeyframeInScript, } from "./gsapWriterAcorn.js"; @@ -535,3 +536,60 @@ tl.from("#goodbye", { opacity: 0 }, 1);`; expect(copyAnimationsInScript(script, "#tag", "#tag-2", 3)).toBe(script); }); }); + +describe("replaceTweenWithKeyframesInScript", () => { + const script = `var tl = gsap.timeline({ paused: true }); +tl.fromTo("#a", { x: 0 }, { x: 100, duration: 1, delay: 0.5, onStart: go }, 1); +tl.set("#b", { x: 5 }, 0);`; + const tweenOn = (selector: string) => + parseGsapScriptAcorn(script).animations.find((a) => a.targetSelector === selector)!; + const edit = (position: number, extra = {}) => ({ + targetSelector: "#a", + position, + duration: 2, + keyframes: [ + { percentage: 100, properties: { x: 100 } }, + { percentage: 0, properties: { x: 0 } }, + ], + ...extra, + }); + const rewritten = (out: string | null) => out?.split("\n")[1]; + + it("leaves a tween it cannot find, or a set(), to the caller", () => { + expect(replaceTweenWithKeyframesInScript(script, "#missing", edit(1))).toBeNull(); + expect(replaceTweenWithKeyframesInScript(script, tweenOn("#b").id, edit(0))).toBeNull(); + }); + + it("rewrites a tween that stays put as to(), keeping its position, delay and callbacks", () => { + const { id, resolvedStart } = tweenOn("#a"); + expect(rewritten(replaceTweenWithKeyframesInScript(script, id, edit(resolvedStart!)))).toBe( + 'tl.to("#a", { keyframes: { "0%": { x: 0 }, "100%": { x: 100 } }, delay: 0.5, onStart: go, duration: 2 }, 1);', + ); + }); + + it("moves a retargeted tween to the new position without its delay, with the edit's ease", () => { + const out = replaceTweenWithKeyframesInScript( + script, + tweenOn("#a").id, + edit(3, { targetSelector: "#c", ease: "none", easeEach: "power1.in" }), + ); + expect(rewritten(out)).toBe( + 'tl.to("#c", { keyframes: { "0%": { x: 0 }, "100%": { x: 100 }, easeEach: "power1.in" }, onStart: go, duration: 2, ease: "none" }, 3);', + ); + }); +}); + +describe("position argument", () => { + it("is added after the last argument, so a call with a trailing comma stays valid", () => { + const script = `var tl = gsap.timeline({ paused: true }); +tl.to( + "#a", + { x: 100, duration: 1 }, +); +window.__timelines["t"] = tl;`; + const id = parseGsapScriptAcorn(script).animations[0]!.id; + const result = updateAnimationInScript(script, id, { position: 0.5 }); + expect(() => new Function("gsap", "window", result)).not.toThrow(); + expect(parseGsapScriptAcorn(result).animations[0]!.position).toBe(0.5); + }); +}); diff --git a/packages/parsers/src/gsapWriterAcorn.ts b/packages/parsers/src/gsapWriterAcorn.ts index 8077725bb97..bcc347fd7fa 100644 --- a/packages/parsers/src/gsapWriterAcorn.ts +++ b/packages/parsers/src/gsapWriterAcorn.ts @@ -443,7 +443,8 @@ function overwritePosition(ms: MagicString, call: TweenCallInfo, position: numbe if (call.positionArg) { ms.overwrite(call.positionArg.start, call.positionArg.end, valueToCode(position)); } else { - ms.appendLeft(call.node.end - 1, `, ${valueToCode(position)}`); + const last = call.node.arguments.at(-1); + ms.appendLeft(last ? last.end : call.node.end - 1, `, ${valueToCode(position)}`); } } @@ -1790,6 +1791,54 @@ export function materializeKeyframesFromScript( return ms.toString(); } +/** + * Rewrites a tween as `to()` with these keyframes where it stands: the call keeps its place in the + * script and its position argument, so a tween placed after it ('>', '<', '+=', none) stays put. + */ +export function replaceTweenWithKeyframesInScript( + script: string, + animationId: string, + edit: { + targetSelector: string; + position: number; + duration: number; + keyframes: Array<{ + percentage: number; + properties: Record; + ease?: string; + auto?: boolean; + }>; + ease?: string; + easeEach?: string; + }, +): string | null { + const parsed = parseGsapScriptAcornForWrite(script); + const target = parsed?.located.find((l) => l.id === animationId); + const call = target?.call; + if (!target || call?.varsArg?.type !== "ObjectExpression") return null; + const { animation } = target; + if (animation.method !== "to" && animation.method !== "from" && animation.method !== "fromTo") + return null; + const ms = new MagicString(script); + const start = animation.resolvedStart ?? animation.position; + const moved = typeof start !== "number" || Math.abs(start - edit.position) > 5e-4; + const kept = preservedVarsEntries(call.varsArg, script).filter( + (e) => !/^\s*duration\s*:/.test(e) && !(moved && /^\s*delay\s*:/.test(e)), + ); + const sorted = [...edit.keyframes].sort((a, b) => a.percentage - b.percentage); + const parts = [`keyframes: ${buildKeyframeObjectCode(sorted, edit.easeEach)}`, ...kept]; + parts.push(`duration: ${valueToCode(edit.duration)}`); + if (edit.ease) parts.push(`ease: ${JSON.stringify(edit.ease)}`); + if (animation.hasUnresolvedSelector || animation.targetSelector !== edit.targetSelector) { + const selectorArg = call.node.arguments[0]; + ms.overwrite(selectorArg.start, selectorArg.end, JSON.stringify(edit.targetSelector)); + } + convertMethodToTo(ms, animation, call, call.varsArg); + overwriteVarsArg(ms, call, `{ ${parts.join(", ")} }`); + if (moved) overwritePosition(ms, call, edit.position); + return ms.toString(); +} + // ── Add animation with keyframes ────────────────────────────────────────────── /** Insert a new keyframed `to()` call and return the new animation ID. */ diff --git a/packages/studio-server/src/routes/files.patchRace.test.ts b/packages/studio-server/src/routes/files.patchRace.test.ts index c03862028fa..43122c516b6 100644 --- a/packages/studio-server/src/routes/files.patchRace.test.ts +++ b/packages/studio-server/src/routes/files.patchRace.test.ts @@ -14,6 +14,7 @@ import { Hono } from "hono"; import { afterEach, describe, expect, it, vi } from "vitest"; import { fileContentVersion, identifyFileWrite } from "../helpers/fileVersion"; import { registerFileRoutes } from "./files"; +import { stubAdapter } from "./stubAdapter.test-helpers"; const hooks = vi.hoisted(() => ({ transforming: undefined as (() => void) | undefined, @@ -76,15 +77,7 @@ function project() { const path = join(dir, "index.html"); writeFileSync(path, ORIGINAL); const app = new Hono(); - registerFileRoutes(app, { - listProjects: () => [], - resolveProject: async (id: string) => ({ id, dir }), - bundle: async () => null, - lint: async () => ({ findings: [] }), - runtimeUrl: "/api/runtime.js", - rendersDir: () => "/tmp/renders", - startRender: () => ({ id: "job", status: "rendering", progress: 0, outputPath: "/tmp/o.mp4" }), - }); + registerFileRoutes(app, stubAdapter(dir)); const post = (route: string, body: unknown) => app.request(`http://localhost/projects/demo/file-mutations/${route}`, { method: "POST", diff --git a/packages/studio-server/src/routes/files.replaceInPlace.test.ts b/packages/studio-server/src/routes/files.replaceInPlace.test.ts new file mode 100644 index 00000000000..26ee3ea8701 --- /dev/null +++ b/packages/studio-server/src/routes/files.replaceInPlace.test.ts @@ -0,0 +1,146 @@ +// @vitest-environment node +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { Hono } from "hono"; +import { afterEach, describe, expect, it } from "vitest"; +import { registerFileRoutes } from "./files"; +import { stubAdapter } from "./stubAdapter.test-helpers"; + +const dirs: string[] = []; +afterEach(() => { + for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }); +}); + +interface Anim { + id: string; + targetSelector: string; + resolvedStart?: number; + method: string; +} + +const notHold = (a: Anim) => a.method !== "set"; + +function app(script: string): Hono { + const dir = mkdtempSync(join(tmpdir(), "hf-replace-in-place-")); + dirs.push(dir); + const html = ` +
+ +`; + writeFileSync(join(dir, "comp.html"), html); + const hono = new Hono(); + registerFileRoutes(hono, stubAdapter(dir)); + return hono; +} + +async function animations(hono: Hono): Promise { + const res = await hono.request("http://localhost/projects/demo/gsap-animations/comp.html"); + return ((await res.json()) as { animations: Anim[] }).animations; +} + +// The script's calls, without the hold sets the server keeps before a first position keyframe. +const calls = (code: string) => + code.split("\n").filter((line) => line.startsWith("tl.") && !line.includes("hf-hold")); + +/** A move on `selector` at the playhead, sent the way the playhead writer sends it. */ +async function moveAtPlayhead(script: string, selector: string) { + const hono = app(script); + const before = await animations(hono); + const edited = before.find((a) => a.targetSelector === selector)!; + const res = await hono.request("http://localhost/projects/demo/gsap-mutations/comp.html", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + type: "replace-with-keyframes", + animationId: edited.id, + targetSelector: selector, + position: edited.resolvedStart, + duration: 1, + keyframes: [ + { percentage: 0, properties: { x: 0 } }, + { percentage: 50, properties: { x: 40 } }, + { percentage: 100, properties: { x: 100 } }, + ], + easeEach: "none", + }), + }); + const { after: html } = (await res.json()) as { after: string }; + const after = await animations(hono); + const starts = (list: Anim[]) => list.map((a) => [a.targetSelector, a.resolvedStart]); + return { html, starts: starts(after.filter(notHold)), was: starts(before) }; +} + +describe("an edit at the playhead rewrites its tween where it stands", () => { + it.each([ + [ + "no position argument", + `tl.to("#a", { x: 100, duration: 1 });\ntl.to("#b", { y: 50, duration: 1 });`, + ], + [ + "'<' and '+='", + `tl.to("#a", { x: 100, duration: 1 }, 1);\ntl.to("#b", { y: 50, duration: 1 }, "<");\ntl.to("#c", { y: 9, duration: 1 }, "+=0.5");`, + ], + [ + "'>'", + `tl.to("#a", { x: 100, duration: 1 }, 0.5);\ntl.to("#b", { y: 50, duration: 1 }, ">");`, + ], + [ + "a label", + `tl.addLabel("intro", 2);\ntl.to("#a", { x: 100, duration: 1 }, "intro");\ntl.to("#b", { y: 50, duration: 1 }, "intro+=0.5");`, + ], + [ + "a from() entrance", + `tl.from("#a", { x: -60, duration: 1 });\ntl.to("#b", { y: 50, duration: 1 });`, + ], + ])("leaves every other tween's source and start alone after %s", async (_, script) => { + const { html, starts, was } = await moveAtPlayhead(script, "#a"); + + expect(starts).toEqual(was); + const others = calls(script).filter((line) => !line.includes('"#a"')); + expect(calls(html).filter((line) => !line.includes('"#a"'))).toEqual(others); + expect(calls(html).findIndex((line) => line.includes('"#a"'))).toBe( + calls(script).findIndex((line) => line.includes('"#a"')), + ); + }); + + it("keeps a chained call's next link in place", async () => { + const script = `tl.to("#a", { x: 100, duration: 1 }).to("#b", { y: 50, duration: 1 });`; + const { html, starts, was } = await moveAtPlayhead(script, "#a"); + + expect(starts).toEqual(was); + expect(calls(html)).toHaveLength(1); + expect(calls(html)[0]).toMatch( + /^tl\.to\("#a", \{ keyframes: .*\}\)\.to\("#b", \{ y: 50, duration: 1 \}\);$/, + ); + }); + + it.each([ + [ + "a relative one", + `tl.to("#b", { y: 50, duration: 1 }, 0);\ntl.to("#a", { x: 100, duration: 1 }, "<");`, + `"<");`, + ], + [ + "a label", + `tl.addLabel("intro", 2);\ntl.to("#a", { x: 100, duration: 1 }, "intro");`, + `"intro");`, + ], + [ + "the last tween's number", + `tl.to("#b", { y: 50, duration: 1 }, 0);\ntl.to("#a", { x: 100, duration: 1 }, 1);`, + `}, 1);`, + ], + ])("keeps the edited tween's own position argument when it is %s", async (_, script, tail) => { + const { html, starts, was } = await moveAtPlayhead(script, "#a"); + + expect(starts).toEqual(was); + const edited = calls(html).find((line) => line.includes('"#a"'))!; + expect(edited.endsWith(tail)).toBe(true); + expect(calls(html).indexOf(edited)).toBe(calls(script).findIndex((l) => l.includes('"#a"'))); + }); +}); diff --git a/packages/studio-server/src/routes/files.ts b/packages/studio-server/src/routes/files.ts index 9202fd74fa6..4f0321d70e2 100644 --- a/packages/studio-server/src/routes/files.ts +++ b/packages/studio-server/src/routes/files.ts @@ -71,6 +71,7 @@ import { addMotionPathToScript, removeArcPathFromScript, addAnimationWithKeyframesToScript, + replaceTweenWithKeyframesInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, shiftPositionsInScript, @@ -1299,6 +1300,25 @@ export type GsapMutationRequest = type GsapMutationResult = string | { script: string; skippedSelectors: string[] }; +function replaceInPlaceUnlessSetOrUnknown( + scriptText: string, + body: Extract, +): string { + const edit = { ...body, easeEach: resolveReplacementEaseEach(scriptText, body) }; + const inPlace = replaceTweenWithKeyframesInScript(scriptText, body.animationId, edit); + if (inPlace !== null) return inPlace; + const script = removeAnimationFromScript(scriptText, body.animationId); + return addAnimationWithKeyframesToScript( + script, + body.targetSelector, + body.position, + body.duration, + body.keyframes, + body.ease, + edit.easeEach, + ).script; +} + function resolveReplacementEaseEach( scriptText: string, request: { animationId: string; easeEach?: string }, @@ -1779,17 +1799,7 @@ function executeGsapMutationAcorn( if (keyframesWritePosition(body.keyframes) || keyframesWriteRotation(body.keyframes)) { stripStudioEditsFromTarget(block.document, body.targetSelector); } - const script = removeAnimationFromScript(block.scriptText, body.animationId); - const added = addAnimationWithKeyframesToScript( - script, - body.targetSelector, - body.position, - body.duration, - body.keyframes, - body.ease, - resolveReplacementEaseEach(block.scriptText, body), - ); - return added.script; + return replaceInPlaceUnlessSetOrUnknown(block.scriptText, body); } case "split-animations": { if ( @@ -2151,17 +2161,7 @@ async function executeGsapMutationRecast( if (keyframesWritePosition(body.keyframes) || keyframesWriteRotation(body.keyframes)) { stripStudioEditsFromTarget(block.document, body.targetSelector); } - const script = removeAnimationFromScript(block.scriptText, body.animationId); - const added = addAnimationWithKeyframesToScript( - script, - body.targetSelector, - body.position, - body.duration, - body.keyframes, - body.ease, - resolveReplacementEaseEach(block.scriptText, body), - ); - return added.script; + return replaceInPlaceUnlessSetOrUnknown(block.scriptText, body); } case "split-animations": { if ( diff --git a/packages/studio-server/src/routes/freezeFrame.test.ts b/packages/studio-server/src/routes/freezeFrame.test.ts index a123ebbb546..33de1ff550b 100644 --- a/packages/studio-server/src/routes/freezeFrame.test.ts +++ b/packages/studio-server/src/routes/freezeFrame.test.ts @@ -5,7 +5,7 @@ import { tmpdir } from "node:os"; import { basename, dirname, join } from "node:path"; import { registerFreezeFrameRoutes, type FrameExtractor } from "./freezeFrame"; import { fileContentVersion } from "../helpers/fileVersion"; -import type { StudioApiAdapter } from "../types"; +import { stubAdapter } from "./stubAdapter.test-helpers"; const tempDirs: string[] = []; afterEach(() => { @@ -25,17 +25,8 @@ function setup( tempDirs.push(dir); mkdirSync(dirname(join(dir, file.path)), { recursive: true }); writeFileSync(join(dir, file.path), file.html); - const adapter: StudioApiAdapter = { - listProjects: () => [], - resolveProject: async (id: string) => ({ id, dir }), - bundle: async () => null, - lint: async () => ({ findings: [] }), - runtimeUrl: "/api/runtime.js", - rendersDir: () => "/tmp/renders", - startRender: () => ({ id: "j", status: "rendering", progress: 0, outputPath: "/tmp/o.mp4" }), - }; const app = new Hono(); - registerFreezeFrameRoutes(app, adapter, extract, stillToken); + registerFreezeFrameRoutes(app, stubAdapter(dir), extract, stillToken); const post = (body: unknown) => app.request("http://localhost/projects/demo/file-mutations/freeze-frame", { method: "POST", diff --git a/packages/studio-server/src/routes/peaks.test.ts b/packages/studio-server/src/routes/peaks.test.ts index 748a924f3b6..b4986fd72fd 100644 --- a/packages/studio-server/src/routes/peaks.test.ts +++ b/packages/studio-server/src/routes/peaks.test.ts @@ -4,7 +4,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { registerPeakRoutes } from "./peaks"; -import type { StudioApiAdapter } from "../types"; +import { stubAdapter } from "./stubAdapter.test-helpers"; const dirs: string[] = []; afterEach(() => { @@ -15,17 +15,8 @@ function setup(decode: (path: string) => Promise) { const dir = mkdtempSync(join(tmpdir(), "hf-peaks-route-")); dirs.push(dir); writeFileSync(join(dir, "talk.mp4"), "video"); - const adapter: StudioApiAdapter = { - listProjects: () => [], - resolveProject: async (id: string) => ({ id, dir }), - bundle: async () => null, - lint: async () => ({ findings: [] }), - runtimeUrl: "/api/runtime.js", - rendersDir: () => "/tmp/renders", - startRender: () => ({ id: "j", status: "rendering", progress: 0, outputPath: "/tmp/o.mp4" }), - }; const app = new Hono(); - registerPeakRoutes(app, adapter, decode); + registerPeakRoutes(app, stubAdapter(dir), decode); return app; } diff --git a/packages/studio-server/src/routes/stubAdapter.test-helpers.ts b/packages/studio-server/src/routes/stubAdapter.test-helpers.ts new file mode 100644 index 00000000000..b5e9004480d --- /dev/null +++ b/packages/studio-server/src/routes/stubAdapter.test-helpers.ts @@ -0,0 +1,14 @@ +import type { StudioApiAdapter } from "../types"; + +/** An adapter that resolves every project id to `dir` and stubs the rest. */ +export function stubAdapter(dir: string): StudioApiAdapter { + return { + listProjects: () => [], + resolveProject: async (id: string) => ({ id, dir }), + bundle: async () => null, + lint: async () => ({ findings: [] }), + runtimeUrl: "/api/runtime.js", + rendersDir: () => "/tmp/renders", + startRender: () => ({ id: "j", status: "rendering", progress: 0, outputPath: "/tmp/o.mp4" }), + }; +} diff --git a/packages/studio/src/captions/hooks/useCaptionSync.ts b/packages/studio/src/captions/hooks/useCaptionSync.ts index 0523ab4e8f3..1c9c44b58e3 100644 --- a/packages/studio/src/captions/hooks/useCaptionSync.ts +++ b/packages/studio/src/captions/hooks/useCaptionSync.ts @@ -5,6 +5,7 @@ import { useMountEffect } from "../../hooks/useMountEffect"; import { trackEvent } from "../../telemetry/client"; import type { CaptionStyle } from "../types"; import { studioWriteHeaders } from "../../utils/studioFileVersion"; +import { studioApiFetch } from "../../utils/studioApiFetch"; interface CaptionOverrideEntry { wordId?: string; @@ -93,11 +94,14 @@ export function useCaptionSync(projectId: string | null) { const seqAtSave = editSeqRef.current; const overrides = buildOverrides(state.model); - fetch(buildProjectApiPath(pid, `/files/${encodeURIComponent("caption-overrides.json")}`), { - method: "PUT", - headers: { "Content-Type": "text/plain", ...studioWriteHeaders() }, - body: JSON.stringify(overrides, null, 2), - }) + studioApiFetch( + buildProjectApiPath(pid, `/files/${encodeURIComponent("caption-overrides.json")}`), + { + method: "PUT", + headers: { "Content-Type": "text/plain", ...studioWriteHeaders() }, + body: JSON.stringify(overrides, null, 2), + }, + ) .then((res) => { if (!res.ok) throw new Error(`HTTP ${res.status}`); // A newer edit may have re-armed the debounce while this PUT was in @@ -171,7 +175,7 @@ export function useCaptionSync(projectId: string | null) { let data: { content?: string }; try { - const res = await fetch( + const res = await studioApiFetch( buildProjectApiPath(pid, `/files/${encodeURIComponent("caption-overrides.json")}`), ); if (!res.ok) return; // no overrides file yet — normal diff --git a/packages/studio/src/components/ProjectUnreachableBanner.tsx b/packages/studio/src/components/ProjectUnreachableBanner.tsx index b51be2e2e07..dd7eaeb21af 100644 --- a/packages/studio/src/components/ProjectUnreachableBanner.tsx +++ b/packages/studio/src/components/ProjectUnreachableBanner.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface ServedProject { id: string; @@ -24,8 +25,7 @@ interface ProjectUnreachableBannerProps { * * The wording is deliberately narrower than "this project is gone". We can see * which project this server serves; we cannot see why it does not serve this - * one, and nothing here is lost. See - * `docs/hyperframes/plans/sdk/2026-09-20-stale-project-id-remaining-doors-plan.md` §C. + * one, and nothing here is lost. */ export function ProjectUnreachableBanner({ projectId }: ProjectUnreachableBannerProps) { const [served, setServed] = useState(null); @@ -35,7 +35,7 @@ export function ProjectUnreachableBanner({ projectId }: ProjectUnreachableBanner // A list we could not read is not evidence of anything, so a failed fetch // leaves `served` empty and the banner falls back to the vague wording // rather than claiming this Studio serves nothing. - fetch("/api/projects") + studioApiFetch("/api/projects") .then((res) => (res.ok ? res.json() : { projects: [] })) .then((data: { projects?: ServedProject[] }) => { if (!cancelled) setServed(data.projects ?? []); diff --git a/packages/studio/src/components/editor/domGroupMoveBy.test.tsx b/packages/studio/src/components/editor/domGroupMoveBy.test.tsx new file mode 100644 index 00000000000..c7e82da95d4 --- /dev/null +++ b/packages/studio/src/components/editor/domGroupMoveBy.test.tsx @@ -0,0 +1,252 @@ +// @vitest-environment happy-dom +import { act } from "react"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import type { DomEditSelection } from "./domEditingTypes"; +import type { DomEditGroupPathOffsetCommit } from "./domEditOverlayGestures"; +import { STUDIO_OFFSET_X_PROP, STUDIO_OFFSET_Y_PROP } from "./manualEdits"; +import { isStudioManualEditGestureLiveIn } from "./manualEditsDom"; +import { readTranslatePx } from "./plainTranslate"; +import { moveDomGroupBy } from "./domGroupMoveBy"; +import { GsapEditBlockedError } from "../../hooks/gsapEditOutcome"; + +Reflect.set(globalThis, "IS_REACT_ACT_ENVIRONMENT", true); + +const mocks = vi.hoisted(() => ({ drag: vi.fn() })); +vi.mock("../../hooks/gsapRuntimeBridge", () => ({ + tryGsapDragIntercept: mocks.drag, + tryGsapRotationIntercept: vi.fn(), +})); +vi.mock("../../hooks/useAnimatedPropertyCommit", () => ({ + useAnimatedPropertyCommit: () => ({ + commitAnimatedProperty: vi.fn(), + commitAnimatedProperties: vi.fn(), + }), +})); +vi.mock("../../hooks/useSafeGsapCommitMutation", () => ({ + useGsapSaveFailureTelemetry: () => vi.fn(), + useSafeGsapCommitMutation: (commit: unknown) => commit, +})); +vi.mock("../../utils/studioSaveDiagnostics", async (importOriginal) => ({ + ...(await importOriginal()), + trackStudioEditBlocked: vi.fn(), + trackStudioSaveFailure: vi.fn(), +})); + +import { mountGsapAwareEditing } from "../../hooks/useGsapAwareEditing.testHelpers"; + +afterEach(() => { + vi.clearAllMocks(); + document.body.innerHTML = ""; +}); + +/** A preview iframe drawn at half size: 200x100 composition px in a 100x50 box. */ +function preview(): Document { + const iframe = document.createElement("iframe"); + document.body.append(iframe); + const win = iframe.contentWindow!; + Object.defineProperty(win, "frameElement", { configurable: true, value: iframe }); + Object.defineProperty(win, "innerWidth", { configurable: true, value: 200 }); + Object.defineProperty(win, "innerHeight", { configurable: true, value: 100 }); + iframe.getBoundingClientRect = () => new DOMRect(50, 40, 100, 50); + return iframe.contentDocument!; +} + +const turned = (deg: number, scale: number) => { + const r = (deg * Math.PI) / 180; + return [scale * Math.cos(r), scale * Math.sin(r), -scale * Math.sin(r), scale * Math.cos(r)]; +}; + +/** An element whose box centre is `at` plus its own move carried through its ancestors' linear map. */ +function layer(doc: Document, id: string, parent = [1, 0, 0, 1], gsap?: object) { + const element = Object.assign(doc.createElement("div"), gsap ? { _gsap: gsap } : {}); + doc.body.append(element); + const own = () => { + if (!gsap) return readTranslatePx(element); + const read = (prop: string) => Number.parseFloat(element.style.getPropertyValue(prop)) || 0; + return { x: read(STUDIO_OFFSET_X_PROP), y: read(STUDIO_OFFSET_Y_PROP) }; + }; + element.getBoundingClientRect = () => { + const { x, y } = own(); + const [a, b, c, d] = parent as [number, number, number, number]; + return new DOMRect(60 + a * x + c * y - 20, 40 + b * x + d * y - 10, 40, 20); + }; + const selection = { + element, + id, + selector: `#${id}`, + label: id, + capabilities: { canApplyManualOffset: true }, + } as unknown as DomEditSelection; + const centre = () => { + const r = element.getBoundingClientRect(); + return { x: r.left + r.width / 2, y: r.top + r.height / 2 }; + }; + return { element, selection, centre }; +} + +function mountGroupCommit() { + const showToast = vi.fn(); + const save = vi.fn().mockResolvedValue(undefined); + const stageElementPositionOffset = vi.fn(() => ({ save, rollback: vi.fn() })); + const { editing, root } = mountGsapAwareEditing({ showToast, stageElementPositionOffset }); + const commit = (u: DomEditGroupPathOffsetCommit[], o?: { refusalToast?: boolean }) => + editing().handleGsapAwareGroupPathOffsetCommit(u, o); + const moveBy = (moves: Parameters[0]) => + act(() => moveDomGroupBy(moves, (u) => commit(u, { refusalToast: false }))); + return { + commit: (u: DomEditGroupPathOffsetCommit[]) => commit(u), + moveBy, + showToast, + stageElementPositionOffset, + root, + }; +} + +const moved = (from: { x: number; y: number }, to: { x: number; y: number }) => ({ + x: to.x - from.x, + y: to.y - from.y, +}); + +describe("handleDomGroupMoveBy", () => { + it("moves each box by its delta in composition px, saved under one undo entry", async () => { + const doc = preview(); + const offset = layer(doc, "offset"); + offset.element.style.setProperty("translate", "30px 0px"); + const halved = layer(doc, "halved", [0.5, 0, 0, 0.5]); + const before = [offset.centre(), halved.centre()]; + const { moveBy, stageElementPositionOffset, showToast, root } = mountGroupCommit(); + + await moveBy([ + { selection: offset.selection, delta: { x: 10, y: 0 } }, + { selection: halved.selection, delta: { x: 0, y: -5 } }, + ]); + + expect(moved(before[0]!, offset.centre())).toEqual({ x: 10, y: 0 }); + expect(moved(before[1]!, halved.centre())).toEqual({ x: 0, y: -5 }); + const calls = stageElementPositionOffset.mock.calls as unknown as unknown[][]; + expect(calls.map((call) => call[1])).toEqual([ + { x: 40, y: 0 }, + { x: 0, y: -10 }, + ]); + expect(calls[0]![3]).toMatch(/^group-drag:\d+$/); + expect(calls[1]![3]).toBe(calls[0]![3]); + expect(showToast).not.toHaveBeenCalled(); + expect(isStudioManualEditGestureLiveIn(doc)).toBe(false); + act(() => root.unmount()); + }); + + it("lands exactly under a half-scale parent with a rotated ancestor", async () => { + const doc = preview(); + const tilted = layer(doc, "tilted", turned(30, 0.5)); + const before = tilted.centre(); + const { moveBy, root } = mountGroupCommit(); + + await moveBy([{ selection: tilted.selection, delta: { x: 10, y: 0 } }]); + + const delta = moved(before, tilted.centre()); + // Exact to the 0.001 px a translate is written with. + expect(delta.x).toBeCloseTo(10, 3); + expect(delta.y).toBeCloseTo(0, 3); + act(() => root.unmount()); + }); + + it("moves a member GSAP positions through the GSAP write, planned and written at one delta", async () => { + mocks.drag.mockResolvedValue({ status: "persisted" }); + const doc = preview(); + const animated = layer(doc, "animated", [1, 0, 0, 1], { renderTransform: () => {} }); + const before = animated.centre(); + const { moveBy, stageElementPositionOffset, root } = mountGroupCommit(); + + await moveBy([{ selection: animated.selection, delta: { x: 10, y: 0 } }]); + + const write = mocks.drag.mock.calls.find((call) => !call[6]?.preflightOnly); + expect(write?.[0]).toBe(animated.selection); + expect(write?.[1]).toEqual({ x: 10, y: 0 }); + const plan = mocks.drag.mock.calls.find((call) => call[6]?.preflightOnly); + expect(plan?.[1]).toEqual(write?.[1]); + expect(moved(before, animated.centre())).toEqual({ x: 10, y: 0 }); + expect(stageElementPositionOffset).not.toHaveBeenCalled(); + act(() => root.unmount()); + }); + + it("skips a zero delta, and writes nothing when every delta is zero", async () => { + const doc = preview(); + const still = layer(doc, "still"); + const { moveBy, stageElementPositionOffset, root } = mountGroupCommit(); + + await moveBy([{ selection: still.selection, delta: { x: 0, y: 0 } }]); + + expect(stageElementPositionOffset).not.toHaveBeenCalled(); + act(() => root.unmount()); + }); + + it.each([ + [ + "a member that can't take a manual move", + (doc: Document) => { + const locked = layer(doc, "locked"); + Object.assign(locked.selection.capabilities, { + canApplyManualOffset: false, + reasonIfDisabled: "Locked by a helper loop.", + }); + return locked; + }, + /helper loop/, + ], + [ + "a member an animation took over", + (doc: Document) => layer(doc, "folded", [1, 0, 0, 1], { x: "94px" }), + /animation took over/, + ], + [ + "a member the GSAP write refuses", + (doc: Document) => { + mocks.drag.mockResolvedValue({ status: "blocked", reason: "no-selector" }); + return layer(doc, "blocked", [1, 0, 0, 1], { renderTransform: () => {} }); + }, + new GsapEditBlockedError("no-selector").message, + ], + ])("refuses %s before any write, without a Studio toast", async (_, make, reason) => { + const doc = preview(); + const fine = layer(doc, "fine"); + const refused = make(doc); + const before = [fine.centre(), refused.centre()]; + const { moveBy, stageElementPositionOffset, showToast, root } = mountGroupCommit(); + + await expect( + moveBy([ + { selection: fine.selection, delta: { x: 10, y: 0 } }, + { selection: refused.selection, delta: { x: 10, y: 0 } }, + ]), + ).rejects.toThrow(reason); + + expect(stageElementPositionOffset).not.toHaveBeenCalled(); + expect(mocks.drag.mock.calls.some((call) => !call[6]?.preflightOnly)).toBe(false); + expect(showToast).not.toHaveBeenCalled(); + expect([fine.centre(), refused.centre()]).toEqual(before); + expect(isStudioManualEditGestureLiveIn(doc)).toBe(false); + act(() => root.unmount()); + }); + + it.each([ + ["an animation took over", () => layer(preview(), "folded", [1, 0, 0, 1], { x: "94px" }), true], + [ + "the GSAP write refuses", + () => { + mocks.drag.mockResolvedValue({ status: "blocked", reason: "no-selector" }); + return layer(preview(), "blocked", [1, 0, 0, 1], { renderTransform: () => {} }); + }, + false, + ], + ])("still toasts on a canvas group drag when %s", async (_, make, plainTranslate) => { + const { selection } = make(); + const { commit, showToast, root } = mountGroupCommit(); + + await expect( + act(() => commit([{ selection, next: { x: 1, y: 2 }, plainTranslate }])), + ).rejects.toThrow(); + + expect(showToast).toHaveBeenCalledWith(expect.any(String), "error"); + act(() => root.unmount()); + }); +}); diff --git a/packages/studio/src/components/editor/domGroupMoveBy.ts b/packages/studio/src/components/editor/domGroupMoveBy.ts new file mode 100644 index 00000000000..61cb40e7189 --- /dev/null +++ b/packages/studio/src/components/editor/domGroupMoveBy.ts @@ -0,0 +1,95 @@ +import type { DomEditSelection } from "./domEditing"; +import type { DomEditGroupPathOffsetCommit } from "./domEditOverlayGestures"; +import { canCanvasNudgeTargets } from "./domEditNudge"; +import { isStudioManualEditGestureCurrent, restoreStudioPathOffset } from "./manualEdits"; +import { countStudioManualEditSave } from "./manualEditsDom"; +import { + applyManualOffsetDragCommit, + createManualOffsetDragMember, + endManualOffsetDragMembers, + restoreManualOffsetDragMembers, + toTopScreenPoint, + type ManualOffsetDragMember, +} from "./manualOffsetDrag"; + +export interface DomGroupMove { + selection: DomEditSelection; + /** Composition px: the element's box moves by exactly this in the film. */ + delta: { x: number; y: number }; +} + +/** Composition px to the top page's px; the preview frames only scale and shift. */ +function toScreen(doc: Document, delta: { x: number; y: number }) { + const origin = toTopScreenPoint(doc, { x: 0, y: 0 }); + const moved = toTopScreenPoint(doc, delta); + if (!origin || !moved) throw new Error("The preview has no measurable size."); + return { x: moved.x - origin.x, y: moved.y - origin.y }; +} + +function memberFor( + selection: DomEditSelection, + scale: { x: number; y: number }, +): ManualOffsetDragMember { + const { element } = selection; + const box = element.getBoundingClientRect(); + const result = createManualOffsetDragMember({ + key: selection.id ?? selection.selector ?? selection.label, + selection, + element, + rect: { + left: box.left, + top: box.top, + width: box.width, + height: box.height, + editScaleX: scale.x, + editScaleY: scale.y, + }, + gesture: "drag", + }); + if (!result.ok) throw new Error(result.reason); + return result.member; +} + +/** + * Moves each element by its delta as one group drag would drop it: one save, one undo entry. + * Any member that can't move refuses the whole call before anything is drawn or written. + */ +export async function moveDomGroupBy( + moves: DomGroupMove[], + commitGroup: (updates: DomEditGroupPathOffsetCommit[]) => Promise, +): Promise { + const moving = moves.filter(({ delta }) => delta.x !== 0 || delta.y !== 0); + if (moving.length === 0) return; + const selections = moving.map(({ selection }) => selection); + if (!canCanvasNudgeTargets(selections)) { + const blocked = selections.find((s) => !s.capabilities.canApplyManualOffset); + throw new Error(blocked?.capabilities.reasonIfDisabled ?? `${blocked?.label} can't be moved.`); + } + const screens = moving.map(({ selection, delta }) => + toScreen(selection.element.ownerDocument, delta), + ); + const members: ManualOffsetDragMember[] = []; + try { + for (const selection of selections) + members.push(memberFor(selection, toScreen(selection.element.ownerDocument, { x: 1, y: 1 }))); + } catch (error) { + restoreManualOffsetDragMembers(members); + throw error; + } + const updates = members.map((member, index) => ({ + selection: member.selection, + next: applyManualOffsetDragCommit(member, screens[index]!.x, screens[index]!.y), + plainTranslate: member.plainTranslate, + })); + try { + await countStudioManualEditSave(members[0]!.element, () => commitGroup(updates)); + } catch (error) { + for (const member of members) { + if (isStudioManualEditGestureCurrent(member.element, member.gestureToken)) + restoreStudioPathOffset(member.element, member.initialPathOffset); + } + throw error; + } finally { + endManualOffsetDragMembers(members); + } +} diff --git a/packages/studio/src/components/editor/dragUndoPaint.test.ts b/packages/studio/src/components/editor/dragUndoPaint.test.ts index b758109ba96..66693624e39 100644 --- a/packages/studio/src/components/editor/dragUndoPaint.test.ts +++ b/packages/studio/src/components/editor/dragUndoPaint.test.ts @@ -5,7 +5,7 @@ import type { GestureState } from "./domEditOverlayGestures"; import { createDomEditOverlayGestureHandlers } from "./useDomEditOverlayGestures"; import { hasStudioPendingEdits, - revertNewestStudioPendingEdit, + paintBackNewestStudioPendingEdit, } from "../../utils/studioPendingEdits"; afterEach(() => { @@ -59,13 +59,13 @@ it("a drag whose save is still running can be painted back at once, and shown ag const moved = element.style.getPropertyValue("translate"); expect(moved).not.toBe("40px 30px"); - const showAgain = revertNewestStudioPendingEdit(); + const shown = paintBackNewestStudioPendingEdit(); expect(element.style.getPropertyValue("translate")).toBe("40px 30px"); - expect(revertNewestStudioPendingEdit()).toBeNull(); - showAgain!(); + expect(paintBackNewestStudioPendingEdit()).toBeNull(); + shown!.showAgain(); expect(element.style.getPropertyValue("translate")).toBe(moved); saved(); await vi.waitFor(() => expect(hasStudioPendingEdits()).toBe(false)); - expect(revertNewestStudioPendingEdit()).toBeNull(); + expect(paintBackNewestStudioPendingEdit()).toBeNull(); }); diff --git a/packages/studio/src/components/editor/gestureHoldsPreviewReload.test.tsx b/packages/studio/src/components/editor/gestureHoldsPreviewReload.test.tsx index e139ef34d35..b98574d4ea8 100644 --- a/packages/studio/src/components/editor/gestureHoldsPreviewReload.test.tsx +++ b/packages/studio/src/components/editor/gestureHoldsPreviewReload.test.tsx @@ -289,6 +289,39 @@ describe("a drag moves only with its own pointer pressed", () => { ); }); +describe("an outside change during a drag, on a preview that can swap scenes in place", () => { + it("leaves the dragged node in place and shows the change after the drop, loaded fresh", async () => { + const { live, overlay, box } = mountEditor(false); + const swapScenes = vi.fn((html: string) => { + live.contentDocument!.body.innerHTML = html.replace(/^[\s\S]*|<\/body>[\s\S]*$/g, ""); + }); + Object.assign(live.contentWindow!, { __hfSwapScenes: swapScenes }); + vi.stubGlobal( + "fetch", + async () => new Response(served("").contentDocument!.documentElement.outerHTML), + ); + const dragged = byId(live, "title"); + pointer(box, "pointerdown", 150, 150); + pointer(overlay, "pointermove", 190, 170); + + act(() => api().refreshPlayer()); + await settle(); + expect(swapScenes, "swapped under the pointer").not.toHaveBeenCalled(); + expect(byId(live, "title")).toBe(dragged); + const beforeDrop = await paintShadow(api, served("?_t=1")); + expect(api().iframeRef.current, "promoted under the pointer").toBe(live); + + pointer(overlay, "pointerup", 190, 170); + await settle(); + expect(file.title).toBe("translate: 40px 20px"); + const fresh = served("?_t=2"); + expect(await paintShadow(api, fresh)).toBeGreaterThan(beforeDrop); + expect(api().iframeRef.current).toBe(fresh); + expect(byId(fresh, "title").style.getPropertyValue("translate")).toBe("40px 20px"); + vi.unstubAllGlobals(); + }); +}); + type Editor = ReturnType; describe("every way a drag ends without a drop clears its mark and promotes the held reload", () => { diff --git a/packages/studio/src/components/editor/manualEditingAvailability.ts b/packages/studio/src/components/editor/manualEditingAvailability.ts index cc3c806f7a4..dd746b41a7e 100644 --- a/packages/studio/src/components/editor/manualEditingAvailability.ts +++ b/packages/studio/src/components/editor/manualEditingAvailability.ts @@ -78,4 +78,12 @@ export const STUDIO_FLAT_INSPECTOR_ENABLED = resolveStudioBooleanEnvFlag( true, ); +// A host whose mounted API authenticates with same-origin cookies sets this; studioApiFetch then sends them, and its +// requests share the preview media's sockets again. +export const STUDIO_API_SAME_ORIGIN_CREDENTIALS = resolveStudioBooleanEnvFlag( + env, + ["VITE_STUDIO_API_SAME_ORIGIN_CREDENTIALS"], + false, +); + import { resolveEnabledSdkFamilies } from "../../utils/sdkCutoverPolicy"; diff --git a/packages/studio/src/components/editor/manualOffsetDrag.ts b/packages/studio/src/components/editor/manualOffsetDrag.ts index 54fd975ede8..48002d697d5 100644 --- a/packages/studio/src/components/editor/manualOffsetDrag.ts +++ b/packages/studio/src/components/editor/manualOffsetDrag.ts @@ -146,12 +146,12 @@ function getRectCenter(element: HTMLElement): Point | null { return null; } - let point = { - x: rect.left + rect.width / 2, - y: rect.top + rect.height / 2, - }; + const point = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }; + return toTopScreenPoint(element.ownerDocument, point); +} - let win: Window | null = element.ownerDocument.defaultView; +export function toTopScreenPoint(doc: Document, point: Point): Point | null { + let win: Window | null = doc.defaultView; while (win) { const frameElement = getFrameElement(win); if (!frameElement) break; @@ -166,7 +166,6 @@ function getRectCenter(element: HTMLElement): Point | null { }; win = frameElement.ownerDocument.defaultView; } - return point; } diff --git a/packages/studio/src/components/editor/motionPathSelection.test.ts b/packages/studio/src/components/editor/motionPathSelection.test.ts index 35927e38984..8fc2f533b3b 100644 --- a/packages/studio/src/components/editor/motionPathSelection.test.ts +++ b/packages/studio/src/components/editor/motionPathSelection.test.ts @@ -1,41 +1,16 @@ // @vitest-environment jsdom import { afterEach, describe, expect, it } from "vitest"; -import type { DomEditSelection } from "./domEditingTypes"; -import { buildStableSelector, getSelectorIndex } from "./domEditingDom"; +import { mountGroupSiblings, stableSelectionFor } from "../../hooks/domSelectionTestHarness"; import { selectorFor } from "./motionPathSelection"; afterEach(() => { document.body.innerHTML = ""; }); -function selectionFor(el: HTMLElement): DomEditSelection { - const selector = buildStableSelector(el); - return { - element: el, - id: el.id || undefined, - hfId: el.getAttribute("data-hf-id") || undefined, - selector, - selectorIndex: getSelectorIndex(document, el, selector, "index.html", null), - sourceFile: "index.html", - dataAttributes: { start: "0", duration: "2" }, - } as unknown as DomEditSelection; -} - -function mountGroupSiblings(): HTMLElement[] { - document.body.innerHTML = ` -
-
-
-
-
- `; - return Array.from(document.querySelectorAll(".group")); -} - describe("selectorFor", () => { it("addresses one element for a class-only sibling", () => { - const groups = mountGroupSiblings(); - const selector = selectorFor(selectionFor(groups[2]!)); + const groups = mountGroupSiblings(3); + const selector = selectorFor(stableSelectionFor(groups[2]!)); // The bare ".group" both measured home off the FIRST sibling and wrote the // new motion path onto all three. @@ -48,7 +23,7 @@ describe("selectorFor", () => { document.body.innerHTML = `
`; const el = document.querySelector("#hero")!; - expect(selectorFor(selectionFor(el))).toBe("#hero"); + expect(selectorFor(stableSelectionFor(el))).toBe("#hero"); }); it("returns null with no selection", () => { @@ -56,8 +31,8 @@ describe("selectorFor", () => { }); it("returns null when no rung addresses one element", () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[1]!); + const groups = mountGroupSiblings(3); + const selection = stableSelectionFor(groups[1]!); groups[1]!.remove(); expect(selectorFor(selection)).toBeNull(); diff --git a/packages/studio/src/components/editor/probeSourceElement.ts b/packages/studio/src/components/editor/probeSourceElement.ts index 4312e2becb6..4599a320fda 100644 --- a/packages/studio/src/components/editor/probeSourceElement.ts +++ b/packages/studio/src/components/editor/probeSourceElement.ts @@ -1,4 +1,5 @@ import { buildProjectApiPath } from "../../utils/projectRouting"; +import { studioApiFetch } from "../../utils/studioApiFetch"; type ProbeTarget = { id?: string; hfId?: string; selector?: string; selectorIndex?: number }; @@ -12,7 +13,7 @@ const pending = new Map(); async function sendBatch(projectId: string, sourceFile: string, probes: PendingProbe[]) { let exists: boolean[] = []; try { - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath( projectId, `/file-mutations/probe-elements/${encodeURIComponent(sourceFile)}`, diff --git a/packages/studio/src/components/editor/propertyPanelFont.tsx b/packages/studio/src/components/editor/propertyPanelFont.tsx index 071b0296b73..a548f8bea9d 100644 --- a/packages/studio/src/components/editor/propertyPanelFont.tsx +++ b/packages/studio/src/components/editor/propertyPanelFont.tsx @@ -20,6 +20,7 @@ import { } from "./propertyPanelHelpers"; import { useTrackDesignInput } from "../../contexts/DesignPanelInputContext"; import { runWhenInputIdle } from "./overlayFrameLoop"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /* ------------------------------------------------------------------ */ /* Font helper functions */ @@ -135,7 +136,7 @@ let fontListsRequest: Promise | null = null; const fontListListeners = new Set<() => void>(); async function fetchFontList(url: string): Promise { - const data = (await (await fetch(url)).json()) as { fonts?: unknown }; + const data = (await (await studioApiFetch(url)).json()) as { fonts?: unknown }; if (!Array.isArray(data.fonts)) throw new Error(`${url} returned no font list`); return data.fonts as string[]; } @@ -356,7 +357,7 @@ export function FontFamilyField({ const importSystemFont = async (family: string): Promise => { if (!onImportFonts) return null; - const response = await fetch(`/api/fonts/file?family=${encodeURIComponent(family)}`); + const response = await studioApiFetch(`/api/fonts/file?family=${encodeURIComponent(family)}`); if (!response.ok) return null; const blob = await response.blob(); const ext = response.headers.get("Content-Disposition")?.match(/\.(\w+)"?$/)?.[1] ?? "ttf"; diff --git a/packages/studio/src/components/editor/useColorGradingController.ts b/packages/studio/src/components/editor/useColorGradingController.ts index b1a30f29757..162a10968e0 100644 --- a/packages/studio/src/components/editor/useColorGradingController.ts +++ b/packages/studio/src/components/editor/useColorGradingController.ts @@ -29,6 +29,7 @@ import { type ColorGradingPresetPreviews, type ColorGradingPreviewOptions, } from "./useColorGradingPreviews"; +import { studioApiFetch } from "../../utils/studioApiFetch"; export type { ColorGradingPresetPreviews, ColorGradingPreviewOptions }; @@ -290,7 +291,7 @@ export function useColorGradingController({ return; } const controller = new AbortController(); - fetch(cacheKey, { signal: controller.signal }) + studioApiFetch(cacheKey, { signal: controller.signal }) .then(async (response) => { if (!response.ok) return { ok: false as const }; const data: MediaMetadataResponse | null = await response.json(); diff --git a/packages/studio/src/components/editor/useFxCarveNodes.ts b/packages/studio/src/components/editor/useFxCarveNodes.ts index f74e9c532a9..0f1c4321d67 100644 --- a/packages/studio/src/components/editor/useFxCarveNodes.ts +++ b/packages/studio/src/components/editor/useFxCarveNodes.ts @@ -24,6 +24,7 @@ import { import { fxAutomationTarget, type HfAutomationLane } from "@hyperframes/core/audio-automation"; import { clipStart } from "./propertyPanelAudioFxGroupUtils.js"; import { clipAudioOnItsClock, type ClipClock } from "./clipAudioClock.js"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /** Decode rate every carve measurement shares — see `measureCarve`. */ const DECODE_SAMPLE_RATE = 48000; @@ -95,7 +96,7 @@ export async function measureCarve( if (!Ctor) return null; // Each clip as it plays: trimmed to its in-point and duration, and at its own speed. const decode = async (relative: string, clock: ClipClock): Promise => { - const res = await fetch(new URL(relative, doc.baseURI).href); + const res = await studioApiFetch(new URL(relative, doc.baseURI).href); const buffer = await new Ctor(1, 1, DECODE_SAMPLE_RATE).decodeAudioData( await res.arrayBuffer(), ); diff --git a/packages/studio/src/components/editor/useFxLevelling.ts b/packages/studio/src/components/editor/useFxLevelling.ts index d075188455b..351bb4a515b 100644 --- a/packages/studio/src/components/editor/useFxLevelling.ts +++ b/packages/studio/src/components/editor/useFxLevelling.ts @@ -26,6 +26,7 @@ import { trackLeveller } from "./audioFxTelemetry.js"; import type { DomEditSelection } from "./domEditingTypes"; import { clipSourceWindow, readClipClock } from "./clipAudioClock.js"; import { useAuditionTransport } from "./useAuditionTransport.js"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /** * Rate the track is decoded at. Analysis is self-consistent because it reads @@ -63,7 +64,7 @@ export function useFxLevelling( (window as unknown as { webkitOfflineAudioContext?: typeof OfflineAudioContext }) .webkitOfflineAudioContext; if (!Ctor) return null; - const res = await fetch(new URL(src, doc.baseURI).href); + const res = await studioApiFetch(new URL(src, doc.baseURI).href); const buffer = await new Ctor(1, 1, DECODE_SAMPLE_RATE).decodeAudioData( await res.arrayBuffer(), ); diff --git a/packages/studio/src/components/feedback/projectProvenance.ts b/packages/studio/src/components/feedback/projectProvenance.ts index 0dcafc37f0b..d98b6429ed7 100644 --- a/packages/studio/src/components/feedback/projectProvenance.ts +++ b/packages/studio/src/components/feedback/projectProvenance.ts @@ -17,6 +17,7 @@ import { buildProjectApiPath } from "../../utils/projectRouting"; import type { FeedbackContext } from "./feedbackTrigger"; import { isMediaFile } from "../../utils/mediaTypes"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /** Written by `hyperframes init`; absent in a hand-made or copied project. */ const CONFIG_FILE = "hyperframes.json"; @@ -53,7 +54,7 @@ export async function captureProjectProvenance( if (!scaffolded) return; try { - const res = await fetch( + const res = await studioApiFetch( buildProjectApiPath(projectId, `/files/${encodeURIComponent(CONFIG_FILE)}`), ); if (!res.ok) return; diff --git a/packages/studio/src/components/nle/NLEContext.test.ts b/packages/studio/src/components/nle/NLEContext.test.ts index cb59fcdb1bf..591acf3861d 100644 --- a/packages/studio/src/components/nle/NLEContext.test.ts +++ b/packages/studio/src/components/nle/NLEContext.test.ts @@ -126,6 +126,7 @@ describe("NLEProvider — composition source-map scoping", () => { expect(observed.filter((map) => map.size === 0)).toHaveLength(2); expect(fetchMock).toHaveBeenCalledWith("/api/projects/project-b/files/index.html", { signal: expect.any(AbortSignal), + credentials: "omit", }); expect(observed.at(-1)).toEqual(new Map([["b-comp", "compositions/b.html"]])); diff --git a/packages/studio/src/components/nle/NLEContext.tsx b/packages/studio/src/components/nle/NLEContext.tsx index c09ed2735da..9528368c16b 100644 --- a/packages/studio/src/components/nle/NLEContext.tsx +++ b/packages/studio/src/components/nle/NLEContext.tsx @@ -9,6 +9,7 @@ import { setCompositionSourceMap } from "../editor/domEditingDom"; import { ensureMotionPathPluginLoaded } from "../../utils/gsapSoftReload"; import { useAssetPreviewStore } from "../../utils/assetPreviewStore"; import { createStableContext } from "../../utils/hmrStableContext"; +import { studioApiFetch } from "../../utils/studioApiFetch"; export function shouldDisableTimelineWhileCompositionLoading(compositionLoading: boolean): boolean { return compositionLoading; @@ -209,7 +210,7 @@ export function NLEProvider({ setCompositionSourceMap(emptyMap); onCompIdToSrcChangeRef.current?.(emptyMap); - fetch(buildProjectApiPath(projectId, `/files/index.html`), { + studioApiFetch(buildProjectApiPath(projectId, `/files/index.html`), { signal: controller.signal, }) .then((r) => { diff --git a/packages/studio/src/components/nle/NLEPreview.tsx b/packages/studio/src/components/nle/NLEPreview.tsx index 0269cb48c95..1b4ad5ce113 100644 --- a/packages/studio/src/components/nle/NLEPreview.tsx +++ b/packages/studio/src/components/nle/NLEPreview.tsx @@ -12,7 +12,7 @@ import { type RefObject, } from "react"; import { Player } from "../../player"; -import type { PreviewIframeSlot } from "../../player/hooks/useTimelineSyncCallbacks"; +import type { NLEContextValue } from "./NLEContext"; import { DEFAULT_PREVIEW_ZOOM, canStartPreviewPan, @@ -29,16 +29,18 @@ import { RULER_GUTTER_PX, usePreviewGuidesStore } from "../editor/previewGuidesS import { PreviewZoomOverlay, usePreviewNavigator } from "./PreviewZoomOverlay"; import { usePreviewFirstFrameTelemetry } from "../../player/hooks/usePreviewFirstFrameTelemetry"; import { PreviewPoster, usePreviewPoster } from "./PreviewPoster"; -interface NLEPreviewProps { - projectId: string; +interface NLEPreviewProps extends Pick< + NLEContextValue, + | "projectId" + | "onIframeLoad" + | "previewSlots" + | "onShadowIframeLoad" + | "onShadowReadyChange" + | "onShadowError" + | "setShadowIframeNode" + | "resetPreviewSlots" +> { iframeRef: RefObject; - onIframeLoad: () => void; - previewSlots: PreviewIframeSlot[]; - onShadowIframeLoad: (gen: number) => void; - onShadowReadyChange: (gen: number, ready: boolean) => void; - onShadowError: (gen: number, message: string) => void; - setShadowIframeNode: (node: HTMLIFrameElement | null) => void; - resetPreviewSlots: () => void; onCompositionLoadingChange?: (loading: boolean) => void; portrait?: boolean; directUrl?: string; diff --git a/packages/studio/src/components/nle/PreviewPoster.tsx b/packages/studio/src/components/nle/PreviewPoster.tsx index c1e8a802b28..cfee60c9927 100644 --- a/packages/studio/src/components/nle/PreviewPoster.tsx +++ b/packages/studio/src/components/nle/PreviewPoster.tsx @@ -6,6 +6,7 @@ import { type ThumbnailRequest, } from "../../player/lib/thumbnailScheduler"; import type { PreviewCompositionSize } from "../../utils/previewCompositionSize"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /** Frame 0 as the thumbnail route last rendered it; `cachedOnly` never starts a render. */ function previewPosterUrl(projectId: string, cachedOnly: boolean): string { @@ -107,7 +108,7 @@ export function renderPosterForNextOpen(projectId: string): void { priority: "overscan", discardWhenReleased: true, load: async (signal) => { - await (await fetch(url, { signal })).arrayBuffer(); + await (await studioApiFetch(url, { signal })).arrayBuffer(); return { value: { kind: "image", url, aspect: 16 / 9 }, weight: 0 }; }, }; diff --git a/packages/studio/src/components/renders/useFfmpegStatus.ts b/packages/studio/src/components/renders/useFfmpegStatus.ts index 94af085154d..b25f49769c0 100644 --- a/packages/studio/src/components/renders/useFfmpegStatus.ts +++ b/packages/studio/src/components/renders/useFfmpegStatus.ts @@ -1,4 +1,5 @@ import { useCallback, useEffect, useRef, useState } from "react"; +import { studioApiFetch } from "../../utils/studioApiFetch"; /** * What the dev server knows about this machine's FFmpeg, as reported by @@ -59,7 +60,7 @@ function parseStatus(body: unknown): ProbeResult { async function probe(): Promise { try { - const res = await fetch("/api/environment/ffmpeg"); + const res = await studioApiFetch("/api/environment/ffmpeg"); return res.ok ? parseStatus(await res.json()) : null; } catch { return null; diff --git a/packages/studio/src/components/renders/useRenderQueue.ts b/packages/studio/src/components/renders/useRenderQueue.ts index 704ea828d56..62a035ea662 100644 --- a/packages/studio/src/components/renders/useRenderQueue.ts +++ b/packages/studio/src/components/renders/useRenderQueue.ts @@ -8,6 +8,7 @@ import { generateId } from "../../utils/generateId"; import { readServerError } from "./serverError"; import { ffmpegInstallMessage, useFfmpegStatus } from "./useFfmpegStatus"; import { requestStudioFeedback, type FeedbackContext } from "../feedback/feedbackTrigger"; +import { studioApiFetch } from "../../utils/studioApiFetch"; export interface RenderJob { id: string; @@ -126,7 +127,7 @@ export function useRenderQueue( const loadRenders = useCallback(async () => { if (!projectId) return; try { - const res = await fetch(buildProjectApiPath(projectId, `/renders`)); + const res = await studioApiFetch(buildProjectApiPath(projectId, `/renders`)); if (!res.ok) { setLoadError(`Couldn't load render history (server error ${res.status}).`); return; @@ -262,7 +263,7 @@ export function useRenderQueue( } let res: Response; try { - res = await fetch(buildProjectApiPath(projectId, `/render`), { + res = await studioApiFetch(buildProjectApiPath(projectId, `/render`), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), @@ -376,7 +377,7 @@ export function useRenderQueue( ), ); try { - const res = await fetch(`/api/render/${jobId}/cancel`, { method: "POST" }); + const res = await studioApiFetch(`/api/render/${jobId}/cancel`, { method: "POST" }); if (!res.ok && res.status !== 404) { setActionError("Couldn't cancel on the server — the render may still be running."); return; @@ -403,7 +404,7 @@ export function useRenderQueue( setActionError(null); closeActiveEventSource(jobId); try { - const res = await fetch(`/api/render/${jobId}`, { method: "DELETE" }); + const res = await studioApiFetch(`/api/render/${jobId}`, { method: "DELETE" }); if (!res.ok) { setActionError("Couldn't delete the render — it's still on disk."); return; diff --git a/packages/studio/src/components/sidebar/AssetsTab.tsx b/packages/studio/src/components/sidebar/AssetsTab.tsx index 67570fcb221..d0b2d942c18 100644 --- a/packages/studio/src/components/sidebar/AssetsTab.tsx +++ b/packages/studio/src/components/sidebar/AssetsTab.tsx @@ -16,6 +16,7 @@ import { import { AudioRow } from "./AudioRow"; import { GlobalAssetsView } from "./GlobalAssetsView"; import { AssetCard, FontRow } from "./AssetCard"; +import { studioApiFetch } from "../../utils/studioApiFetch"; interface AssetsTabProps { projectId: string; @@ -217,7 +218,7 @@ export const AssetsTab = memo(function AssetsTab({ useEffect(() => { if (manifest404Ref.current.has(projectId)) return; let cancelled = false; - fetch(buildProjectApiPath(projectId, `/preview/.media/manifest.jsonl`)) + studioApiFetch(buildProjectApiPath(projectId, `/preview/.media/manifest.jsonl`)) .then((r) => { if (!r.ok) { manifest404Ref.current.add(projectId); diff --git a/packages/studio/src/components/sidebar/GlobalAssetsView.tsx b/packages/studio/src/components/sidebar/GlobalAssetsView.tsx index e7b91012794..58f7fc086c0 100644 --- a/packages/studio/src/components/sidebar/GlobalAssetsView.tsx +++ b/packages/studio/src/components/sidebar/GlobalAssetsView.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useState } from "react"; +import { studioApiFetch } from "../../utils/studioApiFetch"; // Cross-project asset view — the global media-use cache (~/.media), fetched from // /api/assets/global. Self-contained (owns its fetch + state) so AssetsTab stays @@ -43,7 +44,7 @@ export function GlobalAssetsView({ searchQuery }: { searchQuery: string }) { const [records, setRecords] = useState(null); useEffect(() => { let cancelled = false; - fetch("/api/assets/global") + studioApiFetch("/api/assets/global") .then((r) => (r.ok ? r.json() : { assets: [] })) .then((d) => { if (!cancelled) setRecords(Array.isArray(d.assets) ? d.assets : []); diff --git a/packages/studio/src/contexts/DomEditContext.tsx b/packages/studio/src/contexts/DomEditContext.tsx index 87282b5baac..40b2b742857 100644 --- a/packages/studio/src/contexts/DomEditContext.tsx +++ b/packages/studio/src/contexts/DomEditContext.tsx @@ -24,6 +24,7 @@ const SAVES_AN_EDIT = { handleDomAttributeBatchCommit: true, handleDomPathOffsetCommit: true, handleDomGroupPathOffsetCommit: true, + handleDomGroupMoveBy: true, handleDomZIndexReorderCommit: true, handleDomBoxSizeCommit: true, handleDomRotationCommit: true, @@ -179,6 +180,7 @@ export function DomEditProvider({ handleDomAttributeBatchCommit, handleDomPathOffsetCommit, handleDomGroupPathOffsetCommit, + handleDomGroupMoveBy, handleDomZIndexReorderCommit, handleDomBoxSizeCommit, handleDomRotationCommit, @@ -274,6 +276,7 @@ export function DomEditProvider({ handleDomAttributeBatchCommit, handleDomPathOffsetCommit, handleDomGroupPathOffsetCommit, + handleDomGroupMoveBy, handleDomZIndexReorderCommit, handleDomBoxSizeCommit, handleDomRotationCommit, @@ -350,6 +353,7 @@ export function DomEditProvider({ handleDomAttributeBatchCommit, handleDomPathOffsetCommit, handleDomGroupPathOffsetCommit, + handleDomGroupMoveBy, handleDomZIndexReorderCommit, handleDomBoxSizeCommit, handleDomRotationCommit, diff --git a/packages/studio/src/hooks/domSelectionTestHarness.ts b/packages/studio/src/hooks/domSelectionTestHarness.ts index c2b0bc9bd38..1ce80f0f763 100644 --- a/packages/studio/src/hooks/domSelectionTestHarness.ts +++ b/packages/studio/src/hooks/domSelectionTestHarness.ts @@ -4,6 +4,7 @@ import type React from "react"; import { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import type { DomEditSelection } from "../components/editor/domEditing"; +import { buildStableSelector, getSelectorIndex } from "../components/editor/domEditingDom"; export function installReactActEnvironment(): void { Object.defineProperty(globalThis, "IS_REACT_ACT_ENVIRONMENT", { @@ -61,3 +62,25 @@ export function makeSelection(label: string, element: HTMLElement): DomEditSelec }, }; } + +/** Built as getDomLayerPatchTarget builds it: a bare class for an element with no id or hf-id. */ +export function stableSelectionFor(el: HTMLElement): DomEditSelection { + const selector = buildStableSelector(el); + return { + element: el, + id: el.id || undefined, + hfId: el.getAttribute("data-hf-id") || undefined, + selector, + selectorIndex: getSelectorIndex(document, el, selector, "index.html", null), + sourceFile: "index.html", + dataAttributes: { start: "0", duration: "2" }, + } as unknown as DomEditSelection; +} + +export function mountGroupSiblings(count: number, withIds = false): HTMLElement[] { + const groups = Array.from({ length: count }, (_, i) => + withIds ? `
` : `
`, + ); + document.body.innerHTML = `
${groups.join("")}
`; + return Array.from(document.querySelectorAll(".group")); +} diff --git a/packages/studio/src/hooks/domStyleCommit.propertyNames.test.ts b/packages/studio/src/hooks/domStyleCommit.propertyNames.test.ts new file mode 100644 index 00000000000..9ad83336354 --- /dev/null +++ b/packages/studio/src/hooks/domStyleCommit.propertyNames.test.ts @@ -0,0 +1,73 @@ +// @vitest-environment jsdom +import { expect, it } from "vitest"; +import type { DomEditSelection } from "../components/editor/domEditing"; +import type { PatchOperation } from "../utils/sourcePatcher"; +import { commitDomStyles, type DomStyleCommitContext } from "./domStyleCommit"; + +const selection = { + id: "target", + selector: "#target", + label: "Target", + tagName: "div", + sourceFile: "index.html", + compositionPath: "index.html", + textFields: [], + inlineStyles: {}, + computedStyles: {}, + dataAttributes: {}, + capabilities: { canSelect: true, canEditStyles: true }, +} as unknown as DomEditSelection; + +async function savedPatches(styles: Record) { + const saves: Array<{ operations: PatchOperation[]; label?: string }> = []; + const context: DomStyleCommitContext = { + activeCompPath: "index.html", + previewIframeRef: { current: null }, + showToast: () => undefined, + versions: new Map(), + persistDomEditOperations: (async ( + _selection: DomEditSelection, + operations: PatchOperation[], + options?: { label?: string }, + ) => { + saves.push({ operations, label: options?.label }); + }) as unknown as DomStyleCommitContext["persistDomEditOperations"], + }; + await commitDomStyles(context, selection, styles); + return saves; +} + +const written = (operations: PatchOperation[]) => + operations.map((op) => [(op as { property: string }).property, (op as { value: string }).value]); + +it("writes a style named the JavaScript way under its CSS name", async () => { + const saves = await savedPatches({ backgroundColor: "#ff0000" }); + expect(saves.map((save) => written(save.operations))).toEqual([ + [["background-color", "#ff0000"]], + ]); +}); + +it("saves a map mixing both forms as one patch and one undo step, all under CSS names", async () => { + const saves = await savedPatches({ + borderRadius: "4", + "border-color": "red", + WebkitTextStroke: "1px black", + msTransform: "none", + }); + expect(saves).toHaveLength(1); + expect(saves[0]!.label).toBe("Edit layer style"); + expect(written(saves[0]!.operations)).toEqual([ + ["border-radius", "4px"], + ["border-color", "red"], + ["-webkit-text-stroke", "1px black"], + ["-ms-transform", "none"], + ]); +}); + +it("keeps a custom property's name exactly as given", async () => { + const saves = await savedPatches({ "--brand": "#123456", "--brandAccent": "#654321" }); + expect(written(saves[0]!.operations)).toEqual([ + ["--brand", "#123456"], + ["--brandAccent", "#654321"], + ]); +}); diff --git a/packages/studio/src/hooks/domStyleCommit.ts b/packages/studio/src/hooks/domStyleCommit.ts index f0c02f4c2ad..33158c15863 100644 --- a/packages/studio/src/hooks/domStyleCommit.ts +++ b/packages/studio/src/hooks/domStyleCommit.ts @@ -1,5 +1,6 @@ import type { PatchOperation } from "../utils/sourcePatcher"; import { + cssPropertyName, isImageBackgroundValue, isManualGeometryStyleProperty, normalizeDomEditStyleValue, @@ -43,8 +44,14 @@ export interface DomStyleCommitContext { export async function commitDomStyles( context: DomStyleCommitContext, selection: DomEditSelection, - styles: Record, + stylesInEitherCase: Record, ): Promise { + const styles = Object.fromEntries( + Object.entries(stylesInEitherCase).map(([property, value]) => [ + cssPropertyName(property), + value, + ]), + ); const entries = Object.entries(styles); if (entries.length === 0) return domEditCommitDeclined("no-selection"); if (entries.some(([property]) => isManualGeometryStyleProperty(property))) diff --git a/packages/studio/src/hooks/draggedGsapPosition.ts b/packages/studio/src/hooks/draggedGsapPosition.ts index e4358f90e8c..687a334f36d 100644 --- a/packages/studio/src/hooks/draggedGsapPosition.ts +++ b/packages/studio/src/hooks/draggedGsapPosition.ts @@ -75,3 +75,13 @@ export function computeDraggedGsapPosition( baseGsapY, }; } + +/** Puts the drag's preview offset back once the written position renders instead. */ +export function restoreDragOffset(element: HTMLElement): void { + const origin = (axis: "x" | "y") => + Number.parseFloat(element.getAttribute(`data-hf-drag-initial-offset-${axis}`) ?? "") || 0; + element.style.setProperty("--hf-studio-offset-x", `${origin("x")}px`); + element.style.setProperty("--hf-studio-offset-y", `${origin("y")}px`); + element.removeAttribute("data-hf-drag-initial-offset-x"); + element.removeAttribute("data-hf-drag-initial-offset-y"); +} diff --git a/packages/studio/src/hooks/gsapDragCommit.test.ts b/packages/studio/src/hooks/gsapDragCommit.test.ts index 221fbebffa9..d9f94c2bcd4 100644 --- a/packages/studio/src/hooks/gsapDragCommit.test.ts +++ b/packages/studio/src/hooks/gsapDragCommit.test.ts @@ -14,6 +14,7 @@ import { type GsapDragCommitCallbacks, } from "./gsapDragCommit"; import { usePlayerStore } from "../player/store/playerStore"; +import { liveTween, previewWith } from "./gsapParsedTween.test-helpers"; // Minimal selection whose element has no drag-baseline attributes (origX/Y = 0). const selection = (): DomEditSelection => @@ -111,175 +112,86 @@ function recordingCallbacks(): { }; } -describe("commitGsapPositionFromDrag — flat tween", () => { - beforeEach(() => { - usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); - }); - - it("extends the existing tween (never spawns a parallel one) when dragged OUTSIDE its range", async () => { - // fallow-ignore-next-line code-duplication - usePlayerStore.setState({ currentTime: 6 }); // outside [1.2, 3.4] - const { types, callbacks } = recordingCallbacks(); - - await commitGsapPositionFromDrag( - selection(), - flatTween(), - { x: -100, y: 0 }, - { x: 0, y: 0 }, - null, - "#puck-a", - callbacks, - ); - - expect(types).toContain("convert-to-keyframes"); - expect(types).toContain("replace-with-keyframes"); // the extend - expect(types).not.toContain("add-with-keyframes"); // regression: no parallel tween - }); - - it("adds a keyframe at the playhead when dragged INSIDE its range", async () => { - // fallow-ignore-next-line code-duplication - usePlayerStore.setState({ currentTime: 2 }); // inside [1.2, 3.4] - // fallow-ignore-next-line code-duplication - const { types, callbacks } = recordingCallbacks(); - - await commitGsapPositionFromDrag( - selection(), - flatTween(), - { x: -100, y: 0 }, - { x: 0, y: 0 }, - null, - "#puck-a", - callbacks, - ); - - expect(types).toContain("add-keyframe"); - expect(types).not.toContain("add-with-keyframes"); - }); +describe("commitGsapPositionFromDrag — at a selected keyframe or past the tween", () => { + beforeEach(() => usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null })); + const puck = () => { + const element = document.createElement("div"); + element.id = "puck-a"; + return { id: "puck-a", selector: "#puck-a", element } as unknown as DomEditSelection; + }; + const preview = ( + sel: DomEditSelection, + anim: GsapAnimation, + ends: Record, + from = false, + ) => + previewWith(sel.element, [ + liveTween( + sel.element, + { start: anim.resolvedStart!, duration: anim.duration!, vars: anim.properties, ends }, + { from }, + ), + ]); - it("MODIFIES the selected keyframe (no extend) when one is selected, even past the tween end", async () => { - // User clicked the 100% diamond (activeKeyframePct=100), playhead drifted past - // the end. Expect: convert + add-keyframe AT 100% — not replace-with-keyframes. + it("changes the selected keyframe without extending, even with the playhead past the end", async () => { usePlayerStore.setState({ currentTime: 6, activeKeyframePct: 100 }); // outside [1.2, 3.4] - // fallow-ignore-next-line code-duplication - const { types, mutations, callbacks } = recordingCallbacks(); - + const { mutations, callbacks } = recordingCallbacks(); + const sel = puck(); await commitGsapPositionFromDrag( - selection(), + sel, flatTween(), { x: -100, y: 0 }, { x: 0, y: 0 }, - null, - "#puck-a", + preview(sel, flatTween(), { x: [0, -260] }), callbacks, ); - - expect(types).toContain("add-keyframe"); - expect(types).not.toContain("replace-with-keyframes"); // not extended - const addKf = mutations.find((m) => m.type === "add-keyframe"); - expect(addKf?.percentage).toBe(100); // modified the selected endpoint - // consumed: cleared so the next free drag doesn't keep modifying + expect(mutations).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + position: 1.2, + duration: 2.2, + easeEach: "power1.out", + keyframes: [{ percentage: 100, properties: { x: -100, y: 0 } }], + }), + ]); expect(usePlayerStore.getState().activeKeyframePct).toBeNull(); - // parked the playhead on the edited keyframe (1.2 start + 100% * 2.2 dur), - // so the edit is visible instead of rendering the base pose expect(usePlayerStore.getState().requestedSeekTime).toBe(3.4); }); -}); -describe("commitGsapPositionFromDrag — keyframed tween backfill", () => { - beforeEach(() => { - usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); - }); - - const keyframedTween = (): GsapAnimation => - ({ - id: "#puck-a-kf", - targetSelector: "#puck-a", - method: "to", - resolvedStart: 1.2, - duration: 2.2, - keyframes: { - keyframes: [ - { percentage: 0, properties: { x: 0 } }, - { percentage: 100, properties: { x: -260 } }, - ], - }, - }) as unknown as GsapAnimation; - - it("passes backfillDefaults so a newly-introduced prop doesn't move the other keyframes", async () => { - // Drag the 0% keyframe DOWN (introduces y on an x-only tween). The add-keyframe - // must carry backfillDefaults at the element's base so 100% gets y:0, not y:780. - usePlayerStore.setState({ currentTime: 1.2, activeKeyframePct: 0 }); - const { mutations, callbacks } = recordingCallbacks(); - - await commitGsapPositionFromDrag( - selection(), - keyframedTween(), - { x: 0, y: 780 }, // studioOffset: dragged straight down - { x: 0, y: 0 }, // gsapPos → base falls back to {0,0} (selection has no base attrs) - null, - "#puck-a", - callbacks, - ); - - const addKf = mutations.find((m) => m.type === "add-keyframe"); - expect(addKf).toBeDefined(); - expect(addKf?.percentage).toBe(0); // edited the selected 0% keyframe - expect(addKf?.properties).toMatchObject({ y: 780 }); - expect(addKf?.backfillDefaults).toEqual({ x: 0, y: 0 }); // base → 100% gets y:0 - }); -}); - -describe("commitGsapPositionFromDrag — from() tween dragged outside its range", () => { - beforeEach(() => usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null })); - - const fromTween = (): GsapAnimation => - ({ - id: "#title-from-400", + it("extends a from() tween to the playhead, keeping its parsed end as the old end", async () => { + usePlayerStore.setState({ currentTime: 2.2 }); // outside [0.4, 1.3] + const fromTween = { + id: "#title-from-400-position", targetSelector: "#title", method: "from", + propertyGroup: "position", resolvedStart: 0.4, duration: 0.9, + ease: "none", properties: { y: 70 }, - }) as unknown as GsapAnimation; - - it("REPLACES the split position from() tween (no parallel tween → no drop jump)", async () => { - usePlayerStore.setState({ currentTime: 2.13 }); // outside [0.4, 1.3] - const types: string[] = []; - const mutations: Array> = []; - const callbacks: GsapDragCommitCallbacks = { - commitMutation: async (_s, m) => { - types.push(m.type as string); - mutations.push(m); - }, - // After split-into-property-groups, the position group is a from() tween (no keyframes). - fetchAnimations: async () => [ - { - id: "#title-from-400-position", - targetSelector: "#title", - method: "from", - propertyGroup: "position", - resolvedStart: 0.4, - duration: 0.9, - properties: { y: 70 }, - } as unknown as GsapAnimation, - ], - }; - + } as unknown as GsapAnimation; + const { types, mutations, callbacks } = recordingCallbacks(); + const sel = puck(); await commitGsapPositionFromDrag( - selection(), - fromTween(), + sel, + fromTween, { x: 0, y: -333 }, { x: 0, y: 0 }, - null, - "#title", + preview(sel, fromTween, { y: [70, 0] }, true), callbacks, ); - - expect(types).toContain("split-into-property-groups"); - expect(types).toContain("replace-with-keyframes"); - expect(types).not.toContain("add-with-keyframes"); // regression: no parallel tween - const replace = mutations.find((m) => m.type === "replace-with-keyframes"); - expect(replace?.animationId).toBe("#title-from-400-position"); // replaces the split from() + expect(types).toEqual(["replace-with-keyframes"]); + expect(mutations[0]).toMatchObject({ + animationId: "#title-from-400-position", + position: 0.4, + duration: 1.8, + easeEach: "none", + keyframes: [ + { percentage: 0, properties: { y: 70, x: 0 } }, + { percentage: 50, properties: { y: 0, x: 0 } }, + { percentage: 100, properties: { y: -333, x: 0 } }, + ], + }); }); }); @@ -581,32 +493,31 @@ describe("commitStaticGsapRotation — instantPatch (value-only set)", () => { }); }); -describe("commitGsapPositionFromDrag — keyframe/structural commits omit instantPatch", () => { +describe("commitGsapPositionFromDrag — keyframe commits omit instantPatch", () => { beforeEach(() => usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null })); - it("a structural keyframe drag (convert-to-keyframes → add-keyframe) sets no instantPatch", async () => { - usePlayerStore.setState({ currentTime: 2 }); // inside [1.2, 3.4] → convert + add-keyframe + it("a keyframe drag relies on the soft reload, not the instant patch", async () => { + usePlayerStore.setState({ currentTime: 2 }); // inside [1.2, 3.4] const { commits, callbacks } = optionRecordingCallbacks(); - + const element = document.createElement("div"); + const sel = { id: "puck-a", selector: "#puck-a", element } as unknown as DomEditSelection; + const live = liveTween(element, { + start: 1.2, + duration: 2.2, + vars: { x: -260 }, + ends: { x: [0, -260] }, + }); await commitGsapPositionFromDrag( - selection(), + sel, flatTween(), { x: -100, y: 0 }, { x: 0, y: 0 }, - null, - "#puck-a", + previewWith(element, [live]), callbacks, ); - - // The keyframe path is structural here (convert + add-keyframe) and must rely - // on the soft reload — none of its commits opt into the instant patch. - expect(commits.length).toBeGreaterThan(0); - for (const c of commits) { - expect(c.options.instantPatch).toBeUndefined(); - } - const types = commits.map((c) => c.mutation.type); - expect(types).toContain("convert-to-keyframes"); - expect(types).toContain("add-keyframe"); + expect(commits.map((c) => c.mutation.type)).toEqual(["replace-with-keyframes"]); + expect(commits[0]!.options.instantPatch).toBeUndefined(); + expect(commits[0]!.options.softReload).toBe(true); }); }); diff --git a/packages/studio/src/hooks/gsapDragCommit.ts b/packages/studio/src/hooks/gsapDragCommit.ts index 44d459ec1ea..a542dbafb10 100644 --- a/packages/studio/src/hooks/gsapDragCommit.ts +++ b/packages/studio/src/hooks/gsapDragCommit.ts @@ -4,14 +4,10 @@ */ import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; -import { - STUDIO_ORIGINAL_WIDTH_ATTR, - STUDIO_ORIGINAL_HEIGHT_ATTR, -} from "../components/editor/manualEditsTypes"; import { usePlayerStore } from "../player/store/playerStore"; import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler"; import { roundTo3, roundToLayoutPx } from "../utils/rounding"; -import { computeElementPercentage, writeTargetSelector } from "./gsapShared"; +import { computeElementPercentage, keyframeEases, writeTargetSelector } from "./gsapShared"; import { computeDraggedGsapPosition } from "./draggedGsapPosition"; import type { CommitMutation } from "./gsapScriptCommitTypes"; import { isGestureTransactionCommit, runGestureTransaction } from "./gestureTransaction"; @@ -295,104 +291,6 @@ export async function commitStaticGsapSize( ); } -/** Rounded `n` when it's a positive finite number, else `fallback`. */ -function positiveOr(n: number, fallback: number): number { - return Number.isFinite(n) && n > 0 ? roundToLayoutPx(n) : fallback; -} - -/** - * Prior size for a keyframed resize: the existing global set's value, else the - * element's pre-resize size (the draft saved it on the element before mutating - * el.style.width/height). Falls back to the new size when neither is available. - */ -function resolvePriorSize( - sizeSet: GsapAnimation | null, - el: Element | null | undefined, - fallbackW: number, - fallbackH: number, -): { width: number; height: number } { - if (sizeSet) { - return { - width: positiveOr(Number(sizeSet.properties.width), fallbackW), - height: positiveOr(Number(sizeSet.properties.height), fallbackH), - }; - } - const ow = Number.parseFloat(el?.getAttribute(STUDIO_ORIGINAL_WIDTH_ATTR) ?? ""); - const oh = Number.parseFloat(el?.getAttribute(STUDIO_ORIGINAL_HEIGHT_ATTR) ?? ""); - return { width: positiveOr(ow, fallbackW), height: positiveOr(oh, fallbackH) }; -} - -/** - * Resize an *animated* element by keyframing its size at the current playhead, - * instead of a global `gsap.set` hold. Builds a width/height keyframe tween - * aligned to the element's existing animation: every base keyframe keeps the - * prior size, only the keyframe nearest the playhead gets the new size — so - * resizing one keyframe leaves the others unchanged. Replaces any prior global - * size set. Returns false when there's no usable range (caller falls back to the - * static set). - */ -export async function commitKeyframedSizeFromResize( - selection: DomEditSelection, - size: { width: number; height: number }, - selector: string, - sizeSet: GsapAnimation | null, - animatedTween: GsapAnimation, - callbacks: GsapDragCommitCallbacks, -): Promise { - const ts = resolveTweenStart(animatedTween) ?? 0; - const td = resolveTweenDuration(animatedTween); - if (!(td > 0)) return false; - - const newW = roundToLayoutPx(size.width); - const newH = roundToLayoutPx(size.height); - const prior = resolvePriorSize(sizeSet, selection.element, newW, newH); - - const ct = usePlayerStore.getState().currentTime; - const pct = Math.max(0, Math.min(100, Math.round(((ct - ts) / td) * 1000) / 10)); - - // Base keyframe percentages from the animated tween (flat tween → 0 & 100), - // plus the endpoints and the playhead. Each keeps the prior size except the - // keyframe at the playhead, which gets the new size. - const pcts = new Set( - animatedTween.keyframes?.keyframes.map((k) => k.percentage) ?? [0, 100], - ); - pcts.add(0); - pcts.add(100); - pcts.add(pct); - const keyframes = Array.from(pcts) - .sort((a, b) => a - b) - .map((p) => ({ - percentage: p, - properties: Math.abs(p - pct) < 0.05 ? { width: newW, height: newH } : { ...prior }, - })); - - // Add the size keyframe tween FIRST, then delete the old global hold. The gesture - // transport applies both in one ordered batch; a plain commit fallback keeps the - // same recoverable ordering. Only the transaction's result triggers the reload. - const addLabel = `Resize (size keyframe ${pct.toFixed(0)}%)`; - const target = newTweenTarget(selection); - if (!target) return false; - await callbacks.commitMutation( - selection, - { - type: "add-with-keyframes", - targetSelector: target, - position: roundTo3(ts), - duration: roundTo3(td), - keyframes, - }, - sizeSet ? { label: addLabel, skipReload: true } : { label: addLabel, softReload: true }, - ); - if (sizeSet) { - await callbacks.commitMutation( - selection, - { type: "delete", animationId: sizeSet.id }, - { label: "Resize layer", softReload: true }, - ); - } - return true; -} - // ── Whole-path offset (plain drag on animated element) ────────────────── /** @@ -438,7 +336,6 @@ export async function commitWholePathOffset( const ts = resolveTweenStart(effectiveAnim); const td = resolveTweenDuration(effectiveAnim); - const ease = effectiveAnim.keyframes?.easeEach ?? effectiveAnim.ease; let kfs = effectiveAnim.keyframes?.keyframes ?? []; if (kfs.length === 0) { @@ -475,7 +372,7 @@ export async function commitWholePathOffset( position: roundTo3(ts ?? 0), duration: roundTo3(td || 1), keyframes: shifted, - ease, + ...keyframeEases(effectiveAnim), }, { label: "Move animation path", softReload: true, beforeReload: restoreOffset }, ); diff --git a/packages/studio/src/hooks/gsapDragPositionCommit.ts b/packages/studio/src/hooks/gsapDragPositionCommit.ts index 34476152321..27dda31bd1e 100644 --- a/packages/studio/src/hooks/gsapDragPositionCommit.ts +++ b/packages/studio/src/hooks/gsapDragPositionCommit.ts @@ -1,8 +1,7 @@ import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; -import { PROPERTY_GROUPS } from "@hyperframes/parsers/gsap-constants"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; import { usePlayerStore } from "../player/store/playerStore"; -import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler"; +import { resolveTweenStart } from "../utils/globalTimeCompiler"; import { KEYFRAME_PCT_MATCH, resolveEditableTweenDuration } from "./gsapShared"; import { roundTo3 } from "../utils/rounding"; import { computeDraggedGsapPosition } from "./draggedGsapPosition"; @@ -10,8 +9,9 @@ import { type GsapDragCommitCallbacks, computeCurrentPercentage, parkPlayheadOnKeyframe, - materializeIfDynamic, } from "./gsapDragCommit"; +import type { GsapEditOutcome } from "./gsapEditOutcome"; +import { commitValueAtPlayhead, planValueEdit } from "./gsapValueAtPlayhead"; /** * The tween's keyframes with one inserted at `percentage`. Any existing keyframe @@ -38,237 +38,26 @@ export function buildTemporalArcKeyframes( ].sort((a, b) => a.percentage - b.percentage); } -async function extendTweenAndAddKeyframe( +/** commitGsapPositionFromDrag's refusal, decided without writing. */ +export function gsapPositionFromDragOutcome( selection: DomEditSelection, anim: GsapAnimation, - properties: Record, - targetTime: number, - tweenStart: number, - tweenDuration: number, - callbacks: GsapDragCommitCallbacks, - beforeReload?: () => void, - backfillDefaults?: Record, -): Promise { - const tweenEnd = tweenStart + tweenDuration; - const newStart = Math.min(targetTime, tweenStart); - const newEnd = Math.max(targetTime, tweenEnd); - const newDuration = Math.max(0.01, newEnd - newStart); - const existingKfs = anim.keyframes?.keyframes ?? []; - const remappedKfs: Array<{ percentage: number; properties: Record }> = - []; - for (const kf of existingKfs) { - const absTime = tweenStart + (kf.percentage / 100) * tweenDuration; - const newPct = Math.round(((absTime - newStart) / newDuration) * 1000) / 10; - const props: Record = { ...kf.properties }; - for (const k of Object.keys(properties)) { - if (!(k in props) && backfillDefaults?.[k] != null) props[k] = backfillDefaults[k]; - } - remappedKfs.push({ percentage: newPct, properties: props }); - } - - const targetPct = Math.round(((targetTime - newStart) / newDuration) * 1000) / 10; - remappedKfs.push({ percentage: targetPct, properties }); - - remappedKfs.sort((a, b) => a.percentage - b.percentage); - - await callbacks.commitMutation( - selection, - { - type: "replace-with-keyframes", - animationId: anim.id, - targetSelector: anim.targetSelector, - position: roundTo3(newStart), - duration: roundTo3(newDuration), - keyframes: remappedKfs, - }, - { - label: `Move layer (extended keyframe)`, - keyframeAction: "add", - softReload: true, - beforeReload, - }, - ); -} - -// fallow-ignore-next-line complexity -async function commitKeyframedPosition( - selection: DomEditSelection, - anim: GsapAnimation, - properties: Record, - callbacks: GsapDragCommitCallbacks, - beforeReload?: () => void, - backfillDefaults?: Record, -): Promise { - const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); - const computedPct = computeCurrentPercentage(selection, anim); - const pct = activeKeyframePct ?? computedPct; - await callbacks.commitMutation( - selection, - { - type: "add-keyframe", - animationId: anim.id, - percentage: pct, - properties, - ...(backfillDefaults ? { backfillDefaults } : {}), - }, - { label: `Move layer (keyframe ${pct}%)`, softReload: true, beforeReload }, - ); - if (activeKeyframePct != null) { - setActiveKeyframePct(null); - parkPlayheadOnKeyframe(anim, pct); - } -} - -interface DragRuntimeGsap { - getProperty: (target: Element, key: string) => unknown; - set: (target: Element, vars: Record) => void; -} -interface DragRuntimeTimeline { - seek: (time: number) => void; -} -interface DragRuntime { - gsapLib: DragRuntimeGsap; - el: Element; - mainTl: DragRuntimeTimeline; -} - -function resolveDragRuntime( - iframe: HTMLIFrameElement | null | undefined, - selector: string | undefined, -): DragRuntime | null { - if (!iframe || !selector) return null; - const win = iframe.contentWindow as - | (Window & { - gsap?: Partial; - __timelines?: Record>; - }) - | null; - const gsap = win?.gsap; - if (typeof gsap?.getProperty !== "function" || typeof gsap.set !== "function") return null; - let el: Element | null = null; - try { - el = iframe.contentDocument?.querySelector(selector) ?? null; - } catch { - return null; - } - if (!el) return null; - const timelines = win?.__timelines; - const mainTl = timelines ? Object.values(timelines)[0] : undefined; - if (typeof mainTl?.seek !== "function") return null; - return { - gsapLib: gsap as DragRuntimeGsap, - el, - mainTl: mainTl as DragRuntimeTimeline, - }; -} - -// fallow-ignore-next-line complexity -async function commitFlatViaKeyframes( - selection: DomEditSelection, - anim: GsapAnimation, - properties: Record, - callbacks: GsapDragCommitCallbacks, - beforeReload?: () => void, - iframe?: HTMLIFrameElement | null, - selector?: string, - backfillDefaults?: Record, -): Promise { - const ct = usePlayerStore.getState().currentTime; - const ts = resolveTweenStart(anim); - const td = resolveEditableTweenDuration(anim, selection); - const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); - const outsideRange = - activeKeyframePct == null && ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01); - - const resolvedFromValues: Record = {}; - const runtime = resolveDragRuntime(iframe, selector); - if (runtime && ts !== null) { - const { gsapLib, el, mainTl } = runtime; - const draggedValues: Record = {}; - const channelsTheClearWipes = new Set([ - ...Object.keys(properties), - ...PROPERTY_GROUPS.position, - ]); - for (const key of channelsTheClearWipes) { - const v = Number(gsapLib.getProperty(el, key)); - if (Number.isFinite(v)) draggedValues[key] = v; - } - try { - gsapLib.set(el, { clearProps: Object.keys(properties).join(",") }); - mainTl.seek(ts); - for (const key of Object.keys(properties)) { - const v = Number(gsapLib.getProperty(el, key)); - if (Number.isFinite(v)) resolvedFromValues[key] = roundTo3(v); - } - mainTl.seek(ct); - } catch { - for (const key of Object.keys(resolvedFromValues)) delete resolvedFromValues[key]; - } finally { - if (Object.keys(draggedValues).length > 0) gsapLib.set(el, draggedValues); - } - } - - if (outsideRange && ts !== null) { - const coalesceKey = `gsap:convert-drag:${anim.id}`; - await callbacks.commitMutation( - selection, - { - type: "convert-to-keyframes", - animationId: anim.id, - ...(Object.keys(resolvedFromValues).length > 0 ? { resolvedFromValues } : {}), - }, - { label: "Convert to keyframes for drag", skipReload: true, coalesceKey }, - ); - const fresh = callbacks.fetchAnimations ? await callbacks.fetchAnimations() : []; - // By id first: a target with several tweens (two `to`s on the same selector) - // matches the selector lookup on whichever one happens to be first, and the - // extend-and-add below would then rewrite a tween the drag never touched. - const converted = - fresh.find((a) => a.id === anim.id && a.keyframes) ?? - fresh.find((a) => a.targetSelector === anim.targetSelector && a.keyframes) ?? - anim; - const convertedStart = resolveTweenStart(converted) ?? ts; - const convertedDur = resolveTweenDuration(converted) || td; - await extendTweenAndAddKeyframe( - selection, - converted, - properties, - ct, - convertedStart, - convertedDur, - callbacks, - beforeReload, - ); - return; - } - - const coalesceKey = `gsap:convert-drag:${anim.id}`; - // fallow-ignore-next-line code-duplication - await callbacks.commitMutation( - selection, - { - type: "convert-to-keyframes", - animationId: anim.id, - ...(Object.keys(resolvedFromValues).length > 0 ? { resolvedFromValues } : {}), - }, - { label: "Convert to keyframes for drag", skipReload: true, coalesceKey }, - ); - const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim); - const editedSelected = activeKeyframePct != null; - if (editedSelected) setActiveKeyframePct(null); - - await callbacks.commitMutation( - selection, - { - type: "add-keyframe", - animationId: anim.id, - percentage: pct, - properties, - ...(backfillDefaults ? { backfillDefaults } : {}), - }, - { label: `Move layer (keyframe ${pct}%)`, softReload: true, beforeReload, coalesceKey }, + studioOffset: { x: number; y: number }, + gsapPos: { x: number; y: number }, + iframe: HTMLIFrameElement | null, +): GsapEditOutcome { + if (anim.arcPath?.enabled) return { status: "persisted" }; + const { newX, newY, baseGsapX, baseGsapY } = computeDraggedGsapPosition( + selection.element, + studioOffset, + gsapPos, ); - if (editedSelected) parkPlayheadOnKeyframe(anim, pct); + const plan = planValueEdit(selection, anim, { x: newX, y: newY }, iframe, { + backfill: { x: baseGsapX, y: baseGsapY }, + }); + return plan.ok + ? { status: "persisted" } + : { status: "blocked", reason: "keyframes-uneditable", detail: plan.reason }; } // fallow-ignore-next-line code-duplication @@ -279,9 +68,8 @@ export async function commitGsapPositionFromDrag( studioOffset: { x: number; y: number }, gsapPos: { x: number; y: number }, iframe: HTMLIFrameElement | null, - selector: string, callbacks: GsapDragCommitCallbacks, -): Promise { +): Promise { const el = selection.element; // fallow-ignore-next-line code-duplication const { newX, newY, baseGsapX, baseGsapY } = computeDraggedGsapPosition( @@ -298,8 +86,6 @@ export async function commitGsapPositionFromDrag( el.removeAttribute("data-hf-drag-initial-offset-y"); }; - const backfillDefaults: Record = { x: baseGsapX, y: baseGsapY }; - const ct = usePlayerStore.getState().currentTime; if (anim.arcPath?.enabled) { const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim); @@ -324,14 +110,15 @@ export async function commitGsapPositionFromDrag( ); setActiveKeyframePct(null); parkPlayheadOnKeyframe(anim, pct); - return; + return { status: "persisted" }; } const tweenStart = resolveTweenStart(anim); // Clip-wide, same as applyArcKeyframeAtPlayhead: authoring GSAP's 0.5s // default here would collapse a duration-less arc's window on drag. const tweenDuration = resolveEditableTweenDuration(anim, selection); - if (tweenStart === null || tweenDuration <= 0 || keyframes.length < 2) return; + if (tweenStart === null || tweenDuration <= 0 || keyframes.length < 2) + return { status: "persisted" }; const temporalKeyframes = buildTemporalArcKeyframes(anim, pct, { x: newX, y: newY }); await callbacks.commitMutation( selection, @@ -351,161 +138,11 @@ export async function commitGsapPositionFromDrag( beforeReload: restoreOffset, }, ); - return; - } - if (anim.keyframes) { - const newId = await materializeIfDynamic(anim, iframe, callbacks.commitMutation, selection); - const effectiveAnim = newId ? { ...anim, id: newId } : anim; - const dragProps: Record = { x: newX, y: newY }; - - const ts = resolveTweenStart(effectiveAnim); - const td = resolveEditableTweenDuration(effectiveAnim, selection); - const outsideRange = ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01); - const hasSelectedKeyframe = usePlayerStore.getState().activeKeyframePct != null; - if (outsideRange && !hasSelectedKeyframe) { - await extendTweenAndAddKeyframe( - selection, - effectiveAnim, - dragProps, - ct, - ts, - td, - callbacks, - restoreOffset, - backfillDefaults, - ); - } else { - await commitKeyframedPosition( - selection, - effectiveAnim, - dragProps, - callbacks, - restoreOffset, - backfillDefaults, - ); - } - } else if (anim.method === "from" || anim.method === "fromTo") { - const ct = usePlayerStore.getState().currentTime; - const ts = resolveTweenStart(anim); - const td = resolveEditableTweenDuration(anim, selection); - const hasSelectedKeyframe = usePlayerStore.getState().activeKeyframePct != null; - const outsideRange = - !hasSelectedKeyframe && ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01); - const dragProps: Record = { x: newX, y: newY }; - - if (outsideRange && ts !== null) { - await callbacks.commitMutation( - selection, - { type: "split-into-property-groups", animationId: anim.id }, - { label: "Split from() for drag", skipReload: true }, - ); - - const allAnims = callbacks.fetchAnimations ? await callbacks.fetchAnimations() : []; - const existingPosAnim = allAnims.find( - (a) => a.propertyGroup === "position" && a.targetSelector === anim.targetSelector, - ); - - if (existingPosAnim?.keyframes) { - const posTs = resolveTweenStart(existingPosAnim); - const posTd = resolveEditableTweenDuration(existingPosAnim, selection); - if (posTs !== null) { - await extendTweenAndAddKeyframe( - selection, - existingPosAnim, - { x: newX, y: newY }, - ct, - posTs, - posTd, - callbacks, - restoreOffset, - backfillDefaults, - ); - return; - } - } - - const newStart = Math.min(ct, ts); - const newEnd = Math.max(ct, ts + td); - const newDuration = Math.max(0.01, newEnd - newStart); - const dragBefore = ct < ts; - const origStartPct = Math.round(((ts - newStart) / newDuration) * 1000) / 10; - const origEndPct = Math.round(((ts + td - newStart) / newDuration) * 1000) / 10; - - const keyframes: Array<{ percentage: number; properties: Record }> = - []; - if (dragBefore) { - keyframes.push({ percentage: 0, properties: { x: newX, y: newY } }); - if (origStartPct > 0.5 && origStartPct < 99.5) { - keyframes.push({ percentage: origStartPct, properties: { x: 0, y: 0 } }); - } - keyframes.push({ percentage: 100, properties: { x: 0, y: 0 } }); - } else { - keyframes.push({ percentage: 0, properties: { x: 0, y: 0 } }); - if (origEndPct > 0.5 && origEndPct < 99.5) { - keyframes.push({ percentage: origEndPct, properties: { x: 0, y: 0 } }); - } - keyframes.push({ percentage: 100, properties: { x: newX, y: newY } }); - } - keyframes.sort((a, b) => a.percentage - b.percentage); - - const baseKf = { - targetSelector: anim.targetSelector, - position: roundTo3(newStart), - duration: roundTo3(newDuration), - keyframes, - }; - await callbacks.commitMutation( - selection, - existingPosAnim - ? { type: "replace-with-keyframes", animationId: existingPosAnim.id, ...baseKf } - : { type: "add-with-keyframes", ...baseKf }, - { - label: "Move layer (from extended)", - keyframeAction: "add", - softReload: true, - beforeReload: restoreOffset, - }, - ); - } else { - const coalesceKey = `gsap:convert-drag:${anim.id}`; - await callbacks.commitMutation( - selection, - { - type: "convert-to-keyframes", - animationId: anim.id, - }, - { label: "Convert from() for drag", skipReload: true, coalesceKey }, - ); - const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); - const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim); - if (activeKeyframePct != null) setActiveKeyframePct(null); - await callbacks.commitMutation( - selection, - { - type: "add-keyframe", - animationId: anim.id, - percentage: pct, - properties: dragProps, - ...(backfillDefaults ? { backfillDefaults } : {}), - }, - { - label: `Move layer (keyframe ${pct}%)`, - softReload: true, - beforeReload: restoreOffset, - coalesceKey, - }, - ); - } - } else { - await commitFlatViaKeyframes( - selection, - anim, - { x: newX, y: newY }, - callbacks, - restoreOffset, - iframe, - selector, - backfillDefaults, - ); + return { status: "persisted" }; } + return commitValueAtPlayhead(selection, anim, { x: newX, y: newY }, iframe, callbacks, { + label: "Move layer", + backfill: { x: baseGsapX, y: baseGsapY }, + beforeReload: restoreOffset, + }); } diff --git a/packages/studio/src/hooks/gsapEditOutcome.ts b/packages/studio/src/hooks/gsapEditOutcome.ts index 68ef4dcf5b9..eb6544b8880 100644 --- a/packages/studio/src/hooks/gsapEditOutcome.ts +++ b/packages/studio/src/hooks/gsapEditOutcome.ts @@ -1,6 +1,11 @@ import { editabilityForProvenance, type GsapAnimation } from "@hyperframes/core/gsap-parser"; -export type GsapEditBlockReason = "no-selector" | "unroll-required" | "source-uneditable"; +export type GsapEditBlockReason = + | "no-selector" + | "unroll-required" + | "source-uneditable" + | "keyframes-uneditable" + | "mixed-files"; /** * Which of the nine situations produced a block. The user-facing `reason` stays @@ -21,7 +26,18 @@ export type GsapEditBlockDetail = | "no-position-tween" | "live-rotation-no-source-tween" | "live-resize-no-source-tween" - | "zero-duration-tween"; + | "zero-duration-tween" + | PlayheadEditRefusal; + +/** Why an edit at the playhead could not be written as keyframes of the file's tween. */ +export type PlayheadEditRefusal = + | "eased-keyframes" + | "simple-array-keyframes" + | "unknown-ease" + | "implicit-end-unknown" + | "not-a-tween" + | "no-timing" + | "shared-tween"; export type GsapEditOutcome = | { @@ -52,6 +68,10 @@ export const GSAP_EDIT_BLOCK_COPY: Record = { "unroll-required": "This motion comes from a helper or loop. Choose Unroll to edit it explicitly.", "source-uneditable": "This animation is computed at runtime. Edit the animation in the Code tab.", + "keyframes-uneditable": + "Studio can't add this edit to the animation's keyframes. Edit this animation in the Code tab.", + "mixed-files": + "These layers are animated in different files. Move each file's layers separately.", }; export class GsapEditBlockedError extends Error { diff --git a/packages/studio/src/hooks/gsapGroupPreflight.ts b/packages/studio/src/hooks/gsapGroupPreflight.ts new file mode 100644 index 00000000000..64e1af72a30 --- /dev/null +++ b/packages/studio/src/hooks/gsapGroupPreflight.ts @@ -0,0 +1,34 @@ +import type { DomEditGroupPathOffsetCommit } from "../components/editor/DomEditOverlay"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import { GsapEditBlockedError } from "./gsapEditOutcome"; +import { gsapWriteFile } from "./gsapScriptCommitTypes"; + +/** The first member a group's preflight refused, else one from a second file. */ +export function firstPreflightFailure( + results: PromiseSettledResult[], + updates: DomEditGroupPathOffsetCommit[], + savedOnElement: Map, + activeCompPath: string | null | undefined, +): { error: unknown; selection: DomEditSelection } | null { + for (const [index, result] of results.entries()) { + if (result.status !== "rejected") continue; + const selection = updates[index]?.selection; + if (selection) return { error: result.reason, selection }; + } + return secondFile(updates, savedOnElement, activeCompPath); +} + +/** The group's script writes go out as one batch to one file, so members from two files refuse. */ +function secondFile( + updates: DomEditGroupPathOffsetCommit[], + savedOnElement: Map, + activeCompPath: string | null | undefined, +): { error: unknown; selection: DomEditSelection } | null { + const scripted = updates.filter(({ selection }) => !savedOnElement.has(selection)); + const fileOf = (s: DomEditSelection) => gsapWriteFile(s, activeCompPath); + const file = scripted[0] && fileOf(scripted[0].selection); + const other = scripted.find(({ selection }) => fileOf(selection) !== file); + return other + ? { error: new GsapEditBlockedError("mixed-files"), selection: other.selection } + : null; +} diff --git a/packages/studio/src/hooks/gsapMutationClient.ts b/packages/studio/src/hooks/gsapMutationClient.ts index fb9c0871f08..6ea38ad0262 100644 --- a/packages/studio/src/hooks/gsapMutationClient.ts +++ b/packages/studio/src/hooks/gsapMutationClient.ts @@ -1,11 +1,12 @@ import { studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; export class GsapPreviewConvergenceError extends Error {} export class GsapOwnershipProtocolError extends GsapPreviewConvergenceError {} /** Verify rollback ownership support before any GSAP mutation can land. */ export async function requireGsapOwnershipProtocol(projectId: string): Promise { - const response = await fetch( + const response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-mutation-capabilities`, ); if (!response.ok) { @@ -29,7 +30,7 @@ export async function rollbackOwnedMutation( if (targetPath.includes("\0") || targetPath.includes("..")) { throw new Error(`Unsafe path: ${targetPath}`); } - const response = await fetch( + const response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-mutation-rollback/${encodeURIComponent(targetPath)}`, { method: "POST", @@ -95,7 +96,7 @@ export async function postGsapMutation( ): Promise { let response: Response; try { - response = await fetch( + response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-mutations/${encodeURIComponent(filePath)}`, { method: "POST", diff --git a/packages/studio/src/hooks/gsapParsedTween.test-helpers.ts b/packages/studio/src/hooks/gsapParsedTween.test-helpers.ts new file mode 100644 index 00000000000..cc0e6a46219 --- /dev/null +++ b/packages/studio/src/hooks/gsapParsedTween.test-helpers.ts @@ -0,0 +1,75 @@ +import { vi } from "vitest"; +import { classifyTweenPropertyGroup } from "@hyperframes/core/gsap-parser"; +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import { usePlayerStore } from "../player/store/playerStore"; + +/** A property's `[start, end]` as GSAP parsed it from the file when the tween first rendered. */ +type Ends = Record; + +/** A GSAP 3 tween as the preview runtime holds it, with the property tweens the parse readers walk. */ +export function liveTween( + target: Element, + tween: { start: number; duration: number; vars: Record; ends?: Ends }, + { from = false, parts }: { from?: boolean; parts?: unknown[] } = {}, +) { + let head: Record | undefined; + for (const [p, [s, e]] of Object.entries(tween.ends ?? {}).reverse()) + head = from ? { p, s: e, c: s - e, _next: head } : { p, s, c: e - s, _next: head }; + return { + targets: () => [target], + startTime: () => tween.start, + duration: () => tween.duration, + vars: tween.vars, + _from: from, + ...(head && { _pt: { d: { _pt: head } } }), + ...(parts && { timeline: { getChildren: () => parts } }), + }; +} + +/** A preview iframe whose one timeline holds `tweens`, answering `getProperty` from `live`. */ +export function previewWith( + element: Element, + tweens: unknown[], + live: Record = {}, +): HTMLIFrameElement { + return { + contentWindow: { + __timelines: { main: { getChildren: () => tweens, duration: () => 10 } }, + gsap: { + getProperty: (_el: Element, prop: string) => live[prop] ?? 0, + defaults: () => ({ ease: "power1.out" }), + }, + }, + contentDocument: element.ownerDocument, + } as unknown as HTMLIFrameElement; +} + +export const tween = (fields: Partial): GsapAnimation => + ({ targetSelector: "#box", propertyGroup: "position", ...fields }) as GsapAnimation; + +/** A `to` tween on `#el` from 0, grouped as the parser would; duration 0 is an immediate-render hold. */ +export function elTween( + id: string, + properties: Record, + duration: number, + ease?: string, +): GsapAnimation { + return { + id, + targetSelector: "#el", + propertyGroup: classifyTweenPropertyGroup(properties), + method: "to", + properties, + position: 0, + resolvedStart: 0, + duration, + ...(duration === 0 ? { extras: { immediateRender: "__raw:true" } } : ease && { ease }), + } as unknown as GsapAnimation; +} + +/** Per-test cleanup for the intercept sweeps: mocks, the playhead store and the document. */ +export function resetGsapEditState(): void { + vi.restoreAllMocks(); + usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); + document.body.innerHTML = ""; +} diff --git a/packages/studio/src/hooks/gsapParsedTween.test.ts b/packages/studio/src/hooks/gsapParsedTween.test.ts new file mode 100644 index 00000000000..c57393ca79c --- /dev/null +++ b/packages/studio/src/hooks/gsapParsedTween.test.ts @@ -0,0 +1,62 @@ +// @vitest-environment happy-dom +import { gsap } from "gsap"; +import { afterEach, describe, expect, it } from "vitest"; +import { findParsedTween, parsedImplicitEndValue } from "./gsapParsedTween"; +import { liveTween, previewWith, tween } from "./gsapParsedTween.test-helpers"; + +type Parsed = Parameters[0]; +const el = document.createElement("div"); +const part = (start: number, ends?: Record) => + liveTween(el, { start, duration: 1, vars: { x: 0 }, ends }); +const keyframed = (parts: unknown[]) => + liveTween(el, { start: 0, duration: 2, vars: { keyframes: [] } }, { parts }) as Parsed; + +describe("parsedImplicitEndValue", () => { + it("reads a flat tween's own start and end", () => { + const value = parsedImplicitEndValue(part(0, { x: [-60, 0] }) as Parsed); + expect([value("x", "start"), value("x", "end")]).toEqual([-60, 0]); + }); + + it("reads a keyframed tween's start from its first part and its end from its last", () => { + const value = parsedImplicitEndValue( + keyframed([part(0, { x: [0, 50] }), part(1, { x: [50, 120] })]), + ); + expect([value("x", "start"), value("x", "end")]).toEqual([0, 120]); + }); + + it("refuses when the part nearest that end is not initialised, rather than read an earlier one", () => { + const value = parsedImplicitEndValue(keyframed([part(0, { x: [0, 50] }), part(1)])); + expect(value("x", "end")).toBeNull(); + }); + + it("has no value without a parsed tween", () => { + expect(parsedImplicitEndValue(null)("x", "start")).toBeNull(); + }); +}); + +describe("findParsedTween", () => { + afterEach(() => document.body.replaceChildren()); + + it("takes the flat tween an edit names, not a keyframed tween at the same start", () => { + const fade = liveTween(el, { start: 0, duration: 2, vars: { keyframes: {}, ease: "none" } }); + const slide = liveTween(el, { start: 0, duration: 2, vars: { x: 300 } }); + const edit = tween({ method: "to", properties: { x: 300 }, resolvedStart: 0, duration: 2 }); + expect(findParsedTween(previewWith(el, [fade, slide]), el, edit)).toBe(slide); + }); + + it("parses a to() tween the playhead has not reached, from its authored start", () => { + const box = document.body.appendChild(document.createElement("div")); + box.id = "box"; + const timeline = gsap.timeline({ paused: true }).to(box, { x: 300, duration: 1 }, 2); + timeline.seek(0.5); + gsap.set(box, { x: 40 }); + const iframe = { contentWindow: { __timelines: { main: timeline }, gsap } }; + const edit = tween({ method: "to", properties: { x: 300 }, resolvedStart: 2, duration: 1 }); + + const parsed = findParsedTween(iframe as unknown as HTMLIFrameElement, box, edit); + + expect(parsedImplicitEndValue(parsed)("x", "start")).toBe(0); + expect([gsap.getProperty(box, "x"), timeline.time()]).toEqual([40, 0.5]); + timeline.kill(); + }); +}); diff --git a/packages/studio/src/hooks/gsapParsedTween.ts b/packages/studio/src/hooks/gsapParsedTween.ts new file mode 100644 index 00000000000..90a8e800608 --- /dev/null +++ b/packages/studio/src/hooks/gsapParsedTween.ts @@ -0,0 +1,243 @@ +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import { elementTargets } from "../utils/elementGsap"; +import { resolveTweenStart } from "../utils/globalTimeCompiler"; +import type { ImplicitEndValue } from "./gsapValueAtPlayhead"; + +// GSAP 3 internals: a property tween in a tween's `_pt` chain; CSSPlugin keeps its own under `d._pt`. +interface PropTween { + p?: string; + s?: number; + c?: number; + d?: { _pt?: PropTween }; + _next?: PropTween; +} +interface ParsedTween { + _pt?: PropTween; + _from?: boolean; + _initted?: boolean; + vars?: Record; + parent?: { + vars?: { defaults?: { ease?: unknown } }; + time?: () => number; + seek?: (time: number, suppressEvents?: boolean) => unknown; + getChildren?: (nested?: boolean, tweens?: boolean, timelines?: boolean) => ParsedTween[]; + }; + timeline?: { getChildren?: () => ParsedTween[] }; + targets?: () => unknown[]; + startTime?: () => number; + duration?: () => number; +} +interface GsapWindow { + gsap?: { + defaults?: () => { ease?: unknown }; + getProperty?: (target: Element, prop: string) => unknown; + set?: (target: Element, vars: Record) => void; + parseEase?: (name: string) => unknown; + }; + __timelines?: Record ParsedTween[] }>; +} + +// `scale` parses into the two longhands, which always share a start and end for a `scale` tween. +const PARSED_NAME: Record = { scale: "scaleX", rotate: "rotation" }; + +function findPropTween(pt: PropTween | undefined, prop: string): PropTween | null { + for (let node = pt; node; node = node._next) { + if (node.p === prop && typeof node.s === "number" && typeof node.c === "number") return node; + const nested = findPropTween(node.d?._pt, prop); + if (nested) return nested; + } + return null; +} + +/** `[start, end]` of `prop` in one initialised tween; a from() tween runs its pair backwards. */ +function endsIn(tween: ParsedTween, prop: string): [number, number] | null { + const pt = findPropTween(tween._pt, PARSED_NAME[prop] ?? prop); + if (!pt) return null; + const pair: [number, number] = [pt.s!, pt.s! + pt.c!]; + return tween._from ? [pair[1], pair[0]] : pair; +} + +/** The live tween GSAP built from `anim`: same element, start and channels, parsed. */ +// fallow-ignore-next-line complexity +export function findParsedTween( + iframe: HTMLIFrameElement | null, + element: Element, + anim: GsapAnimation, +): ParsedTween | null { + const win = iframe?.contentWindow as GsapWindow | null; + const start = resolveTweenStart(anim); + if (!win?.__timelines || start == null) return null; + const steps = anim.keyframes?.keyframes.map((kf) => kf.properties) ?? [anim.properties]; + const props = [...new Set(steps.flatMap((step) => Object.keys(step)))]; + const keyframed = Boolean(anim.keyframes); + for (const timeline of Object.values(win.__timelines)) { + for (const tween of timeline?.getChildren?.(true) ?? []) { + const targets = (tween.targets?.() ?? []) as Array<{ id?: unknown }>; + if (!targets.includes(element) && !targets.some((t) => element.id && t.id === element.id)) + continue; + if (!startsAt(tween, start)) continue; + const vars = tween.vars ?? {}; + const carries = keyframed ? "keyframes" in vars : props.some((p) => p in vars); + if (!carries || !((tween.duration?.() ?? 0) > 0)) continue; + parseUnplayed(win, element, tween, props); + return tween; + } + } + return null; +} + +/** GSAP's startTime() counts the tween's `delay`; the file's parse does not. */ +function startsAt(tween: ParsedTween, start: number): boolean { + const delay = Number(tween.vars?.delay) || 0; + return Math.abs((tween.startTime?.() ?? Number.NaN) - delay - start) <= 1e-3; +} + +/** `anim` timed as GSAP runs it: its start with any delay, a duration it leaves to GSAP filled in. */ +export function withLiveTiming(anim: GsapAnimation, tween: ParsedTween | null): GsapAnimation { + const start = tween?.startTime?.(); + return { + ...anim, + ...(Number.isFinite(start) && { resolvedStart: start }), + ...(anim.duration == null && tween && { duration: tween.duration?.() }), + }; +} + +/** GSAP parses a to() tween only when the playhead first passes it, and a soft reload resets that. + * Play its timeline from the tween's start (so earlier tweens set its start value) to its end and + * back, its channels cleared first; then restore every styled element's attributes and GSAP cache. */ +function parseUnplayed(win: GsapWindow, element: Element, tween: ParsedTween, props: string[]) { + const seek = !isParsed(tween) && seekable(win, tween); + if (!seek) return; + const { parent, gsap } = seek; + const before = layerStates(tween, element); + const now = parent.time(); + const start = tween.startTime?.() ?? 0; + gsap.set(element, { clearProps: props.join(",") }); + // Re-read now, so GSAP rebuilds its transform cache from the cleared element before the seek. + for (const p of props) gsap.getProperty(element, p); + try { + parent.seek(start, true); + parent.seek(start + (tween.duration?.() ?? 0), true); + } finally { + parent.seek(now, true); + restore(before); + } +} + +function isParsed(tween: ParsedTween): boolean { + const parts = tween.timeline?.getChildren?.() ?? []; + return Boolean(tween._initted) && parts.every((part) => part._initted); +} + +type GsapTools = { + getProperty: (el: Element, p: string) => unknown; + set: (el: Element, v: Record) => void; +}; + +function seekable(win: GsapWindow, tween: ParsedTween) { + const { parent } = tween; + const gsap = win.gsap; + if (!parent?.seek || !parent.time || !gsap?.getProperty || !gsap.set) return null; + return { + parent: { seek: parent.seek.bind(parent), time: parent.time.bind(parent) }, + gsap: { getProperty: gsap.getProperty.bind(gsap), set: gsap.set.bind(gsap) } as GsapTools, + }; +} + +type Layer = Element & { _gsap?: Record }; + +function layerStates(tween: ParsedTween, element: Element) { + const layers = new Set([element]); + for (const child of tween.parent?.getChildren?.(true, true, false) ?? []) + for (const target of elementTargets(child)) layers.add(target); + return [...layers].map((layer) => ({ + layer, + attributes: new Map([...layer.attributes].map((a) => [a.name, a.value])), + cache: layer._gsap && { ...layer._gsap }, + })); +} + +function restore(states: ReturnType) { + for (const { layer, attributes, cache } of states) { + restoreAttributes(layer, attributes); + if (cache && layer._gsap) restoreCache(layer._gsap, cache); + } +} + +function restoreAttributes(layer: Element, attributes: Map) { + for (const { name } of [...layer.attributes]) + if (!attributes.has(name)) layer.removeAttribute(name); + for (const [name, value] of attributes) + if (layer.getAttribute(name) !== value) layer.setAttribute(name, value); +} + +function restoreCache(live: Record, cache: Record) { + for (const key of Object.keys(live)) if (!(key in cache)) delete live[key]; + Object.assign(live, cache); +} + +/** Start and end values from GSAP's own parse of the tween, as loaded from the file. Null when + * GSAP has not initialised that part of the tween yet: the caller refuses rather than guess. */ +export function parsedImplicitEndValue(tween: ParsedTween | null): ImplicitEndValue { + return (prop, end) => { + if (!tween) return null; + for (const part of partsFrom(tween, end)) { + const pair = endsIn(part, prop); + if (pair) return end === "start" ? pair[0] : pair[1]; + // The nearest part animating `prop` is not initialised: an earlier one would be a wrong value. + if (prop in (part.vars ?? {})) return null; + } + return null; + }; +} + +/** A keyframed tween's parts, nearest `end` first; a flat tween is its own one part. */ +function partsFrom(tween: ParsedTween, end: "start" | "end"): ParsedTween[] { + const parts = tween.timeline?.getChildren?.() ?? []; + if (parts.length === 0) return [tween]; + return end === "start" ? parts : [...parts].reverse(); +} + +/** The ease GSAP resolved for a flat tween that authors none: its timeline's default, else GSAP's. */ +export function parsedTweenEase(iframe: HTMLIFrameElement | null, tween: ParsedTween | null) { + if (!tween) return null; + const win = iframe?.contentWindow as GsapWindow | null; + const ease = + tween.vars?.ease ?? tween.parent?.vars?.defaults?.ease ?? win?.gsap?.defaults?.().ease; + if (typeof ease === "string") return ease; + const named = (name: string) => win?.gsap?.parseEase?.(name) === ease; + return typeof ease === "function" ? (BUILT_IN_EASES.find(named) ?? null) : null; +} + +// GSAP holds a resolved ease, its own default included, as the function parseEase returns. +const BUILT_IN_EASES = [ + "none", + ...[ + "power1", + "power2", + "power3", + "power4", + "sine", + "expo", + "circ", + "back", + "elastic", + "bounce", + ].flatMap((e) => [`${e}.in`, `${e}.out`, `${e}.inOut`]), +]; + +/** An array of keyframe steps at the exact percentages GSAP times them; the parse rounds them. */ +export function withExactStepTimes(anim: GsapAnimation, tween: ParsedTween | null): GsapAnimation { + const data = anim.keyframes; + const parts = tween?.timeline?.getChildren?.() ?? []; + const total = tween?.duration?.() ?? 0; + if (data?.format !== "object-array" || parts.length !== data.keyframes.length || !(total > 0)) + return anim; + const ends = parts.map((part) => ((part.startTime?.() ?? 0) + (part.duration?.() ?? 0)) / total); + if (ends.some((end) => !Number.isFinite(end))) return anim; + const keyframes = data.keyframes.map((kf, i) => ({ + ...kf, + percentage: Math.round(ends[i]! * 100000) / 1000, + })); + return { ...anim, keyframes: { ...data, keyframes } }; +} diff --git a/packages/studio/src/hooks/gsapPositionDetection.test.ts b/packages/studio/src/hooks/gsapPositionDetection.test.ts new file mode 100644 index 00000000000..fabacbe3ca6 --- /dev/null +++ b/packages/studio/src/hooks/gsapPositionDetection.test.ts @@ -0,0 +1,78 @@ +import { afterEach, describe, expect, it } from "vitest"; +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import { usePlayerStore } from "../player/store/playerStore"; +import { tween } from "./gsapParsedTween.test-helpers"; +import { findGsapPositionAnimation, pickClosestToPlayhead } from "./gsapPositionDetection"; + +afterEach(() => usePlayerStore.setState({ currentTime: 0 })); + +const slide = ( + id: string, + resolvedStart: number, + duration: number, + fields: Partial = {}, +) => tween({ id, method: "to", properties: { x: 10 }, resolvedStart, duration, ...fields }); +const keyed = (...percentages: number[]) => ({ + keyframes: { + format: "object-array" as const, + keyframes: percentages.map((percentage) => ({ percentage, properties: { x: percentage } })), + }, +}); + +describe("pickClosestToPlayhead", () => { + it.each([ + ["the one spanning the playhead", 1.5, [slide("a", 0, 1), slide("b", 1, 1)], "b"], + ["the nearer end when none spans it", 5, [slide("a", 0, 1), slide("b", 2, 2)], "b"], + [ + "the one whose file states the playhead's value", + 1, + [slide("a", 0, 1), slide("b", 1, 1)], + "a", + ], + [ + "the later one when both state it", + 1, + [slide("a", 0, 2, keyed(0, 50, 100)), slide("b", 0.5, 1, keyed(0, 50, 100))], + "b", + ], + [ + "the one with more keyframes on a tie", + 5, + [slide("a", 0, 1, keyed(0, 100)), slide("b", 0, 1, keyed(0, 50, 100))], + "b", + ], + ])("picks %s", (_, time, anims, id) => { + usePlayerStore.setState({ currentTime: time }); + expect(pickClosestToPlayhead(anims)?.id).toBe(id); + }); +}); + +describe("findGsapPositionAnimation", () => { + it.each([ + [ + "the tween spanning the playhead", + 1.5, + undefined, + [slide("a", 0, 1, keyed(0, 100)), slide("b", 1, 1)], + "b", + ], + ["the nearer tween", 9, undefined, [slide("a", 0, 1), slide("b", 6, 1)], "b"], + [ + "the selected target's tween", + 0.5, + "#box", + [slide("a", 0, 1, { targetSelector: "#card", ...keyed(0, 100) }), slide("b", 0, 1)], + "b", + ], + [ + "a tween on one target over a shared one", + 0.5, + undefined, + [slide("a", 0, 1, { targetSelector: "#box, #card" }), slide("b", 0, 1)], + "b", + ], + ])("prefers %s", (_, time, selector, anims, id) => { + usePlayerStore.setState({ currentTime: time }); + expect(findGsapPositionAnimation(anims, selector)?.id).toBe(id); + }); +}); diff --git a/packages/studio/src/hooks/gsapPositionDetection.ts b/packages/studio/src/hooks/gsapPositionDetection.ts index f140930df93..1a63e119819 100644 --- a/packages/studio/src/hooks/gsapPositionDetection.ts +++ b/packages/studio/src/hooks/gsapPositionDetection.ts @@ -7,7 +7,7 @@ */ import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import { usePlayerStore } from "../player/store/playerStore"; -import { getIframeGsap, queryIframeElement } from "./gsapShared"; +import { getIframeGsap, KEYFRAME_PCT_MATCH, queryIframeElement } from "./gsapShared"; import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler"; // fallow-ignore-next-line complexity @@ -47,52 +47,71 @@ export function findGsapPositionAnimation( if (animations.length === 0) return null; const currentTime = usePlayerStore.getState().currentTime; - const scored = animations - .filter((a) => animHasPosition(a) || a.keyframes || animations.length === 1) - .map((a) => { - let score = 0; - if (animHasPosition(a)) score += 10; - if (a.keyframes) score += 5; - if (selector && a.targetSelector === selector) score += 8; - else if (a.targetSelector.includes(",")) score -= 5; - const pos = a.resolvedStart ?? (typeof a.position === "number" ? a.position : 0); - const dur = a.duration ?? 0; - if (currentTime >= pos - 0.05 && currentTime <= pos + dur + 0.05) score += 50; - else - score -= Math.round( - Math.min(Math.abs(currentTime - pos), Math.abs(currentTime - pos - dur)) * 5, - ); - return { anim: a, score }; - }); + const scored = animations.filter(animHasPosition).map((a) => { + let score = 0; + if (a.keyframes) score += 5; + if (selector && a.targetSelector === selector) score += 8; + else if (a.targetSelector.includes(",")) score -= 5; + return { anim: a, score: score + playheadProximity(a, currentTime) }; + }); scored.sort((a, b) => b.score - a.score); - return scored[0]?.anim ?? animations[0]; + return scored[0]?.anim ?? null; +} + +function playheadProximity(a: GsapAnimation, currentTime: number): number { + const pos = a.resolvedStart ?? (typeof a.position === "number" ? a.position : 0); + const dur = a.duration ?? 0; + if (currentTime >= pos - 0.05 && currentTime <= pos + dur + 0.05) return 50; + return -Math.round(Math.min(Math.abs(currentTime - pos), Math.abs(currentTime - pos - dur)) * 5); +} + +/** Whether the file states `anim`'s value at `time`; a tween's implicit start is GSAP's current value. */ +function statesValueAt(anim: GsapAnimation, time: number): boolean { + const duration = resolveTweenDuration(anim); + if (!(duration > 0)) return false; + const pct = ((time - (resolveTweenStart(anim) ?? 0)) / duration) * 100; + const near = (keyframe: number) => Math.abs(keyframe - pct) <= KEYFRAME_PCT_MATCH; + if (anim.keyframes) return anim.keyframes.keyframes.some((kf) => near(kf.percentage)); + if (anim.method === "from") return near(0); + return near(100) || (anim.method === "fromTo" && near(0)); } /** * From a set of candidate tweens, pick the one whose time range is closest to * the current playhead. A tween that *contains* the playhead wins outright; * otherwise the nearest endpoint wins. This ensures a drag at t=6s edits (or - * extends) the 4s tween, not the 1.5s one. Tie-break: most keyframes (so a - * gesture-recorded tween beats a stub when both are equidistant). + * extends) the 4s tween, not the 1.5s one. Ties: the one whose file states a value at the + * playhead (the later one, which renders, if both do), then most keyframes. */ // fallow-ignore-next-line complexity export function pickClosestToPlayhead(anims: GsapAnimation[]): GsapAnimation | null { if (anims.length <= 1) return anims[0] ?? null; const ct = usePlayerStore.getState().currentTime; return anims.reduce((best, a) => { - const s = resolveTweenStart(a) ?? 0; - const e = s + resolveTweenDuration(a); - const dist = ct >= s && ct <= e ? 0 : Math.min(Math.abs(ct - s), Math.abs(ct - e)); - const bestS = resolveTweenStart(best) ?? 0; - const bestE = bestS + resolveTweenDuration(best); - const bestDist = - ct >= bestS && ct <= bestE ? 0 : Math.min(Math.abs(ct - bestS), Math.abs(ct - bestE)); + const dist = playheadDistance(a, ct); + const bestDist = playheadDistance(best, ct); if (dist < bestDist) return a; - if ( - dist === bestDist && - (a.keyframes?.keyframes.length ?? 0) > (best.keyframes?.keyframes.length ?? 0) - ) - return a; + const stated = dist === 0 && bestDist === 0 ? statedValueWinner(a, best, ct) : null; + if (stated) return stated; + if (dist === bestDist && keyframeCount(a) > keyframeCount(best)) return a; return best; }); } + +function playheadDistance(anim: GsapAnimation, time: number): number { + const s = resolveTweenStart(anim) ?? 0; + const e = s + resolveTweenDuration(anim); + return time >= s && time <= e ? 0 : Math.min(Math.abs(time - s), Math.abs(time - e)); +} + +function statedValueWinner(a: GsapAnimation, b: GsapAnimation, time: number) { + const [mine, theirs] = [statesValueAt(a, time), statesValueAt(b, time)]; + if (mine !== theirs) return mine ? a : b; + const [s, bS] = [resolveTweenStart(a) ?? 0, resolveTweenStart(b) ?? 0]; + if (mine && s !== bS) return s > bS ? a : b; + return null; +} + +function keyframeCount(anim: GsapAnimation): number { + return anim.keyframes?.keyframes.length ?? 0; +} diff --git a/packages/studio/src/hooks/gsapResizeDropPoint.test.ts b/packages/studio/src/hooks/gsapResizeDropPoint.test.ts index 19d5c816d4f..c1ff52645cc 100644 --- a/packages/studio/src/hooks/gsapResizeDropPoint.test.ts +++ b/packages/studio/src/hooks/gsapResizeDropPoint.test.ts @@ -148,17 +148,18 @@ function positionAnimation( } as unknown as GsapAnimation; } -/** Every x/y a run wrote, in commit order. */ +/** Every x/y a run wrote AT THE PLAYHEAD (percentage 0 here), in commit order. */ function persistedPositions(calls: unknown[][]): Array<{ x?: number; y?: number }> { const written: Array<{ x?: number; y?: number }> = []; for (const call of calls) { const mutation = call[1] as { properties?: Record; - keyframes?: Array<{ properties: Record }>; + keyframes?: Array<{ percentage: number; properties: Record }>; x?: number; y?: number; }; - const sources = [mutation.properties, ...(mutation.keyframes ?? []).map((k) => k.properties)]; + const atPlayhead = (mutation.keyframes ?? []).filter((k) => k.percentage === 0); + const sources = [mutation.properties, ...atPlayhead.map((k) => k.properties)]; if (mutation.x != null || mutation.y != null) written.push({ x: mutation.x, y: mutation.y }); for (const source of sources) { if (source && (source.x != null || source.y != null)) diff --git a/packages/studio/src/hooks/gsapResizeElementSize.test.tsx b/packages/studio/src/hooks/gsapResizeElementSize.test.tsx index 6ff66863853..712f3ac876b 100644 --- a/packages/studio/src/hooks/gsapResizeElementSize.test.tsx +++ b/packages/studio/src/hooks/gsapResizeElementSize.test.tsx @@ -37,6 +37,7 @@ const widthTween = { position: 0, resolvedStart: 0, duration: 4, + ease: "none", } as unknown as GsapAnimation; function mount(animations: GsapAnimation[]) { diff --git a/packages/studio/src/hooks/gsapResizeGeometrySweep.test.ts b/packages/studio/src/hooks/gsapResizeGeometrySweep.test.ts index 20585969761..c9a97c9c3da 100644 --- a/packages/studio/src/hooks/gsapResizeGeometrySweep.test.ts +++ b/packages/studio/src/hooks/gsapResizeGeometrySweep.test.ts @@ -23,17 +23,13 @@ * the way through. A sweep across rotations is what tells us it is. */ import { afterEach, expect, it, vi } from "vitest"; -import { classifyTweenPropertyGroup } from "@hyperframes/core/gsap-parser"; import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; import { usePlayerStore } from "../player/store/playerStore"; +import { elTween, resetGsapEditState } from "./gsapParsedTween.test-helpers"; import { tryGsapResizeIntercept } from "./gsapResizeIntercept"; -afterEach(() => { - vi.restoreAllMocks(); - usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); - document.body.innerHTML = ""; -}); +afterEach(resetGsapEditState); const LAYOUT = { left: 120, top: 520 }; @@ -57,20 +53,6 @@ function renderRect(pose: Pose, rotationDeg: number) { type Props = Record; -function tween(id: string, properties: Props, duration: number): GsapAnimation { - return { - id, - targetSelector: "#el", - propertyGroup: classifyTweenPropertyGroup(properties), - method: "to", - properties, - position: 0, - resolvedStart: 0, - duration, - ...(duration === 0 ? { extras: { immediateRender: "__raw:true" } } : {}), - } as unknown as GsapAnimation; -} - interface Case { name: string; /** The element's untransformed CSS box. */ @@ -99,18 +81,24 @@ const ROTATIONS = [0, -8, 45, -47, 90, 180]; * the size routes here however it looks from the animation list. */ const ROUTES = { - "scale tween": { animations: () => [tween("#el-scale", { scale: 1 }, 2)], settles: true }, + "scale tween": { + animations: () => [elTween("#el-scale", { scale: 1 }, 2, "none")], + settles: true, + }, "scale longhands": { - animations: () => [tween("#el-scale", { scaleX: 1, scaleY: 1 }, 2)], + animations: () => [elTween("#el-scale", { scaleX: 1, scaleY: 1 }, 2, "none")], settles: true, }, - "scale instant hold": { animations: () => [tween("#el-scale", { scale: 1 }, 0)], settles: false }, + "scale instant hold": { + animations: () => [elTween("#el-scale", { scale: 1 }, 0, "none")], + settles: false, + }, "size tween": { - animations: () => [tween("#el-size", { width: 630, height: 408 }, 2)], + animations: () => [elTween("#el-size", { width: 630, height: 408 }, 2, "none")], settles: false, }, "size instant hold": { - animations: () => [tween("#el-size", { width: 630, height: 408 }, 0)], + animations: () => [elTween("#el-size", { width: 630, height: 408 }, 0, "none")], settles: false, }, } as const; diff --git a/packages/studio/src/hooks/gsapResizeIntercept.test.ts b/packages/studio/src/hooks/gsapResizeIntercept.test.ts index 72e8b33a2f3..1fb7afe9f97 100644 --- a/packages/studio/src/hooks/gsapResizeIntercept.test.ts +++ b/packages/studio/src/hooks/gsapResizeIntercept.test.ts @@ -7,7 +7,8 @@ import { observeGsapGesture } from "./gsapGestureOutcome"; import { trackStudioEvent } from "../utils/studioTelemetry"; import type { CommitMutation } from "./gsapScriptCommitTypes"; import { computeCurrentPercentage } from "./gsapDragCommit"; -import { tryGsapResizeIntercept } from "./gsapResizeIntercept"; +import { commitSizeAtPlayhead, tryGsapResizeIntercept } from "./gsapResizeIntercept"; +import { liveTween, previewWith, tween } from "./gsapParsedTween.test-helpers"; vi.mock("../utils/studioTelemetry", () => ({ trackStudioEvent: vi.fn() })); @@ -15,6 +16,8 @@ afterEach(() => { vi.clearAllMocks(); vi.restoreAllMocks(); usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); + // One #clip per test: leftovers would make every tween on it look shared. + document.body.innerHTML = ""; }); /** @@ -42,10 +45,18 @@ function fakeIframe(el: HTMLElement, gsapValues: Record) { // The element's OPACITY intro tween lives on the timeline: unfiltered // capture would pick `opacity` up via the other-tween sweep. const opacityIntro = { targets: () => [el], vars: { opacity: 0, duration: 0.8 } }; + const scaleIntro = liveTween( + el, + { start: 0.2, duration: 0.8, vars: { scale: 0.9 }, ends: { scaleX: [0.9, 1] } }, + { from: true }, + ); return { contentWindow: { - __timelines: { main: { getChildren: () => [opacityIntro] } }, - gsap: { getProperty: (_el: Element, prop: string) => gsapValues[prop] ?? 0 }, + __timelines: { main: { getChildren: () => [opacityIntro, scaleIntro] } }, + gsap: { + getProperty: (_el: Element, prop: string) => gsapValues[prop] ?? 0, + defaults: () => ({ ease: "power1.out" }), + }, }, contentDocument: document, } as unknown as HTMLIFrameElement; @@ -295,24 +306,26 @@ async function runResize( return committed; } -it("scale-route resize converts via the group filter and commits scale, not width/height", async () => { +it("scale-route resize keyframes scale through the group filter, not width/height", async () => { const el = makeGradedElement(); const iframe = fakeIframe(el, { scale: 1, scaleX: 1, scaleY: 1, opacity: 0, rotation: 0 }); // uniform: 800/640 === 450/360 const committed = await runResize(el, iframe, { width: 800, height: 450 }); - const convert = committed.find((m) => m.type === "convert-to-keyframes"); - expect(convert).toBeDefined(); - const fromValues = convert!.resolvedFromValues as Record; - // Group filter: the opacity intro tween must NOT leak into the conversion. - expect(fromValues).not.toHaveProperty("opacity"); - expect(fromValues).toHaveProperty("scale"); + const keyframes = committed.find((m) => m.type === "replace-with-keyframes")?.keyframes as + | Array<{ properties: Record }> + | undefined; + // Group filter: the opacity intro tween must NOT leak into the scale keyframes. + expect(keyframes?.some((k) => "opacity" in k.properties)).toBe(false); + expect(keyframes?.some((k) => "scale" in k.properties)).toBe(true); // Every committed property is scale-group — the resize never writes // width/height for a scale-driven element (the double-apply bug class). const allProps = committed.flatMap((m) => [ ...Object.keys((m.properties as Record) ?? {}), - ...Object.keys((m.resolvedFromValues as Record) ?? {}), + ...((m.keyframes as Array<{ properties: object }>) ?? []).flatMap((k) => + Object.keys(k.properties), + ), ]); expect(allProps).not.toContain("width"); expect(allProps).not.toContain("height"); @@ -560,6 +573,45 @@ it("hands the size to the element's CSS when its only tween is a fade", async () expect(commitMutation).not.toHaveBeenCalled(); }); +it.each([ + ["stays put", { x: 0, y: 0 }, { width: 300 }, undefined], + ["moves", { x: -40, y: 0 }, { width: 300, x: 10, y: 0 }, true], +])( + "a size written at the playhead carries the anchor only when the box %s", + async (_, offset, written, owns) => { + const selection = titleSelection(); + const el = selection.element; + el.setAttribute("data-hf-drag-gsap-base-x", "50"); + el.setAttribute("data-hf-drag-gsap-base-y", "0"); + const slide = tween({ + id: "#title-to-0", + targetSelector: "#title", + propertyGroup: undefined, + method: "to", + properties: { x: 100, width: 320 }, + resolvedStart: 0, + duration: 2, + ease: "none", + }); + usePlayerStore.setState({ currentTime: 1 }); + const commitMutation = vi.fn(); + const live = liveTween(el, { start: 0, duration: 2, vars: slide.properties }); + + const outcome = await commitSizeAtPlayhead( + selection, + slide, + { width: 300 }, + previewWith(el, [live]), + offset, + { commitMutation }, + ); + + expect(outcome.ownsDragOffset).toBe(owns); + const mutation = commitMutation.mock.calls[0]![1]; + expect(mutation.keyframes[0].properties).toEqual(written); + }, +); + it.each([ [5, 1], [0.5, 1], diff --git a/packages/studio/src/hooks/gsapResizeIntercept.ts b/packages/studio/src/hooks/gsapResizeIntercept.ts index 5cc3c93e592..8795a379573 100644 --- a/packages/studio/src/hooks/gsapResizeIntercept.ts +++ b/packages/studio/src/hooks/gsapResizeIntercept.ts @@ -14,43 +14,34 @@ import { } from "../components/editor/manualEditsTypes"; import { setElementGsapPosition, setElementGsapScale } from "../utils/elementGsap"; import { usePlayerStore } from "../player/store/playerStore"; -import { readAllAnimatedProperties, readGsapProperty } from "./gsapRuntimeReaders"; +import { readGsapProperty } from "./gsapRuntimeReaders"; import { commitStaticGsapPosition, commitStaticGsapSize, - commitKeyframedSizeFromResize, computeCurrentPercentage, findExistingPositionWrite, findSizeSetAnimation, - materializeIfDynamic, } from "./gsapDragCommit"; import type { GsapDragCommitCallbacks } from "./gsapDragCommit"; -import { computeDraggedGsapPosition } from "./draggedGsapPosition"; +import { computeDraggedGsapPosition, restoreDragOffset } from "./draggedGsapPosition"; import { pickClosestToPlayhead, readGsapPositionFromIframe } from "./gsapPositionDetection"; import { commitWholePropertyOffset } from "./gsapWholePropertyOffsetCommit"; import { commitGsapPositionFromDrag } from "./gsapDragPositionCommit"; -import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler"; +import { resolveTweenDuration } from "../utils/globalTimeCompiler"; import { isInstantHold, selectorFromSelection, writeTargetSelector } from "./gsapShared"; import { roundTo3, roundToLayoutPx } from "../utils/rounding"; import { resolveGroupTween } from "./gsapRuntimeBridge"; import { logResize } from "../utils/resizeDebug"; -import { animationWritesAnyProperty, type GsapEditOutcome } from "./gsapEditOutcome"; +import { + animationWritesAnyProperty, + assertGsapEditPersisted, + type GsapEditOutcome, +} from "./gsapEditOutcome"; +import { commitValueAtPlayhead } from "./gsapValueAtPlayhead"; import { preflightGsapResizeIntercept, resizeRoute } from "./gsapResizePreflight"; -const IDENTITY_ONE_PROPS = new Set(["opacity", "autoAlpha", "scale", "scaleX", "scaleY"]); const SIZE_PROPS = new Set(["width", "height"]); - -/** Build identity (zero / one) values for each property in `source`. */ -function synthesizeIdentityProps( - source: Record, -): Record { - const id: Record = {}; - for (const [k, v] of Object.entries(source)) { - if (typeof v === "number") id[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0; - else id[k] = v; - } - return id; -} +const POSITION_XY = new Set(["x", "y"]); /** * The element's box before the resize draft ran, in CSS pixels. @@ -72,6 +63,51 @@ function originalBoxSize( return Number.isFinite(inline) && inline > 0 ? inline : null; } +/** The box's width and height before the draft, for a size tween that animates only one. */ +function preGestureBoxSize(el: HTMLElement): Record { + const width = originalBoxSize(el, STUDIO_ORIGINAL_BOX_WIDTH_ATTR, "width"); + const height = originalBoxSize(el, STUDIO_ORIGINAL_BOX_HEIGHT_ATTR, "height"); + return { ...(width != null && { width }), ...(height != null && { height }) }; +} + +/** A size write at the playhead. When the same tween animates position, the resize's anchor move + * goes into this one write: a second write to the tween in the same gesture would plan on stale ids. */ +export async function commitSizeAtPlayhead( + selection: DomEditSelection, + anim: GsapAnimation, + size: Record, + iframe: HTMLIFrameElement | null, + dragOffset: { x: number; y: number } | undefined, + callbacks: GsapDragCommitCallbacks, +): Promise { + const selector = selectorFromSelection(selection); + const moves = !!dragOffset && (dragOffset.x !== 0 || dragOffset.y !== 0) && !!selector; + const anchor = + moves && animationWritesAnyProperty(anim, POSITION_XY) + ? computeDraggedGsapPosition( + selection.element, + dragOffset, + readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 }, + ) + : null; + const written = await commitValueAtPlayhead( + selection, + anim, + anchor ? { ...size, x: anchor.newX, y: anchor.newY } : size, + iframe, + callbacks, + { + label: "Resize", + backfill: { + ...preGestureBoxSize(selection.element), + ...(anchor && { x: anchor.baseGsapX, y: anchor.baseGsapY }), + }, + ...(anchor && { beforeReload: () => restoreDragOffset(selection.element) }), + }, + ); + return written.status === "persisted" && anchor ? { ...written, ownsDragOffset: true } : written; +} + /** * Whether this tween already states scale as `scaleX`/`scaleY`. * @@ -98,6 +134,7 @@ export async function tryGsapResizeIntercept( iframe: HTMLIFrameElement | null, commitMutation: GsapDragCommitCallbacks["commitMutation"], fetchFallbackAnimations?: () => Promise, + dragOffset?: { x: number; y: number }, ): Promise { const fetchedAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : []; const outcome = preflightGsapResizeIntercept(selection, animations, iframe, fetchedAnimations); @@ -120,7 +157,7 @@ export async function tryGsapResizeIntercept( postSplitFetch, ); - let anim = + const anim = resolved?.anim && animationWritesAnyProperty(resolved.anim, resizeProperties) ? resolved.anim : null; @@ -166,15 +203,11 @@ export async function tryGsapResizeIntercept( ); if (animatedTween) { logResize("intercept-route", { route: "keyframed-size", tweenId: animatedTween.id }); - const handled = await commitKeyframedSizeFromResize( - selection, - size, - sel, - sizeSet, - animatedTween, - { commitMutation, fetchAnimations: fetchFallbackAnimations }, - ); - if (handled) return { status: "persisted" }; + const sized = { width: roundToLayoutPx(size.width), height: roundToLayoutPx(size.height) }; + return commitSizeAtPlayhead(selection, animatedTween, sized, iframe, dragOffset, { + commitMutation, + fetchAnimations: fetchFallbackAnimations, + }); } } @@ -196,16 +229,10 @@ export async function tryGsapResizeIntercept( const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim); - if (activeKeyframePct != null) setActiveKeyframePct(null); const selector = selectorFromSelection(selection); - // Scope every capture to the resize group — same contract as the rotation - // intercept. Unfiltered, an opacity-touching intro tween on the element - // would ride into resize conversions/backfills (the Fix-2 bake class). - const runtimeProps = selector - ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) - : {}; let resizeProps: Record; + let resizeBackfill: Record; let scaleDraftEl: HTMLElement | null = null; let scaleDraftDropPoint: { x: number; y: number } | null = null; /** The scale this commit is putting on the element, for the finalize step. */ @@ -262,6 +289,7 @@ export async function tryGsapResizeIntercept( resizeProps = useScaleLonghands ? { scaleX: newScaleX, scaleY: newScaleY } : { scale: newScaleX }; + resizeBackfill = { scaleX: liveScaleX, scaleY: liveScaleY }; logResize("intercept-route", { route: "scale-tween", cssW, @@ -295,6 +323,7 @@ export async function tryGsapResizeIntercept( width: roundToLayoutPx(size.width), height: roundToLayoutPx(size.height), }; + resizeBackfill = preGestureBoxSize(selection.element); } // Finalize a scale-route commit: tear down the gesture's inline width/height // draft (leaving it applied compounds with the committed scale — the element @@ -404,10 +433,12 @@ export async function tryGsapResizeIntercept( ); if (positionTween) { logResize("scale-finalize", { route: "position-keyframe", tweenId: positionTween.id }); - await commitGsapPositionFromDrag(selection, positionTween, delta, base, iframe, selector, { - commitMutation, - fetchAnimations: fetchFallbackAnimations, - }); + assertGsapEditPersisted( + await commitGsapPositionFromDrag(selection, positionTween, delta, base, iframe, { + commitMutation, + fetchAnimations: fetchFallbackAnimations, + }), + ); return true; } const existingSet = findExistingPositionWrite(currentAnimations, selector, selection.element); @@ -435,135 +466,14 @@ export async function tryGsapResizeIntercept( return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() }; } - const ct = usePlayerStore.getState().currentTime; - const ts = resolveTweenStart(anim); - const td = tweenDuration; - const outsideRange = ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01); // Convert flat tweens to keyframes only for in-range resizes. - // Outside-range uses the extend path which handles everything atomically. - if (!outsideRange) { - // fallow-ignore-next-line code-duplication - if (anim.hasUnresolvedKeyframes || anim.hasUnresolvedSelector) { - const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection); - if (newId) anim = { ...anim, id: newId }; - } else if (!anim.keyframes) { - const resolvedFromValues = selector - ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) - : undefined; - await commitMutation( - selection, - { type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues }, - { label: "Convert to keyframes for resize" }, - ); - if (fetchFallbackAnimations) { - const fresh = await fetchFallbackAnimations(); - const refreshed = fresh.find( - (a) => a.targetSelector === anim!.targetSelector && a.keyframes, - ); - if (refreshed) anim = refreshed; - } - } - } - - // A NON-uniform scale must also take the full-rewrite path: it mixes - // scaleX/scaleY into a tween whose existing keyframes may carry the uniform - // `scale` shorthand, and GSAP's percentage keyframes animate each property - // name independently — a shorthand/longhand mix would leave the old `scale` - // sub-tween running against the new scaleX/scaleY. The rewrite below - // normalizes every keyframe to the longhands. For an in-range resize the - // min/max window math below degenerates to the tween's own start/duration, - // so timing is unchanged. - if ((outsideRange || useScaleLonghands) && ts !== null) { - // For flat tweens, synthesize the keyframes from the tween's properties - const kfs = - anim.keyframes?.keyframes ?? - (() => { - const fromProps = - anim.method === "from" || anim.method === "fromTo" - ? { ...anim.properties } - : synthesizeIdentityProps(anim.properties); - const toProps = - anim.method === "from" - ? synthesizeIdentityProps(anim.properties) - : { ...anim.properties }; - return [ - { percentage: 0, properties: fromProps }, - { percentage: 100, properties: toProps }, - ]; - })(); - const newStart = Math.min(ct, ts); - const newEnd = Math.max(ct, ts + td); - const newDuration = Math.max(0.01, newEnd - newStart); - const existingKfs = kfs; - const remapped: Array<{ percentage: number; properties: Record }> = []; - for (const kf of existingKfs) { - const absTime = ts + (kf.percentage / 100) * td; - const newPct = Math.round(((absTime - newStart) / newDuration) * 1000) / 10; - const props = { ...kf.properties }; - // Normalize the uniform `scale` shorthand to longhands when this commit - // writes scaleX/scaleY, so the tween never mixes the two forms. - if (nonUniformScale && "scale" in props) { - const uniform = props.scale; - if (typeof uniform === "number") { - props.scaleX = uniform; - props.scaleY = uniform; - } - delete props.scale; - } - // Only backfill properties that the animation already had (x, y, scale). - // Don't backfill width/height — they should only appear on the resize keyframe. - for (const k of Object.keys(resizeProps)) { - if (k in props) continue; - if (k === "width" || k === "height") continue; - props[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0; - } - remapped.push({ percentage: newPct, properties: props }); - } - const targetPct = Math.round(((ct - newStart) / newDuration) * 1000) / 10; - // An in-range rewrite can land on an existing keyframe's percentage — - // merge into it instead of emitting a duplicate step. - const collidingKf = remapped.find((kf) => Math.abs(kf.percentage - targetPct) < 0.05); - if (collidingKf) Object.assign(collidingKf.properties, resizeProps); - else remapped.push({ percentage: targetPct, properties: resizeProps }); - remapped.sort((a, b) => a.percentage - b.percentage); - - await commitMutation( - selection, - { - type: "replace-with-keyframes", - animationId: anim.id, - targetSelector: anim.targetSelector, - position: roundTo3(newStart), - duration: roundTo3(newDuration), - keyframes: remapped, - }, - { - label: outsideRange - ? `Resize (extended to ${ct.toFixed(2)}s)` - : `Resize (keyframe ${Math.round(((ct - newStart) / newDuration) * 1000) / 10}%)`, - softReload: true, - ...(!collidingKf ? { keyframeAction: "add" as const } : {}), - }, - ); - return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() }; - } - - const backfillDefaults: Record = {}; - for (const k of Object.keys(runtimeProps)) { - if (SIZE_PROPS.has(k)) continue; - backfillDefaults[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0; - } - - await commitMutation( - selection, - { - type: "add-keyframe", - animationId: anim.id, - percentage: pct, - properties: resizeProps, - backfillDefaults, - }, - { label: `Resize (keyframe ${pct}%)`, softReload: true }, - ); + const callbacks = { commitMutation, fetchAnimations: fetchFallbackAnimations }; + if (resizeGroup === "size") + return commitSizeAtPlayhead(selection, anim, resizeProps, iframe, dragOffset, callbacks); + const written = await commitValueAtPlayhead(selection, anim, resizeProps, iframe, callbacks, { + label: "Resize", + backfill: resizeBackfill, + }); + if (written.status !== "persisted") return written; return { status: "persisted", ownsDragOffset: await finalizeScaleResizeCommit() }; } diff --git a/packages/studio/src/hooks/gsapResizeSweep.test.ts b/packages/studio/src/hooks/gsapResizeSweep.test.ts index 43e2b976819..f2381bf8434 100644 --- a/packages/studio/src/hooks/gsapResizeSweep.test.ts +++ b/packages/studio/src/hooks/gsapResizeSweep.test.ts @@ -23,57 +23,40 @@ import { classifyTweenPropertyGroup } from "@hyperframes/core/gsap-parser"; import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; import { usePlayerStore } from "../player/store/playerStore"; +import { elTween, resetGsapEditState } from "./gsapParsedTween.test-helpers"; import { tryGsapResizeIntercept } from "./gsapResizeIntercept"; -afterEach(() => { - vi.restoreAllMocks(); - usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); - document.body.innerHTML = ""; -}); +afterEach(resetGsapEditState); type Props = Record; -function tween(id: string, properties: Props, duration: number): GsapAnimation { - return { - id, - targetSelector: "#el", - propertyGroup: classifyTweenPropertyGroup(properties), - method: "to", - properties, - position: 0, - resolvedStart: 0, - duration, - ...(duration === 0 ? { extras: { immediateRender: "__raw:true" } } : {}), - } as unknown as GsapAnimation; -} - /** The dimensions an element's animations actually vary across. */ const SCALE = { none: null, - "instant hold": () => tween("#el-scale", { scale: 1.2 }, 0), - tween: () => tween("#el-scale", { scale: 1.2 }, 2), - longhands: () => tween("#el-scale", { scaleX: 1.2, scaleY: 1.1 }, 2), + "instant hold": () => elTween("#el-scale", { scale: 1.2 }, 0), + tween: () => elTween("#el-scale", { scale: 1.2 }, 2), + longhands: () => elTween("#el-scale", { scaleX: 1.2, scaleY: 1.1 }, 2), } as const; const SIZE = { none: null, - "instant hold": () => tween("#el-size", { width: 300, height: 200 }, 0), - tween: () => tween("#el-size", { width: 300, height: 200 }, 2), + "instant hold": () => elTween("#el-size", { width: 300, height: 200 }, 0), + tween: () => elTween("#el-size", { width: 300, height: 200 }, 2), } as const; const POSITION = { none: null, - "static hold": () => tween("#el-position", { x: 40, y: 60 }, 0), - tween: () => tween("#el-position", { x: 40, y: 60 }, 2), + "static hold": () => elTween("#el-position", { x: 40, y: 60 }, 0), + tween: () => elTween("#el-position", { x: 40, y: 60 }, 2), } as const; const EXTRA = { none: null, // What a 3D card carries, and the shape that produced two same-group ids. "3d and rotation": () => [ - tween("#el-other", { rotationY: -540, rotationX: 720, _auto: 0 }, 0), - tween("#el-rotation", { rotation: 720 }, 0), - tween("#el-other-2", { z: 50 }, 0), + elTween("#el-other", { rotationY: -540, rotationX: 720, _auto: 0 }, 0), + elTween("#el-rotation", { rotation: 720 }, 0), + elTween("#el-other-2", { z: 50 }, 0), ], // A tween that already spans two groups, which the resize has to split. - "a mixed tween": () => [tween("#el-mixed", { scale: 1.2, width: 300, height: 200 }, 0)], + "a mixed tween": () => [elTween("#el-mixed", { scale: 1.2, width: 300, height: 200 }, 0)], } as const; interface Recorded { @@ -113,7 +96,7 @@ function fakeSource(initial: GsapAnimation[]) { current = [ ...current.filter((animation) => animation.id !== id), ...[...byGroup].map(([group, properties]) => - tween(`#el-split-${group}`, properties, target.duration ?? 0), + elTween(`#el-split-${group}`, properties, target.duration ?? 0), ), ]; }; @@ -123,7 +106,7 @@ function fakeSource(initial: GsapAnimation[]) { if (mutation.type === "split-into-property-groups") return id && split(id); if (!id) { if (mutation.type === "add") - current = [...current, tween(`#el-added-${current.length}`, properties, 0)]; + current = [...current, elTween(`#el-added-${current.length}`, properties, 0)]; return; } mergeInto(id, properties); @@ -224,7 +207,7 @@ it(`sweeps ${CASES.length} animated shapes without a stale id or a mixed tween`, */ function scaleAt(id: string, position: number): GsapAnimation { return { - ...tween(id, { scale: 1 }, 2), + ...elTween(id, { scale: 1 }, 2), position, resolvedStart: position, keyframes: { diff --git a/packages/studio/src/hooks/gsapRuntimeBridge.sharedTween.test.ts b/packages/studio/src/hooks/gsapRuntimeBridge.sharedTween.test.ts index 3d9fe60e73b..87335035446 100644 --- a/packages/studio/src/hooks/gsapRuntimeBridge.sharedTween.test.ts +++ b/packages/studio/src/hooks/gsapRuntimeBridge.sharedTween.test.ts @@ -121,7 +121,7 @@ describe("tryGsapDragIntercept: which tweens a word's drag may use", () => { }); describe("tryGsapDragIntercept: one drag is one undo step", () => { - it("records the split and the move under one gesture key", async () => { + it("records the move under one gesture key, without splitting the mixed tween", async () => { document.body.innerHTML = `
`; const hero = document.getElementById("hero")!; const mixed = { @@ -133,12 +133,8 @@ describe("tryGsapDragIntercept: one drag is one undo step", () => { position: 0, resolvedStart: 0, duration: 1, + ease: "none", } as unknown as GsapAnimation; - const split = [ - { ...mixed, id: "#hero-fromTo-0-position", propertyGroup: "position" }, - { ...mixed, id: "#hero-fromTo-0-opacity", propertyGroup: "opacity" }, - ] as GsapAnimation[]; - let fetches = 0; const commitMutation = vi.fn(); await tryGsapDragIntercept( { id: "hero", selector: "#hero", element: hero } as unknown as DomEditSelection, @@ -146,10 +142,12 @@ describe("tryGsapDragIntercept: one drag is one undo step", () => { [mixed], null, commitMutation, - async () => (fetches++ === 0 ? [mixed] : split), + async () => [mixed], ); + const types = commitMutation.mock.calls.map((call) => call[1].type); const options = commitMutation.mock.calls.map((call) => call[2]); - expect(options.length).toBeGreaterThan(1); + expect(types).not.toContain("split-into-property-groups"); + expect(options.length).toBeGreaterThan(0); expect(new Set(options.map((o) => o.coalesceKey)).size).toBe(1); expect(options[0].coalesceKey).toMatch(/^gsap:drag:/); expect(options.every((o) => o.coalesceMs === Number.POSITIVE_INFINITY)).toBe(true); diff --git a/packages/studio/src/hooks/gsapRuntimeBridge.test.ts b/packages/studio/src/hooks/gsapRuntimeBridge.test.ts index d6f206b51cb..4c4fb101f39 100644 --- a/packages/studio/src/hooks/gsapRuntimeBridge.test.ts +++ b/packages/studio/src/hooks/gsapRuntimeBridge.test.ts @@ -23,7 +23,7 @@ function fakeIframe(elId: string, children: unknown[]): HTMLIFrameElement { return { contentWindow: { __timelines: { "index.html": timeline }, - gsap: { getProperty: () => 0 }, + gsap: { getProperty: () => 0, defaults: () => ({ ease: "power1.out" }) }, }, contentDocument: { querySelector: (sel: string) => (sel === `#${elId}` ? el : null) }, } as unknown as HTMLIFrameElement; @@ -451,7 +451,8 @@ describe("tryGsapDragIntercept — autoKeyframeEnabled toggle (#1808)", () => { fakeIframe("puck-b", []), commitMutation, ); - return { handled, types: commitMutation.mock.calls.map(([, mutation]) => mutation.type) }; + const mutations = commitMutation.mock.calls.map(([, mutation]) => mutation); + return { handled, mutations, types: mutations.map((mutation) => mutation.type) }; } it("shifts the whole tween instead of adding a keyframe when the toggle is off", async () => { @@ -461,10 +462,40 @@ describe("tryGsapDragIntercept — autoKeyframeEnabled toggle (#1808)", () => { expect(types).not.toContain("add-keyframe"); }); - it("still adds/updates a keyframe at the playhead when the toggle is on (default)", async () => { - const { handled, types } = await runAutoKeyframeDrag(true); + it("shifts a linear flat tween as keyframes that stay linear", async () => { + usePlayerStore.setState({ autoKeyframeEnabled: false, currentTime: 1 }); + const commitMutation = vi.fn(); + const linear = { ...stalePositionAnim, ease: "none" } as GsapAnimation; + const live = { + targets: () => [{ id: "puck-b" }], + vars: { x: -180, y: -60, ease: "none" }, + duration: () => 2, + startTime: () => 1, + }; + await tryGsapDragIntercept( + selection, + { x: -50, y: 0 }, + [linear], + fakeIframe("puck-b", [live]), + commitMutation, + ); + const [mutation] = commitMutation.mock.calls.map(([, m]) => m); + expect(mutation).toMatchObject({ type: "replace-with-keyframes", easeEach: "none" }); + expect(mutation).not.toHaveProperty("ease", "none"); + }); + + it("still changes only the keyframe at the playhead when the toggle is on (default)", async () => { + const { handled, mutations } = await runAutoKeyframeDrag(true); expect(handled).toEqual({ status: "persisted" }); - expect(types).not.toContain("replace-with-keyframes"); + expect(mutations).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + keyframes: [ + { percentage: 0, properties: { x: 0, y: 0 } }, + { percentage: 100, properties: { x: -50, y: 0 } }, + ], + }), + ]); }); }); @@ -540,7 +571,11 @@ describe("tryGsapDragIntercept — motion paths", () => { ], ease: "none", }, - expect.objectContaining({ label: "Move layer (new keyframe)", softReload: true }), + expect.objectContaining({ + label: "Move layer (new keyframe)", + keyframeAction: "add", + softReload: true, + }), ); expect(commitMutation.mock.calls.map(([, mutation]) => mutation.type)).not.toContain( "add-motion-path-point", diff --git a/packages/studio/src/hooks/gsapRuntimeBridge.ts b/packages/studio/src/hooks/gsapRuntimeBridge.ts index fb00fe2f717..b4d4c85da1b 100644 --- a/packages/studio/src/hooks/gsapRuntimeBridge.ts +++ b/packages/studio/src/hooks/gsapRuntimeBridge.ts @@ -9,12 +9,13 @@ * easing, or seek position. */ import type { GsapAnimation, PropertyGroupName } from "@hyperframes/core/gsap-parser"; -import { isXYPositionWrite } from "@hyperframes/parsers/gsap-constants"; +import { isXYPositionWrite, PROPERTY_GROUPS } from "@hyperframes/parsers/gsap-constants"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; import { usePlayerStore } from "../player/store/playerStore"; import { readAllAnimatedProperties, readGsapProperty } from "./gsapRuntimeReaders"; -import { commitGsapPositionFromDrag } from "./gsapDragPositionCommit"; +import { commitGsapPositionFromDrag, gsapPositionFromDragOutcome } from "./gsapDragPositionCommit"; +import { commitValueAtPlayhead } from "./gsapValueAtPlayhead"; import { commitStaticGsapPosition, commitStaticGsapRotation, @@ -22,7 +23,6 @@ import { computeCurrentPercentage, findExistingPositionWrite, findRotationSetAnimation, - materializeIfDynamic, } from "./gsapDragCommit"; import { commitWholePropertyOffset } from "./gsapWholePropertyOffsetCommit"; import { isGestureTransactionCommit } from "./gestureTransaction"; @@ -54,64 +54,29 @@ const ROTATION_CHANNEL_SET = new Set(ROTATION_CHANNELS); // ── Property-group tween resolution ─────────────────────────────────────── /** - * Find the tween for a given property group, splitting a legacy mixed tween - * if necessary. Returns the resolved animation or null if none exists. - * - * Resolution order: - * 1. Tween already tagged with `propertyGroup === group` - * 2. Legacy mixed tween (`!propertyGroup`) → split via server mutation, - * re-fetch, then return the group tween - * 3. null — caller must handle the missing-tween case + * The tween to edit for a property group: a tween tagged with it, else a legacy tween that mixes + * it with other groups. A mixed tween is edited in place, never split first: inside a gesture the + * split is only buffered, so ids read after it are stale and the edit lands beside the old tween. */ export async function resolveGroupTween( group: PropertyGroupName, animations: GsapAnimation[], - selection: DomEditSelection, - commitMutation: GsapDragCommitCallbacks["commitMutation"], + _selection: DomEditSelection, + _commitMutation: GsapDragCommitCallbacks["commitMutation"], fetchFallbackAnimations?: () => Promise, ): Promise<{ anim: GsapAnimation; animations: GsapAnimation[] } | null> { - // 1. Already-split group tween — pick the one closest to the current - // playhead so a drag at t=6s edits the tween at 4s, not the one at 1.5s. - const groupAnims = animations.filter((a) => a.propertyGroup === group); - const groupAnim = pickClosestToPlayhead(groupAnims); - if (groupAnim) return { anim: groupAnim, animations }; - - // 2. Legacy mixed tween — split it, then re-fetch - const legacyMixed = animations.find((a) => !a.propertyGroup); - if (legacyMixed) { - await commitMutation( - selection, - { type: "split-into-property-groups", animationId: legacyMixed.id }, - { label: "Split mixed tween into property groups", skipReload: true }, - ); - if (fetchFallbackAnimations) { - const fresh = await fetchFallbackAnimations(); - const freshGroupAnim = fresh.find((a) => a.propertyGroup === group); - if (freshGroupAnim) return { anim: freshGroupAnim, animations: fresh }; - } - } - - // 3. Try fallback fetch (no split needed, just wasn't in the initial list) - if (!legacyMixed && fetchFallbackAnimations) { - const fresh = await fetchFallbackAnimations(); - const freshGroupAnim = fresh.find((a) => a.propertyGroup === group); - if (freshGroupAnim) return { anim: freshGroupAnim, animations: fresh }; - - // Fallback: legacy mixed in the fresh list - const freshLegacy = fresh.find((a) => !a.propertyGroup); - if (freshLegacy) { - await commitMutation( - selection, - { type: "split-into-property-groups", animationId: freshLegacy.id }, - { label: "Split mixed tween into property groups", skipReload: true }, - ); - const reFetched = await fetchFallbackAnimations(); - const reFetchedGroup = reFetched.find((a) => a.propertyGroup === group); - if (reFetchedGroup) return { anim: reFetchedGroup, animations: reFetched }; - } - } - - return null; + const inGroup = (list: GsapAnimation[]) => { + const tagged = list.filter((a) => a.propertyGroup === group); + const props = new Set(PROPERTY_GROUPS[group]); + const mixed = list.filter((a) => !a.propertyGroup && animationWritesAnyProperty(a, props)); + return pickClosestToPlayhead(tagged.length > 0 ? tagged : mixed); + }; + const anim = inGroup(animations); + if (anim) return { anim, animations }; + if (!fetchFallbackAnimations) return null; + const fresh = await fetchFallbackAnimations(); + const freshAnim = inGroup(fresh); + return freshAnim ? { anim: freshAnim, animations: fresh } : null; } // ── High-level intercept ─────────────────────────────────────────────────── @@ -205,6 +170,59 @@ function oneUndoStep( commit(selection, mutation, { ...options, coalesceKey, coalesceMs: Number.POSITIVE_INFINITY }); } +const isPositionWriteOf = (selector: string) => (a: GsapAnimation) => + a.targetSelector === selector && isXYPositionWrite(a); + +/** The one position write a self-heal keeps when holds fight over `selector`, else null. */ +function positionWriteKeeper(animations: GsapAnimation[], selector: string): GsapAnimation | null { + const dupes = animations.filter(isPositionWriteOf(selector)); + // Real tweens one after another are a motion, not a conflict: only holds can fight. + if (dupes.length < 2 || dupes.filter((a) => !isInstantHold(a)).length > 1) return null; + return dupes.find((a) => a.keyframes) ?? dupes.find((a) => (a.duration ?? 0) > 0) ?? dupes[0]!; +} + +/** Where a drag writes. With no live motion and no keyframed tween (a hold, or a + * zero-length keyframed tween) the position belongs in a `tl.set`, never keyframes. */ +function dragRoute( + posAnim: GsapAnimation | null, + iframe: HTMLIFrameElement | null, + selector: string, + altKey?: boolean, +): "static" | "whole-path" | "at-playhead" { + const hasNonHold = hasNonHoldTweenForElement(iframe, selector, undefined, POSITION_CHANNELS); + const hasKeyframedPosTween = !!posAnim?.keyframes && resolveTweenDuration(posAnim) > 0; + if (!hasNonHold && !hasKeyframedPosTween) return "static"; + // Alt-drag shifts the whole path; with auto-keyframe off (#1808) that is the default. + return altKey || !usePlayerStore.getState().autoKeyframeEnabled ? "whole-path" : "at-playhead"; +} + +/** The commit's route and keyframe plan, writing nothing, so a group refuses whole. */ +async function planDrag( + selection: DomEditSelection, + offset: { x: number; y: number }, + allAnimations: GsapAnimation[], + iframe: HTMLIFrameElement | null, + options: { altKey?: boolean }, +): Promise { + const selector = selectorFromSelection(selection); + if (!selector) return { status: "blocked", reason: "no-selector" }; + const own = tweensForThisElement(selection, allAnimations); + const keeper = positionWriteKeeper(own, selector); + const animations = keeper + ? own.filter((a) => a === keeper || !isPositionWriteOf(selector)(a)) + : own; + const resolved = await resolveGroupTween("position", animations, selection, async () => {}); + const posAnim = resolved?.anim ?? findGsapPositionAnimation(animations, selector); + const route = dragRoute(posAnim, iframe, selector, options.altKey); + if (route === "static") return { status: "persisted" }; + if (!posAnim) { + return { status: "blocked", reason: "source-uneditable", detail: "no-position-tween" }; + } + if (route === "whole-path") return { status: "persisted" }; + const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 }; + return gsapPositionFromDragOutcome(selection, posAnim, offset, gsapPos, iframe); +} + /** Commits a drag through the GSAP script. Callers reject `blocked` (the gesture layer * restores its drafts) and save `element-offset` on the element itself. */ export async function tryGsapDragIntercept( @@ -229,7 +247,12 @@ export async function tryGsapDragIntercept( fetchAllAnimations, options?.group, ); - if (preflight.status !== "persisted" || options?.preflightOnly) return preflight; + if (preflight.status !== "persisted") return preflight; + if (options?.preflightOnly) { + return options.group + ? planDrag(selection, offset, allAnimations, iframe, options) + : preflight; + } } const animations = tweensForThisElement(selection, allAnimations); const fetchFallbackAnimations = @@ -246,13 +269,10 @@ export async function tryGsapDragIntercept( // the live keyframed/real tween if present (else any), strip the rest, so the // commit below updates ONE write instead of fighting duplicates. let workingAnimations = animations; - const isPosWrite = (a: GsapAnimation) => a.targetSelector === selector && isXYPositionWrite(a); - if (animations.filter(isPosWrite).length > 1 && fetchFallbackAnimations) { + if (animations.filter(isPositionWriteOf(selector)).length > 1 && fetchFallbackAnimations) { const fresh = await fetchFallbackAnimations(); - const dupes = fresh.filter(isPosWrite); - if (dupes.length > 1) { - const keeper = - dupes.find((a) => a.keyframes) ?? dupes.find((a) => (a.duration ?? 0) > 0) ?? dupes[0]!; + const keeper = positionWriteKeeper(fresh, selector); + if (keeper) { await commitMutation( selection, { @@ -288,26 +308,8 @@ export async function tryGsapDragIntercept( } const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 }; - - // STATIC case (single source of truth = GSAP timeline): the element has no LIVE - // keyframed/tweened position motion. Use the strict non-hold check — a leftover - // position-hold `set` (after a delete-all, or a stale parse that lags it) must - // NOT count as live motion. Either way the position belongs in a - // `tl.set("#el",{x,y})`, not a keyframe conversion: re-nudge an existing set in - // place (idempotent), else add a new one. This also covers the stale-cache - // phantom — committing a set is correct because the element genuinely has no live motion. - const hasNonHold = hasNonHoldTweenForElement(iframe, selector, undefined, POSITION_CHANNELS); - // A KEYFRAMED position tween — even one that's currently a flat constant ("hold", - // e.g. 0% and 100% identical) — is still an animation the user is building, so a - // drag must add/update a keyframe, NOT fall back to a static `set`. Without this, - // dragging an element whose position tween is constant writes a `gsap.set` that - // fights the tween (the "drag didn't create a keyframe / didn't persist" bug). The - // static path is only for elements with NO keyframed position tween (truly static, - // or just a leftover position-hold `set`). - // A zero-duration keyframed tween is a static HOLD, not a live animation — - // treat it as static so the drag heals it instead of feeding it more keyframes. - const hasKeyframedPosTween = !!posAnim?.keyframes && resolveTweenDuration(posAnim) > 0; - if (!hasNonHold && !hasKeyframedPosTween) { + const route = dragRoute(posAnim, iframe, selector, options?.altKey); + if (route === "static") { const existingSet = posAnim && isInstantHold(posAnim) && posAnim.targetSelector === selector ? posAnim @@ -329,27 +331,26 @@ export async function tryGsapDragIntercept( // current ID and avoid a stale-ID remove that creates duplicate tweens. if (fetchFallbackAnimations) { const fresh = await fetchFallbackAnimations(); - const freshMatch = fresh.find( - (a) => - a.targetSelector === posAnim!.targetSelector && - a.propertyGroup === posAnim!.propertyGroup && - isXYPositionWrite(a) === isXYPositionWrite(posAnim!), - ); + const freshMatch = + fresh.find((a) => a.id === posAnim!.id) ?? + pickClosestToPlayhead( + fresh.filter( + (a) => + a.targetSelector === posAnim!.targetSelector && + a.propertyGroup === posAnim!.propertyGroup && + isXYPositionWrite(a) === isXYPositionWrite(posAnim!), + ), + ); if (freshMatch && freshMatch.id !== posAnim.id) { posAnim = freshMatch; } } const cbs = { commitMutation, fetchAnimations: fetchFallbackAnimations }; - // Alt-drag already means "shift the whole path" — the global auto-keyframe - // toggle (#1808) just makes that the default while it's off, so a manual - // edit on an already-animated element nudges the animation instead of - // inserting/updating a keyframe at the playhead. - const autoKeyframeEnabled = usePlayerStore.getState().autoKeyframeEnabled; - if (options?.altKey || !autoKeyframeEnabled) { + if (route === "whole-path") { await commitWholePathOffset(selection, posAnim, offset, gsapPos, iframe, selector, cbs); } else { - await commitGsapPositionFromDrag(selection, posAnim, offset, gsapPos, iframe, selector, cbs); + return commitGsapPositionFromDrag(selection, posAnim, offset, gsapPos, iframe, cbs); } return { status: "persisted" }; } @@ -428,8 +429,9 @@ export async function tryGsapRotationIntercept( ? resolved.anim : null; if (!anim) { - anim = - workingAnimations.find((a) => animationWritesAnyProperty(a, ROTATION_CHANNEL_SET)) ?? null; + anim = pickClosestToPlayhead( + workingAnimations.filter((a) => animationWritesAnyProperty(a, ROTATION_CHANNEL_SET)), + ); } // `angle` is the ABSOLUTE target rotation resolved by the gesture (gsap base + @@ -469,42 +471,14 @@ export async function tryGsapRotationIntercept( return { status: "persisted" }; } - // fallow-ignore-next-line code-duplication - if (anim.hasUnresolvedKeyframes || anim.hasUnresolvedSelector) { - const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection); - if (newId) anim = { ...anim, id: newId }; - } else if (!anim.keyframes) { - const resolvedFromValues = selector - ? readAllAnimatedProperties(iframe, selector, anim, "rotation") - : undefined; - await commitMutation( - selection, - { type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues }, - { label: "Convert to keyframes for rotation", skipReload: true }, - ); - } - - const runtimeProps = readAllAnimatedProperties(iframe, selector, anim, "rotation"); - - const backfillDefaults: Record = { ...runtimeProps }; - if (!("rotation" in runtimeProps)) { - backfillDefaults.rotation = readGsapProperty(iframe, selector, "rotation") ?? 0; - } - - const properties = { ...runtimeProps, rotation: newRotation }; - - await commitMutation( + return commitValueAtPlayhead( selection, - { - type: "add-keyframe", - animationId: anim.id, - percentage: pct, - properties, - backfillDefaults, - }, - { label: `Rotate (keyframe ${pct}%)`, softReload: true }, + anim, + { rotation: newRotation }, + iframe, + { commitMutation, fetchAnimations: fetchFallbackAnimations }, + { label: "Rotate", backfill: { rotation: newRotation }, holdFromStart: true }, ); - return { status: "persisted" }; } export { readRuntimeKeyframes, scanAllRuntimeKeyframes } from "./gsapRuntimeKeyframes"; diff --git a/packages/studio/src/hooks/gsapScriptCommitHelpers.ts b/packages/studio/src/hooks/gsapScriptCommitHelpers.ts index 4bca7d0e2c2..8986de034e7 100644 --- a/packages/studio/src/hooks/gsapScriptCommitHelpers.ts +++ b/packages/studio/src/hooks/gsapScriptCommitHelpers.ts @@ -4,6 +4,7 @@ import type { DomEditSelection } from "../components/editor/domEditingTypes"; export { PROPERTY_DEFAULTS } from "./gsapShared"; import { idSelector, matchesExactlyOne } from "./gsapShared"; import { studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; /** * The selector to author a NEW tween against, minting an id on the element when @@ -116,7 +117,7 @@ export async function assignGsapTargetAutoIdIfNeeded({ showToast?.("Couldn't assign element id because the patch contains invalid values", "error"); return false; } - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/file-mutations/patch-element/${encodeURIComponent(targetPath)}`, { method: "POST", diff --git a/packages/studio/src/hooks/gsapScriptCommitTypes.ts b/packages/studio/src/hooks/gsapScriptCommitTypes.ts index 5682587ad5f..3604dcf4aef 100644 --- a/packages/studio/src/hooks/gsapScriptCommitTypes.ts +++ b/packages/studio/src/hooks/gsapScriptCommitTypes.ts @@ -5,6 +5,14 @@ import type { PublishSdkSession } from "../utils/sdkCutover"; import type { RuntimeTweenChange } from "./gsapRuntimePatch"; import type { KeyframeUsageAction } from "../utils/keyframeUsage"; +/** The file a selection's GSAP write goes to. */ +export function gsapWriteFile( + selection: Pick, + activeCompPath: string | null | undefined, +): string { + return selection.sourceFile || activeCompPath || "index.html"; +} + export interface MutationResult { ok: boolean; changed?: boolean; diff --git a/packages/studio/src/hooks/gsapShared.ts b/packages/studio/src/hooks/gsapShared.ts index 34a7ec58593..e8c7d567020 100644 --- a/packages/studio/src/hooks/gsapShared.ts +++ b/packages/studio/src/hooks/gsapShared.ts @@ -34,6 +34,13 @@ export const PROPERTY_DEFAULTS: Record = { height: 100, }; +/** A tween's eases for re-writing it as keyframes: a flat tween's ease must become easeEach, + * since GSAP eases each percentage segment power1.inOut whatever the tween-level ease says. */ +export function keyframeEases(anim: GsapAnimation): { ease?: string; easeEach?: string } { + if (!anim.keyframes) return { easeEach: anim.ease }; + return { ease: anim.ease, easeEach: anim.keyframes.easeEach }; +} + /** * A timeline write that applies an instantaneous value and then holds it. * `set()` is always a hold; authored `to()` / `fromTo()` tweens are holds only diff --git a/packages/studio/src/hooks/gsapShared.writeTarget.test.ts b/packages/studio/src/hooks/gsapShared.writeTarget.test.ts index 5d9af24411b..d274097856b 100644 --- a/packages/studio/src/hooks/gsapShared.writeTarget.test.ts +++ b/packages/studio/src/hooks/gsapShared.writeTarget.test.ts @@ -3,7 +3,7 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { parseGsapScript } from "@hyperframes/core/gsap-parser"; import { addAnimationWithKeyframesToScript } from "@hyperframes/parsers/gsap-writer-acorn"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; -import { buildStableSelector, getSelectorIndex } from "../components/editor/domEditingDom"; +import { mountGroupSiblings, stableSelectionFor } from "./domSelectionTestHarness"; import { resolveSelectorElementIds, tweenTargetsElement, writeTargetSelector } from "./gsapShared"; import { commitKeyframeAtTimeImpl } from "./gsapKeyframeCommit"; import { trackStudioEvent } from "../utils/studioTelemetry"; @@ -16,38 +16,6 @@ afterEach(() => { document.body.innerHTML = ""; }); -/** - * A selection built the way production builds it (getDomLayerPatchTarget), so - * the class-only case under test is the real one: buildStableSelector hands back - * a BARE class for an element with no id / hf-id / composition id. - */ -function selectionFor(el: HTMLElement): DomEditSelection { - const selector = buildStableSelector(el); - return { - element: el, - id: el.id || undefined, - hfId: el.getAttribute("data-hf-id") || undefined, - selector, - selectorIndex: getSelectorIndex(document, el, selector, "index.html", null), - sourceFile: "index.html", - dataAttributes: { start: "0", duration: "2" }, - } as unknown as DomEditSelection; -} - -/** Five class-only siblings — the shape that made one add collapse the timeline. */ -function mountGroupSiblings(): HTMLElement[] { - document.body.innerHTML = ` -
-
-
-
-
-
-
- `; - return Array.from(document.querySelectorAll(".group")); -} - const BASE_SCRIPT = ` const tl = gsap.timeline({ paused: true }); tl.to("#scene", { opacity: 1, duration: 0.5 }, 0); @@ -68,8 +36,8 @@ function roundTripTargets(selector: string): { script: string; targets: string[] describe("writeTargetSelector", () => { it("addresses exactly one element when the only identity is a shared class", () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[2]); + const groups = mountGroupSiblings(5); + const selection = stableSelectionFor(groups[2]); // Precondition: this is the defect's input — a bare class hitting all five. expect(selection.selector).toBe(".group"); @@ -86,7 +54,7 @@ describe("writeTargetSelector", () => { document.body.innerHTML = `
`; const el = document.querySelector("#box")!; - expect(writeTargetSelector(selectionFor(el))).toBe("#box"); + expect(writeTargetSelector(stableSelectionFor(el))).toBe("#box"); }); it("prefers data-hf-id over a generated structural selector", () => { @@ -95,7 +63,7 @@ describe("writeTargetSelector", () => { `; const el = document.querySelectorAll(".group")[1]!; - const written = writeTargetSelector(selectionFor(el)); + const written = writeTargetSelector(stableSelectionFor(el)); expect(written).toBe('[data-hf-id="hf-42"]'); expect(document.querySelector(written!)).toBe(el); @@ -105,7 +73,7 @@ describe("writeTargetSelector", () => { document.body.innerHTML = `
`; const el = document.querySelector(".header")!; - expect(writeTargetSelector(selectionFor(el))).toBe(".header"); + expect(writeTargetSelector(stableSelectionFor(el))).toBe(".header"); }); it("hands identity back to a data-hf-id ancestor part way up a deep chain", () => { @@ -125,7 +93,7 @@ describe("writeTargetSelector", () => { `; const el = document.querySelectorAll(".cell")[2]!; - const written = writeTargetSelector(selectionFor(el)); + const written = writeTargetSelector(stableSelectionFor(el)); expect(written).toBe('[data-hf-id="mid"] > div:nth-child(3)'); expect(document.querySelectorAll(written!)).toHaveLength(1); @@ -137,7 +105,7 @@ describe("writeTargetSelector", () => { const el = document.querySelectorAll("#scene > div")[1]!; // querySelectorAll throws on this, so the "does it match exactly one?" rung // must read as a miss rather than crashing the add. - const selection = { ...selectionFor(el), selector: "div[unclosed" } as DomEditSelection; + const selection = { ...stableSelectionFor(el), selector: "div[unclosed" } as DomEditSelection; expect(writeTargetSelector(selection)).toBe("#scene > div:nth-child(2)"); }); @@ -145,7 +113,7 @@ describe("writeTargetSelector", () => { it("returns null when a live DOM is present and no rung addresses one element", () => { document.body.innerHTML = `
`; const el = document.querySelectorAll(".group")[1]!; - const selection = selectionFor(el); + const selection = stableSelectionFor(el); expect(selection.selector).toBe(".group"); // Detached between selecting and committing: ownerDocument still resolves, // but there is no parent to count a :nth-child position in. Returning @@ -167,11 +135,11 @@ describe("writeTargetSelector", () => { describe("writeTargetSelector — write/read round trip", () => { it("re-parses and attributes the new tween to the one element it targeted", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); // Ids let resolveSelectorElementIds name the attributed elements; the // SELECTION still has none, so the write path still faces the bare class. groups.forEach((el, i) => el.setAttribute("id", `group-${i}`)); - const selection = { ...selectionFor(groups[2]), id: undefined } as DomEditSelection; + const selection = { ...stableSelectionFor(groups[2]), id: undefined } as DomEditSelection; const written = writeTargetSelector(selection); const { targets } = roundTripTargets(written!); @@ -180,9 +148,9 @@ describe("writeTargetSelector — write/read round trip", () => { }); it("does not widen the add to the element's four class siblings", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); groups.forEach((el, i) => el.setAttribute("id", `group-${i}`)); - const selection = { ...selectionFor(groups[0]), id: undefined } as DomEditSelection; + const selection = { ...stableSelectionFor(groups[0]), id: undefined } as DomEditSelection; // The old bare-class write attributed the one add to every sibling — the // attribution blow-up behind "one add collapsed the timeline to a single row". @@ -194,8 +162,8 @@ describe("writeTargetSelector — write/read round trip", () => { describe("existingTweenTargetSelector", () => { it("keeps the narrowed target when a replace re-authors the tween", async () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[2]); + const groups = mountGroupSiblings(5); + const selection = stableSelectionFor(groups[2]); const commitMutation = vi.fn(async () => undefined); // A tween a previous add already narrowed to one sibling. Re-deriving the // target from the selection would widen it back to all five. @@ -215,8 +183,8 @@ describe("existingTweenTargetSelector", () => { }); it("falls back to the selection when the tween's own target did not resolve", async () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[2]); + const groups = mountGroupSiblings(5); + const selection = stableSelectionFor(groups[2]); const commitMutation = vi.fn(async () => undefined); const setAnim = { id: "a1", @@ -236,8 +204,8 @@ describe("existingTweenTargetSelector", () => { describe("commitKeyframeAtTimeImpl — new-tween target", () => { it("authors a one-element selector when no tween exists at the playhead", async () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[3]); + const groups = mountGroupSiblings(5); + const selection = stableSelectionFor(groups[3]); const commitMutation = vi.fn(async () => undefined); await commitKeyframeAtTimeImpl(selection, 1, [], { x: 12 }, commitMutation); @@ -251,7 +219,7 @@ describe("commitKeyframeAtTimeImpl — new-tween target", () => { describe("tweenTargetsElement", () => { it("matches a tween narrowed to this element by a selector the selection does not use", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); groups[2]!.id = "narrowed"; // The write half authored "#narrowed"; the read half still has ".group". @@ -259,7 +227,7 @@ describe("tweenTargetsElement", () => { }); it("does not hand an individual element the group tween it merely inherits", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); // Selecting one sibling by its own address must not let an edit mutate the // ".group" tween: that write moves all five, not the one being nudged. @@ -267,13 +235,13 @@ describe("tweenTargetsElement", () => { }); it("still edits a group tween when the group itself is the selection", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); expect(tweenTargetsElement(".group", ".group", groups[0])).toBe(true); }); it("does not match a target that is not a selector matches() understands", () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5); expect(tweenTargetsElement("div[unclosed", ".group", groups[0])).toBe(false); }); @@ -281,8 +249,8 @@ describe("tweenTargetsElement", () => { describe("commitKeyframeAtTimeImpl — no one-element target", () => { it("drops the keyframe rather than authoring the bare class", async () => { - const groups = mountGroupSiblings(); - const selection = selectionFor(groups[3]!); + const groups = mountGroupSiblings(5); + const selection = stableSelectionFor(groups[3]!); groups[3]!.remove(); const commitMutation = vi.fn(async () => undefined); @@ -297,7 +265,7 @@ it("counts a keyframe-at-time conversion and insertion as one add gesture", asyn const el = document.createElement("div"); el.id = "target"; document.body.append(el); - const selection = selectionFor(el); + const selection = stableSelectionFor(el); const animations = parseGsapScript( 'const tl = gsap.timeline(); tl.to("#target", {x:100,duration:4},0);', ).animations; diff --git a/packages/studio/src/hooks/gsapValueAtPlayhead.browser.test.ts b/packages/studio/src/hooks/gsapValueAtPlayhead.browser.test.ts new file mode 100644 index 00000000000..af788291060 --- /dev/null +++ b/packages/studio/src/hooks/gsapValueAtPlayhead.browser.test.ts @@ -0,0 +1,83 @@ +// @vitest-environment happy-dom +// Real Chrome with the built runtime: its seek, not a plain GSAP seek, decides what a saved edit shows. +import { readFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import { gsap } from "gsap"; +import { parseGsapScriptAcorn } from "@hyperframes/parsers/gsap-parser-acorn"; +import { replaceTweenWithKeyframesInScript } from "@hyperframes/parsers/gsap-writer-acorn"; +import puppeteer from "puppeteer-core"; +import { expect, it, vi } from "vitest"; +import { findSystemChrome } from "../../vite.browser"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import { usePlayerStore } from "../player/store/playerStore"; +import { planValueEdit } from "./gsapValueAtPlayhead"; + +const require = createRequire(import.meta.url); +vi.setConfig({ testTimeout: 60_000 }); + +const SRC = `var tl = gsap.timeline({ paused: true }); +tl.from("#target", { x: -60, duration: 2, ease: "none" }, 0); +tl.fromTo("#target", { x: 0 }, { x: 60, duration: 1, ease: "none" }, 2); +window.__timelines["main"] = tl;`; + +/** Plans and writes a drag of `#target` to `x` at `at`, as the move gesture saves it. */ +function writeDrag(x: number, at: number): string { + const box = Object.assign(document.body.appendChild(document.createElement("div")), { + id: "target", + }); + const win = { __timelines: {} as Record }; + new Function("gsap", "window", SRC)(gsap, win); + const timeline = win.__timelines.main!; + timeline.progress(0.0001, true).seek(at); + usePlayerStore.setState({ currentTime: at, activeKeyframePct: null }); + const iframe = { contentWindow: { ...win, gsap } } as unknown as HTMLIFrameElement; + const anim = parseGsapScriptAcorn(SRC).animations[1]!; + const selection = { id: "target", selector: "#target", element: box } as DomEditSelection; + const plan = planValueEdit(selection, anim, { x }, iframe); + timeline.kill(); + if (!plan.ok) throw new Error(`the drag was refused: ${JSON.stringify(plan)}`); + return replaceTweenWithKeyframesInScript(SRC, anim.id, plan.mutation)!; +} + +const page = (script: string) => ` +
+
+
+ + +`; + +it("a drag on a fromTo's start shows the dropped x there once the runtime seeks", async () => { + const written = writeDrag(90, 2); + const executablePath = findSystemChrome(); + if (!executablePath) throw new Error("no Chrome found: set HYPERFRAMES_BROWSER_PATH"); + const browser = await puppeteer.launch({ + executablePath, + headless: true, + args: ["--no-sandbox"], + }); + try { + const tab = await browser.newPage(); + await tab.setRequestInterception(true); + // Only the GSAP script is served; anything else is refused, never fetched. + tab.on("request", (request) => + request.url().endsWith("/gsap.min.js") + ? request.respond({ body: readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8") }) + : request.abort("blockedbyclient"), + ); + await tab.setContent(page(written), { waitUntil: "load" }); + await tab.evaluate(readFileSync(require.resolve("@hyperframes/core/runtime"), "utf8")); + await tab.waitForFunction(() => "__player" in window); + const shown = await tab.evaluate(() => { + const w = window as unknown as { + __player: { seek(t: number): void }; + gsap: { getProperty(target: string, prop: string): number }; + }; + w.__player.seek(2); + return w.gsap.getProperty("#target", "x"); + }); + expect(shown).toBeCloseTo(90, 1); + } finally { + await browser.close(); + } +}); diff --git a/packages/studio/src/hooks/gsapValueAtPlayhead.realGsap.test.ts b/packages/studio/src/hooks/gsapValueAtPlayhead.realGsap.test.ts new file mode 100644 index 00000000000..420d7e845b4 --- /dev/null +++ b/packages/studio/src/hooks/gsapValueAtPlayhead.realGsap.test.ts @@ -0,0 +1,179 @@ +// @vitest-environment happy-dom +import { gsap } from "gsap"; +import { parseGsapScriptAcorn } from "@hyperframes/parsers/gsap-parser-acorn"; +import { replaceTweenWithKeyframesInScript } from "@hyperframes/parsers/gsap-writer-acorn"; +import { afterEach, expect, it } from "vitest"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import { usePlayerStore } from "../player/store/playerStore"; +import { findParsedTween, parsedImplicitEndValue, parsedTweenEase } from "./gsapParsedTween"; +import { planValueEdit } from "./gsapValueAtPlayhead"; + +/** Runs a composition script as the preview does: a paused timeline, bound, then seeked to `at`. */ +function play(script: string, at: number) { + const win = { __timelines: {} as Record }; + new Function("gsap", "window", script)(gsap, win); + const timeline = win.__timelines.t!; + timeline.progress(0.0001, true).seek(at); + return { timeline, iframe: { contentWindow: { ...win, gsap } } as unknown as HTMLIFrameElement }; +} + +/** Drags `#x` to `x` at `at`, writes the plan into the script, and replays the written file there. */ +function dragAndReplay(script: string, x: number, at: number) { + const box = document.body.appendChild(document.createElement("div")); + box.id = "x"; + const { timeline, iframe } = play(script, at); + usePlayerStore.setState({ currentTime: at, activeKeyframePct: null }); + const anim = parseGsapScriptAcorn(script).animations[0]!; + const selection = { id: "x", selector: "#x", element: box } as DomEditSelection; + const plan = planValueEdit(selection, anim, { x }, iframe); + timeline.kill(); + if (!plan.ok) return { plan }; + const written = replaceTweenWithKeyframesInScript(script, anim.id, plan.mutation)!; + const replay = play(written, at); + const shown = gsap.getProperty(box, "x"); + replay.timeline.kill(); + return { plan, written, shown }; +} + +const script = (vars: string) => + `var tl = gsap.timeline({ paused: true });\ntl.to("#x", { ${vars} }, 0);\nwindow.__timelines["t"] = tl;`; + +afterEach(() => { + document.body.replaceChildren(); + usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); +}); + +it("edits a delayed tween with no authored ease, landing the value at the playhead", () => { + const { plan, shown } = dragAndReplay(script("duration: 1, delay: 0.5, x: 100"), 200, 2); + expect(plan.ok).toBe(true); + expect(shown).toBe(200); +}); + +it("writes a delayed linear tween so GSAP shows the new value at the playhead, not later", () => { + const { shown } = dragAndReplay(script("duration: 1, delay: 0.5, x: 100, ease: 'none'"), 200, 2); + expect(shown).toBe(200); +}); + +it("keeps GSAP's default ease, by name, for a tween that authors none", () => { + const { plan } = dragAndReplay(script("duration: 1, x: 100"), 60, 0.5); + expect(plan.ok && plan.mutation.easeEach).toBe("power1.out"); +}); + +it("reads a tween the playhead has not reached without redrawing a sibling's live value", () => { + const [x, y] = ["x", "y"].map((id) => + Object.assign(document.body.appendChild(document.createElement("div")), { id }), + ); + const src = `var tl = gsap.timeline({ paused: true }); +tl.to("#y", { x: 100, duration: 1, ease: "none" }, 0); +tl.to("#x", { x: 300, duration: 1 }, 2); +window.__timelines["t"] = tl;`; + const { timeline, iframe } = play(src, 0.5); + gsap.set(y!, { x: 77 }); + + const tween = findParsedTween(iframe, x!, parseGsapScriptAcorn(src).animations[1]!); + + expect(parsedImplicitEndValue(tween)("x", "start")).toBe(0); + expect(gsap.getProperty(y!, "x")).toBe(77); + expect(timeline.time()).toBe(0.5); + timeline.kill(); +}); + +it("keeps a sibling's live attribute while reading an unplayed tween beside the runtime's filler", () => { + const [x, y] = ["x", "y"].map((id) => + Object.assign(document.body.appendChild(document.createElement("div")), { id }), + ); + y!.setAttribute("data-value", "0"); + const src = `var tl = gsap.timeline({ paused: true }); +tl.to({}, { duration: 4, data: "hf-runtime-filler" }, 0); +tl.to("#y", { attr: { "data-value": 100 }, duration: 1, ease: "none" }, 0); +tl.to("#x", { x: 300, duration: 1 }, 2); +window.__timelines["t"] = tl;`; + const { timeline, iframe } = play(src, 0.5); + y!.setAttribute("data-value", "77"); + + const tween = findParsedTween(iframe, x!, parseGsapScriptAcorn(src).animations.at(-1)!); + + expect(parsedImplicitEndValue(tween)("x", "start")).toBe(0); + expect(y!.getAttribute("data-value")).toBe("77"); + timeline.kill(); +}); + +it("reads a later tween's start from the earlier tween on the same layer, as playback does", () => { + const x = Object.assign(document.body.appendChild(document.createElement("div")), { id: "x" }); + const src = `var tl = gsap.timeline({ paused: true }); +tl.to("#x", { x: 50, duration: 4, ease: "none" }, 0); +tl.to("#x", { x: 100, duration: 1, ease: "none", overwrite: "auto" }, 2); +window.__timelines["t"] = tl;`; + const { timeline, iframe } = play(src, 0.5); + + const tween = findParsedTween(iframe, x, parseGsapScriptAcorn(src).animations[1]!); + + expect(parsedImplicitEndValue(tween)("x", "start")).toBe(25); + timeline.seek(2.5); + expect(gsap.getProperty(x, "x")).toBe(62.5); + timeline.kill(); +}); + +it("saves a dragged keyframe tween with its authored start, not the drag's live value", () => { + const box = Object.assign(document.body.appendChild(document.createElement("div")), { id: "x" }); + const src = script( + "keyframes: { '0%': { opacity: 0 }, '100%': { opacity: 1, x: 300 } }, duration: 1, ease: 'none'", + ).replace("}, 0);", "}, 2);"); + const { timeline, iframe } = play(src, 0.5); + usePlayerStore.setState({ currentTime: 0.5, activeKeyframePct: null }); + gsap.set(box, { x: 77 }); + const anim = parseGsapScriptAcorn(src).animations[0]!; + const selection = { id: "x", selector: "#x", element: box } as DomEditSelection; + + const plan = planValueEdit(selection, anim, { x: 77 }, iframe); + timeline.kill(); + + expect(plan.ok).toBe(true); + if (!plan.ok) return; + const written = replaceTweenWithKeyframesInScript(src, anim.id, plan.mutation)!; + const at = (time: number) => { + const replay = play(written, time); + const x = gsap.getProperty(box, "x"); + replay.timeline.kill(); + return x; + }; + expect(at(0.5)).toBe(77); + expect(at(2)).toBe(0); + expect(at(3)).toBe(300); +}); + +it("keeps a layer's other transform values while reading an unplayed tween", () => { + const box = Object.assign(document.body.appendChild(document.createElement("div")), { id: "x" }); + const src = script( + "keyframes: { '0%': { opacity: 0 }, '100%': { opacity: 1, x: 300 } }, duration: 1", + ).replace("}, 0);", "}, 2);"); + const { timeline, iframe } = play(src, 0.5); + gsap.set(box, { + x: 77, + skewX: 23, + rotationX: 19, + xPercent: 12, + transformOrigin: "20px 30px 40px", + }); + + const tween = findParsedTween(iframe, box, parseGsapScriptAcorn(src).animations[0]!); + timeline.kill(); + + expect(parsedImplicitEndValue(tween)("x", "start")).toBe(0); + const values = ["x", "skewX", "rotationX", "xPercent", "transformOrigin"]; + expect(values.map((p) => gsap.getProperty(box, p))).toEqual([77, 23, 19, 12, "20px 30px 40px"]); +}); + +it("names only an ease GSAP built in, and refuses a custom function rather than guess", () => { + const custom = { vars: { ease: (p: number) => p * p } }; + const iframe = { contentWindow: { gsap } } as unknown as HTMLIFrameElement; + expect(parsedTweenEase(iframe, { vars: { ease: gsap.parseEase("expo.in") } })).toBe("expo.in"); + expect(parsedTweenEase(iframe, custom)).toBeNull(); +}); + +it("writes an edit into a looping tween and keeps its repeat and yoyo, as main did", () => { + const vars = "duration: 2, x: 100, ease: 'none', repeat: 1, yoyo: true"; + const { plan, written } = dragAndReplay(script(vars), 40, 1); + expect(plan.ok).toBe(true); + expect(written).toMatch(/repeat: 1[\s\S]*yoyo: true/); +}); diff --git a/packages/studio/src/hooks/gsapValueAtPlayhead.test.ts b/packages/studio/src/hooks/gsapValueAtPlayhead.test.ts new file mode 100644 index 00000000000..e2f5932fe4c --- /dev/null +++ b/packages/studio/src/hooks/gsapValueAtPlayhead.test.ts @@ -0,0 +1,552 @@ +// @vitest-environment happy-dom +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import { usePlayerStore } from "../player/store/playerStore"; +import { GSAP_EDIT_BLOCK_COPY } from "./gsapEditOutcome"; +import { liveTween, previewWith, tween } from "./gsapParsedTween.test-helpers"; +import { tryGsapResizeIntercept } from "./gsapResizeIntercept"; +import { tryGsapDragIntercept, tryGsapRotationIntercept } from "./gsapRuntimeBridge"; +import { planValueAtPlayhead, planValueEdit, type PlayheadEdit } from "./gsapValueAtPlayhead"; + +let el: HTMLElement; +let selection: DomEditSelection; +beforeEach(() => { + el = document.createElement("div"); + el.id = "box"; + document.body.append(el); + selection = { id: "box", selector: "#box", element: el } as DomEditSelection; +}); +afterEach(() => { + el.remove(); + usePlayerStore.setState({ currentTime: 0, activeKeyframePct: null }); +}); + +/** Drags `#box` by `dx` from a pre-gesture GSAP position of `base`, at `time`. */ +async function drag( + anims: GsapAnimation[], + live: unknown[], + { + time, + base, + dx, + values = {}, + }: { time: number; base: [number, number]; dx: number; values?: Record }, +) { + usePlayerStore.setState({ currentTime: time }); + el.setAttribute("data-hf-drag-gsap-base-x", String(base[0])); + el.setAttribute("data-hf-drag-gsap-base-y", String(base[1])); + const commitMutation = vi.fn(); + const outcome = await tryGsapDragIntercept( + selection, + { x: dx, y: 0 }, + anims, + previewWith(el, live, values), + commitMutation, + async () => anims, + ); + return { outcome, mutations: commitMutation.mock.calls.map((call) => call[1]) }; +} + +const fromX = tween({ + id: "#box-from-0-position", + method: "from", + properties: { x: -60 }, + resolvedStart: 0, + duration: 2, + ease: "none", +}); +const fromXLive = (end: number) => + liveTween( + el, + { start: 0, duration: 2, vars: { x: -60, ease: "none" }, ends: { x: [-60, end] } }, + { from: true }, + ); + +/** Two linear `to` tweens of `group` on `#box`, 0-2s then 2-3s, their live copies and a commit recorder. */ +function backToBack( + group: "size" | "scale" | "rotation", + firstEnd: Record, + secondEnd: Record, +) { + const flat = (start: number, duration: number, properties: Record) => + tween({ + id: `#box-to-${start * 1000}-${group}`, + propertyGroup: group, + method: "to", + properties, + resolvedStart: start, + duration, + ease: "none", + }); + const tweens = [flat(0, 2, firstEnd), flat(2, 1, secondEnd)]; + const live = tweens.map((a) => + liveTween(el, { start: a.resolvedStart!, duration: a.duration!, vars: a.properties }), + ); + const commitMutation = vi.fn(); + const written = () => commitMutation.mock.calls.map((call) => call[1]); + return { tweens, live, commitMutation, written }; +} + +describe("a move on a GSAP-animated layer, at the playhead", () => { + it("adds a keyframe inside a from() tween and keeps its end where GSAP parsed it", async () => { + const { outcome, mutations } = await drag([fromX], [fromXLive(40)], { + time: 1, + base: [-10, 0], + dx: 30, + }); + expect(outcome).toEqual({ status: "persisted" }); + expect(mutations).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + animationId: "#box-from-0-position", + position: 0, + duration: 2, + easeEach: "none", + keyframes: [ + { percentage: 0, properties: { x: -60, y: 0 } }, + { percentage: 50, properties: { x: 20, y: 0 } }, + { percentage: 100, properties: { x: 40, y: 0 } }, + ], + }), + ]); + }); + + it("writes the end GSAP parsed from the file, not the dragged element's live value", async () => { + const { mutations } = await drag([fromX], [fromXLive(40)], { + time: 1, + base: [-10, 0], + dx: 30, + values: { x: 999 }, + }); + expect(mutations[0].keyframes.at(-1)).toEqual({ percentage: 100, properties: { x: 40, y: 0 } }); + }); + + it("extends a to() tween back to the playhead, holding the start GSAP folded from CSS translate", async () => { + const toX = tween({ + id: "#box-to-2000-position", + method: "to", + properties: { x: 60 }, + resolvedStart: 2, + duration: 1, + ease: "none", + }); + // `translate: 40px 30px` on the element: GSAP parses x from 40, not 0. + const live = liveTween(el, { start: 2, duration: 1, vars: { x: 60 }, ends: { x: [40, 60] } }); + const { mutations } = await drag([toX], [live], { time: 1, base: [40, 0], dx: -20 }); + expect(mutations).toEqual([ + expect.objectContaining({ + animationId: "#box-to-2000-position", + position: 1, + duration: 2, + easeEach: "none", + keyframes: [ + { percentage: 0, properties: { x: 20, y: 0 } }, + { percentage: 50, properties: { x: 40, y: 0 } }, + { percentage: 100, properties: { x: 60, y: 0 } }, + ], + }), + ]); + }); + + it("refuses, with the Code tab message, when GSAP has not parsed the tween's end yet", async () => { + const unparsed = liveTween(el, { start: 0, duration: 2, vars: { x: -60 } }, { from: true }); + const { outcome, mutations } = await drag([fromX], [unparsed], { + time: 1, + base: [-10, 0], + dx: 30, + }); + expect(outcome).toEqual({ + status: "blocked", + reason: "keyframes-uneditable", + detail: "implicit-end-unknown", + }); + expect(mutations).toEqual([]); + expect(GSAP_EDIT_BLOCK_COPY["keyframes-uneditable"]).toContain("Code tab"); + }); + + it("adds a keyframe between two steps of a keyframes array", async () => { + const keys = tween({ + id: "#box-to-0-position", + method: "to", + properties: {}, + resolvedStart: 0, + duration: 3, + keyframes: { + format: "object-array", + keyframes: [ + // The parse rounds the step to 66.7%; GSAP times it at 2 s of 3. + { percentage: 66.7, properties: { x: 60 } }, + { percentage: 100, properties: { x: 120 } }, + ], + }, + }); + const steps = [ + { startTime: () => 0, duration: () => 2 }, + { startTime: () => 2, duration: () => 1 }, + ]; + const live = liveTween( + el, + { start: 0, duration: 3, vars: { keyframes: [] } }, + { parts: steps }, + ); + const { mutations } = await drag([keys], [live], { time: 1, base: [30, 0], dx: 10 }); + expect(mutations.map((m) => m.type)).toEqual(["replace-with-keyframes"]); + // An array step eases linearly unless it says otherwise; percentage keyframes would not. + expect(mutations[0].keyframes).toEqual([ + { percentage: 33.333, properties: { x: 40, y: 0 }, ease: "none" }, + { percentage: 66.667, properties: { x: 60, y: 0 }, ease: "none" }, + { percentage: 100, properties: { x: 120, y: 0 }, ease: "none" }, + ]); + }); + + it("never writes x and y into a tween that only animates size", async () => { + const size = tween({ + id: "#box-to-0-size", + propertyGroup: "size", + method: "to", + properties: {}, + resolvedStart: 0, + duration: 2, + keyframes: { + format: "percentage", + keyframes: [{ percentage: 100, properties: { width: 300 } }], + }, + }); + const live = liveTween(el, { + start: 0, + duration: 2, + vars: { keyframes: { "100%": { width: 300 } } }, + }); + const { mutations } = await drag([size], [live], { time: 1, base: [0, 0], dx: 10 }); + expect(mutations.some((m) => m.animationId === "#box-to-0-size")).toBe(false); + }); +}); + +describe("where two tweens meet at the playhead", () => { + it("edits the one whose keyframe the file states there, not the one listed first", async () => { + const fromTo = tween({ + id: "#box-fromTo-2000-position", + method: "fromTo", + fromProperties: { x: 0 }, + properties: { x: 60 }, + resolvedStart: 2, + duration: 1, + ease: "none", + }); + const live = liveTween(el, { start: 2, duration: 1, vars: { x: 60 }, ends: { x: [0, 60] } }); + const { mutations } = await drag([fromX, fromTo], [fromXLive(40), live], { + time: 2, + base: [0, 0], + dx: 25, + }); + expect(mutations).toEqual([ + expect.objectContaining({ + animationId: "#box-fromTo-2000-position", + easeEach: "none", + keyframes: [ + { percentage: 0, properties: { x: 25, y: 0 } }, + { percentage: 100, properties: { x: 60, y: 0 } }, + ], + }), + ]); + }); +}); + +describe("a resize on a layer whose size GSAP animates, at the playhead", () => { + it("adds a size keyframe inside the tween at the playhead", async () => { + const { tweens, live, commitMutation, written } = backToBack( + "size", + { width: 300, height: 200 }, + { width: 360, height: 240 }, + ); + usePlayerStore.setState({ currentTime: 1 }); + await tryGsapResizeIntercept( + selection, + { width: 330, height: 210 }, + tweens, + previewWith(el, live), + commitMutation, + ); + expect(written()).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + animationId: "#box-to-0-size", + easeEach: "none", + keyframes: [ + { percentage: 50, properties: { width: 330, height: 210 } }, + { percentage: 100, properties: { width: 300, height: 200 } }, + ], + }), + ]); + }); +}); + +describe("a resize on a layer whose scale GSAP animates, at the playhead", () => { + it("adds a scale keyframe inside the tween at the playhead and leaves the next tween alone", async () => { + const { tweens, live, commitMutation, written } = backToBack( + "scale", + { scale: 1.25 }, + { scale: 1.5 }, + ); + el.setAttribute("data-hf-studio-original-box-width", "240"); + el.setAttribute("data-hf-studio-original-box-height", "160"); + usePlayerStore.setState({ currentTime: 1 }); + // Dropped at 1.5x the box with a live scale of 1.125, the playhead's value of the first tween. + await tryGsapResizeIntercept( + selection, + { width: 320, height: 213.333 }, + tweens, + previewWith(el, live, { scaleX: 1.125, scaleY: 1.125 }), + commitMutation, + ); + const writes = written(); + expect(writes[0]).toMatchObject({ + type: "replace-with-keyframes", + animationId: "#box-to-0-scale", + easeEach: "none", + keyframes: [ + { percentage: 50, properties: { scale: 1.5 } }, + { percentage: 100, properties: { scale: 1.25 } }, + ], + }); + expect(writes.some((m) => m.animationId === "#box-to-2000-scale")).toBe(false); + }); +}); + +describe("a resize inside one gesture, on a tween that mixes size and position", () => { + it("writes the size and the anchor move once, into the tween the file has", async () => { + const keys = tween({ + id: "#box-to-0", + propertyGroup: undefined, + method: "to", + properties: {}, + resolvedStart: 0, + duration: 3, + keyframes: { + format: "object-array", + keyframes: [ + { percentage: 66.667, properties: { x: 60, width: 280 }, ease: "none" }, + { percentage: 100, properties: { x: 120, width: 320 }, ease: "none" }, + ], + }, + }); + el.setAttribute("data-hf-studio-original-box-width", "260"); + el.setAttribute("data-hf-studio-original-box-height", "160"); + el.setAttribute("data-hf-drag-gsap-base-x", "50"); + el.setAttribute("data-hf-drag-gsap-base-y", "30"); + const live = liveTween(el, { start: 0, duration: 3, vars: { keyframes: [] } }); + usePlayerStore.setState({ currentTime: 1 }); + // A gesture buffers its writes: the file the intercept reads back stays as it was. + const commitMutation = vi.fn(); + const outcome = await tryGsapResizeIntercept( + selection, + { width: 300, height: 200 }, + [keys], + previewWith(el, [live]), + commitMutation, + async () => [keys], + { x: -40, y: -40 }, + ); + expect(outcome).toMatchObject({ status: "persisted", ownsDragOffset: true }); + expect(commitMutation.mock.calls.map((call) => call[1])).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + animationId: "#box-to-0", + keyframes: [ + { + percentage: 33.333, + properties: { width: 300, height: 200, x: 10, y: -10 }, + ease: "none", + }, + { + percentage: 66.667, + properties: { x: 60, width: 280, height: 160, y: 30 }, + ease: "none", + }, + { percentage: 100, properties: { x: 120, width: 320, height: 160, y: 30 }, ease: "none" }, + ], + }), + ]); + }); +}); + +describe("a rotate on a GSAP-animated layer, at the playhead", () => { + it("changes the keyframe two flat tweens meet at, on the tween that states it", async () => { + const { tweens, live, commitMutation, written } = backToBack( + "rotation", + { rotation: 20 }, + { rotation: 40 }, + ); + usePlayerStore.setState({ currentTime: 2 }); + await tryGsapRotationIntercept(selection, 25, tweens, previewWith(el, live), commitMutation); + expect(written()).toEqual([ + expect.objectContaining({ + type: "replace-with-keyframes", + animationId: "#box-to-0-rotation", + position: 0, + duration: 2, + easeEach: "none", + keyframes: [{ percentage: 100, properties: { rotation: 25 } }], + }), + ]); + }); +}); + +describe("a rotate on a layer whose tween turns it on another axis", () => { + it("holds the new rotation across the whole tween, so the layer does not turn before the playhead", async () => { + const flip = tween({ + id: "#box-to-0-rotation", + propertyGroup: "rotation", + method: "to", + properties: { rotationY: 180 }, + resolvedStart: 0, + duration: 2, + ease: "none", + }); + usePlayerStore.setState({ currentTime: 1 }); + const commitMutation = vi.fn(); + const live = [liveTween(el, { start: 0, duration: 2, vars: flip.properties })]; + await tryGsapRotationIntercept(selection, 45, [flip], previewWith(el, live), commitMutation); + expect(commitMutation.mock.calls.map((call) => call[1].keyframes)).toEqual([ + [ + { percentage: 0, properties: { rotation: 45 } }, + { percentage: 50, properties: { rotation: 45 } }, + { percentage: 100, properties: { rotationY: 180, rotation: 45 } }, + ], + ]); + }); +}); + +describe("planValueAtPlayhead", () => { + const plan = (edit: Partial) => + planValueAtPlayhead({ + anim: tween({ method: "to", properties: {}, resolvedStart: 0, duration: 4 }), + at: { time: 2 }, + values: {}, + implicitEndValue: () => null, + ...edit, + }); + const kf = ( + keyframes: Array<{ percentage: number; properties: Record }>, + easeEach?: string, + ) => + tween({ + method: "to", + properties: {}, + resolvedStart: 0, + duration: 4, + keyframes: { format: "percentage", keyframes, ...(easeEach && { easeEach }) }, + }); + + it("changes the keyframe under the playhead and no other", () => { + const result = plan({ + anim: kf([ + { percentage: 0, properties: { x: 0 } }, + { percentage: 50, properties: { x: 10 } }, + { percentage: 100, properties: { x: 20 } }, + ]), + values: { x: 15 }, + }); + expect(result.ok && result.mutation.keyframes.map((k) => k.properties.x)).toEqual([0, 15, 20]); + }); + + it("reports an add only when it writes a keyframe the tween did not have", () => { + const changed = plan({ + anim: kf([ + { percentage: 0, properties: { x: 0 } }, + { percentage: 100, properties: { x: 20 } }, + ]), + at: { time: 4 }, + values: { x: 15 }, + }); + const held = plan({ + anim: kf([{ percentage: 100, properties: { x: 20 } }]), + at: { time: 4 }, + values: { y: 5 }, + backfill: { y: 0 }, + holdFromStart: true, + }); + expect(changed.ok && changed.added).toBe(false); + expect(held.ok && held.mutation.keyframes.length).toBe(2); + expect(held.ok && held.added).toBe(true); + }); + + it("eases the new segment like the one it splits", () => { + const result = plan({ + anim: kf([{ percentage: 100, properties: { x: 20 } }], "power2.in"), + at: { time: 1 }, + values: { x: 5 }, + }); + expect(result.ok && result.mutation).toMatchObject({ + easeEach: "power2.in", + keyframes: [ + { percentage: 25, properties: { x: 5 } }, + { percentage: 100, properties: { x: 20 } }, + ], + }); + }); + + it("extends past the end and keeps the authored end where it was", () => { + const result = plan({ + anim: tween({ + method: "to", + properties: { width: 300 }, + resolvedStart: 0, + duration: 2, + ease: "none", + }), + at: { time: 3 }, + values: { width: 400 }, + }); + expect(result.ok && result.mutation).toMatchObject({ + position: 0, + duration: 3, + easeEach: "none", + keyframes: [ + { percentage: 66.667, properties: { width: 300 } }, + { percentage: 100, properties: { width: 400 } }, + ], + }); + }); + + it("splits a uniform scale into longhands for a per-axis edit", () => { + const result = plan({ + anim: tween({ + method: "to", + properties: { scale: 1.25 }, + resolvedStart: 0, + duration: 4, + ease: "none", + }), + values: { scaleX: 1.5, scaleY: 1.1 }, + }); + expect(result.ok && result.mutation.keyframes).toEqual([ + { percentage: 50, properties: { scaleX: 1.5, scaleY: 1.1 } }, + { percentage: 100, properties: { scaleX: 1.25, scaleY: 1.25 } }, + ]); + }); + + it("refuses keyframes eased as a whole, whose segment curves it cannot keep", () => { + const anim = { ...kf([{ percentage: 100, properties: { x: 20 } }]), ease: "power2.out" }; + expect(plan({ anim, values: { x: 5 } })).toEqual({ ok: false, reason: "eased-keyframes" }); + }); +}); + +it("refuses a tween whose selector also animates a sibling, before it plans anything", () => { + el.className = "card"; + const sibling = document.body.appendChild(document.createElement("div")); + sibling.className = "card"; + const shared = tween({ + targetSelector: ".card", + properties: { x: 100 }, + resolvedStart: 0, + duration: 1, + }); + + expect(planValueEdit(selection, shared, { x: 40 }, null)).toEqual({ + ok: false, + reason: "shared-tween", + }); + sibling.remove(); +}); diff --git a/packages/studio/src/hooks/gsapValueAtPlayhead.ts b/packages/studio/src/hooks/gsapValueAtPlayhead.ts new file mode 100644 index 00000000000..87c8fc701a0 --- /dev/null +++ b/packages/studio/src/hooks/gsapValueAtPlayhead.ts @@ -0,0 +1,292 @@ +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import { usePlayerStore } from "../player/store/playerStore"; +import { resolveTweenDuration, resolveTweenStart } from "../utils/globalTimeCompiler"; +import { roundTo3 } from "../utils/rounding"; +import { + materializeIfDynamic, + parkPlayheadOnKeyframe, + type GsapDragCommitCallbacks, +} from "./gsapDragCommit"; +import type { GsapEditOutcome, PlayheadEditRefusal } from "./gsapEditOutcome"; +import { + findParsedTween, + parsedImplicitEndValue, + parsedTweenEase, + withExactStepTimes, + withLiveTiming, +} from "./gsapParsedTween"; +import { KEYFRAME_PCT_MATCH } from "./gsapShared"; +import { tweenReach } from "./gsapTweenReach"; + +type Props = Record; +interface Keyframe { + percentage: number; + properties: Props; + ease?: string; + auto?: boolean; +} + +/** A tween's un-animated value of `prop` at its start or end, from GSAP's own parse; null when unknown. */ +export type ImplicitEndValue = (prop: string, end: "start" | "end") => number | null; + +export interface PlayheadEdit { + anim: GsapAnimation; + /** The playhead's composition time, or a keyframe the user selected in the lane. */ + at: { time: number } | { percentage: number }; + /** Every channel here must already be animated by `anim`. */ + values: Record; + implicitEndValue: ImplicitEndValue; + /** The flat tween's ease as GSAP resolved it, for a tween that authors none. */ + parsedEase?: string | null; + /** A channel of the edit the tween does not animate yet, held at this value on its keyframes. */ + backfill?: Record; + /** Hold the backfill from the tween's start too, where GSAP would otherwise begin at the old value. */ + holdFromStart?: boolean; +} + +export type PlayheadEditPlan = + | { + ok: true; + mutation: { + type: "replace-with-keyframes"; + animationId: string; + targetSelector: string; + position: number; + duration: number; + keyframes: Keyframe[]; + easeEach?: string; + }; + /** A keyframe was added, not only changed: keyframe usage counts it as an add. */ + added: boolean; + } + | { ok: false; reason: PlayheadEditRefusal }; + +// GSAP 3.14 defaults: a percentage keyframe eases its segment power1.inOut; an array step is linear. +const PERCENTAGE_SEGMENT_EASE = "power1.inOut"; +const ARRAY_STEP_EASE = "none"; +const roundPct = (pct: number) => Math.round(pct * 1000) / 1000; +const isLinear = (ease: string | undefined) => !ease || ease === "none" || ease === "linear"; + +interface Normalized { + keyframes: Keyframe[]; + easeEach?: string; +} + +function refuse(reason: PlayheadEditRefusal): { ok: false; reason: PlayheadEditRefusal } { + return { ok: false, reason }; +} + +// fallow-ignore-next-line complexity +function normalize(edit: PlayheadEdit): Normalized | { reason: PlayheadEditRefusal } { + const { anim } = edit; + const data = anim.keyframes; + if (data) { + if (!isLinear(anim.ease) || !isLinear(data.ease)) return { reason: "eased-keyframes" }; + if (data.format === "simple-array") return { reason: "simple-array-keyframes" }; + const arrayStep = data.format === "object-array"; + return { + keyframes: data.keyframes.map((kf) => ({ + ...kf, + properties: { ...kf.properties }, + ...(arrayStep ? { ease: kf.ease ?? ARRAY_STEP_EASE } : {}), + })), + ...(data.easeEach && !arrayStep ? { easeEach: data.easeEach } : {}), + }; + } + // The flat tween's ease becomes easeEach: a top-level ease would leave each segment power1.inOut. + const easeEach = anim.ease ?? edit.parsedEase; + if (!easeEach) return { reason: "unknown-ease" }; + const to = { percentage: 100, properties: { ...anim.properties } }; + if (anim.method === "to") return { keyframes: [to], easeEach }; + if (anim.method === "fromTo") { + return { keyframes: [{ percentage: 0, properties: { ...anim.fromProperties } }, to], easeEach }; + } + if (anim.method === "from") { + const end: Props = {}; + for (const prop of Object.keys(anim.properties)) { + const value = edit.implicitEndValue(prop, "end"); + if (value == null) return { reason: "implicit-end-unknown" }; + end[prop] = value; + } + return { + keyframes: [ + { percentage: 0, properties: { ...anim.properties } }, + { percentage: 100, properties: end }, + ], + easeEach, + }; + } + return { reason: "not-a-tween" }; +} + +function valueAt(keyframes: Keyframe[], prop: string, side: "first" | "last") { + const carrying = keyframes.filter((kf) => kf.properties[prop] != null); + const kf = side === "first" ? carrying[0] : carrying.at(-1); + return kf ? { percentage: kf.percentage, value: kf.properties[prop]! } : null; +} + +function upsert(keyframes: Keyframe[], percentage: number, properties: Props, ease?: string) { + const hit = keyframes.find((kf) => Math.abs(kf.percentage - percentage) <= KEYFRAME_PCT_MATCH); + if (hit) { + Object.assign(hit.properties, properties); + return hit; + } + const added = { percentage, properties, ...(ease ? { ease } : {}) }; + keyframes.push(added); + return added; +} + +/** Every channel the tween animates, held at its value at the tween's authored start or end. */ +function heldEnds( + norm: Normalized, + end: "start" | "end", + implicit: ImplicitEndValue, + backfilled: Record, +) { + const props = new Set(norm.keyframes.flatMap((kf) => Object.keys(kf.properties))); + const held: Props = {}; + for (const prop of props) { + const known = valueAt(norm.keyframes, prop, end === "start" ? "first" : "last"); + // A channel holds its last keyframe after it; only a start can be implicit. + const value = + known && (end === "end" || known.percentage <= 0) + ? known.value + : (backfilled[prop] ?? implicit(prop, "start")); + if (value == null) return null; + held[prop] = value; + } + return held; +} + +/** On a keyframe, change it; between two, add one at the playhead; outside the tween, add one there + * and keep the authored ends. Values come from the file's tween or GSAP's parse, never the DOM. */ +// fallow-ignore-next-line complexity +export function planValueAtPlayhead(edit: PlayheadEdit): PlayheadEditPlan { + const { anim, values } = edit; + const start = resolveTweenStart(anim); + const duration = resolveTweenDuration(anim); + if (start == null || !(duration > 0)) return refuse("no-timing"); + const norm = normalize(edit); + if ("reason" in norm) return refuse(norm.reason); + const keyframes = norm.keyframes; + const authored = keyframes.length; + // GSAP runs `scale` beside scaleX/scaleY and the longhands win, so a per-axis edit splits it. + if ("scaleX" in values || "scaleY" in values) { + for (const kf of keyframes) { + const { scale, ...rest } = kf.properties; + if (scale != null) kf.properties = { scaleX: scale, scaleY: scale, ...rest }; + } + } + const backfilled: Record = {}; + for (const [prop, value] of Object.entries(edit.backfill ?? {})) { + if (!(prop in values) || keyframes.some((kf) => kf.properties[prop] != null)) continue; + if (edit.holdFromStart && !keyframes.some((kf) => kf.percentage <= 0)) + keyframes.unshift({ percentage: 0, properties: {} }); + for (const kf of keyframes) kf.properties[prop] = value; + backfilled[prop] = value; + } + if (Object.keys(values).some((prop) => !keyframes.some((kf) => kf.properties[prop] != null))) + return refuse("implicit-end-unknown"); + let position = start; + let span = duration; + + const pct = + "percentage" in edit.at + ? edit.at.percentage + : roundPct(((edit.at.time - start) / duration) * 100); + if (pct >= -KEYFRAME_PCT_MATCH && pct <= 100 + KEYFRAME_PCT_MATCH) { + const at = Math.min(100, Math.max(0, pct)); + const next = [...keyframes] + .sort((a, b) => a.percentage - b.percentage) + .find((kf) => kf.percentage > at + KEYFRAME_PCT_MATCH); + // The new keyframe splits next's segment, so it takes next's ease. + upsert(keyframes, at, { ...values }, next?.ease); + } else { + const time = (edit.at as { time: number }).time; + const before = time < start; + const held = heldEnds(norm, before ? "start" : "end", edit.implicitEndValue, backfilled); + if (!held) return refuse("implicit-end-unknown"); + position = before ? time : start; + span = before ? start + duration - time : time - start; + for (const kf of keyframes) { + kf.percentage = roundPct( + ((start + (kf.percentage / 100) * duration - position) / span) * 100, + ); + } + const oldEdge = roundPct((((before ? start : start + duration) - position) / span) * 100); + // The span the tween gains is new and linear; the authored segments keep their eases. + const linear = isLinear(norm.easeEach ?? PERCENTAGE_SEGMENT_EASE) ? undefined : "none"; + const edge = upsert(keyframes, oldEdge, held, linear); + if (before && linear) edge.ease ??= linear; + upsert(keyframes, before ? 0 : 100, { ...held, ...values }, before ? undefined : linear); + } + + keyframes.sort((a, b) => a.percentage - b.percentage); + return { + ok: true, + mutation: { + type: "replace-with-keyframes", + animationId: anim.id, + targetSelector: anim.targetSelector, + position: roundTo3(position), + duration: roundTo3(span), + keyframes, + ...(norm.easeEach ? { easeEach: norm.easeEach } : {}), + }, + added: keyframes.length > authored, + }; +} + +/** commitValueAtPlayhead's plan, writing nothing, so a group can plan every member first. */ +export function planValueEdit( + selection: DomEditSelection, + anim: GsapAnimation, + values: Record, + iframe: HTMLIFrameElement | null, + { backfill, holdFromStart }: Pick = {}, +): PlayheadEditPlan { + // One keyframe of a tween its siblings share would move them all. + if (tweenReach(anim, selection.element) === "shared") return refuse("shared-tween"); + const { activeKeyframePct, currentTime } = usePlayerStore.getState(); + const tween = findParsedTween(iframe, selection.element, anim); + const timed = withExactStepTimes(anim, tween); + return planValueAtPlayhead({ + anim: withLiveTiming(timed, tween), + at: activeKeyframePct != null ? { percentage: activeKeyframePct } : { time: currentTime }, + values, + backfill, + holdFromStart, + implicitEndValue: parsedImplicitEndValue(tween), + parsedEase: parsedTweenEase(iframe, tween), + }); +} + +/** Writes `values` into `anim` at the playhead (or the keyframe selected in the lane). */ +export async function commitValueAtPlayhead( + selection: DomEditSelection, + anim: GsapAnimation, + values: Record, + iframe: HTMLIFrameElement | null, + callbacks: GsapDragCommitCallbacks, + options: Pick & { + label: string; + beforeReload?: () => void; + }, +): Promise { + await materializeIfDynamic(anim, iframe, callbacks.commitMutation, selection); + const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState(); + const plan = planValueEdit(selection, anim, values, iframe, options); + if (!plan.ok) return { status: "blocked", reason: "keyframes-uneditable", detail: plan.reason }; + await callbacks.commitMutation(selection, plan.mutation, { + label: options.label, + softReload: true, + beforeReload: options.beforeReload, + ...(plan.added && { keyframeAction: "add" as const }), + }); + if (activeKeyframePct != null) { + setActiveKeyframePct(null); + parkPlayheadOnKeyframe(anim, activeKeyframePct); + } + return { status: "persisted" }; +} diff --git a/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.test.ts b/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.test.ts index 9eddc4ab5ab..0c827ab297b 100644 --- a/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.test.ts +++ b/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.test.ts @@ -26,6 +26,29 @@ function recordingCallbacks(): { }; } +/** Rotates a 2s `#box` tween made of `fields` to 50deg at its end; returns what was committed. */ +async function rotateTo50AtEnd(fields: Record) { + const anim = { + id: "#box-rotate", + targetSelector: "#box", + method: "to", + resolvedStart: 0, + duration: 2, + ...fields, + } as unknown as GsapAnimation; + const { mutations, callbacks } = recordingCallbacks(); + await commitWholePropertyOffset( + selection(), + anim, + { rotation: 50 }, + 100, + null, + callbacks, + "Rotate", + ); + return mutations; +} + describe("commitWholePropertyOffset", () => { it("shifts every keyframe of a keyframed tween by the delta at the nearest keyframe", async () => { const anim = { @@ -159,4 +182,24 @@ describe("commitWholePropertyOffset", () => { { type: "update-properties", animationId: "#box-hold", properties: { width: 300 } }, ]); }); + + it("keeps a linear flat tween linear: its ease becomes the keyframes' easeEach", async () => { + // A tween-level ease leaves each percentage segment power1.inOut, so the box drifts mid-segment. + const mutations = await rotateTo50AtEnd({ ease: "none", properties: { rotation: 40 } }); + expect(mutations[0]).toMatchObject({ type: "replace-with-keyframes", easeEach: "none" }); + expect(mutations[0]).not.toHaveProperty("ease", "none"); + }); + + it("keeps a keyframed tween's easeEach", async () => { + const mutations = await rotateTo50AtEnd({ + keyframes: { + easeEach: "none", + keyframes: [ + { percentage: 0, properties: { rotation: 10 } }, + { percentage: 100, properties: { rotation: 40 } }, + ], + }, + }); + expect(mutations[0]).toMatchObject({ easeEach: "none" }); + }); }); diff --git a/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.ts b/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.ts index 4dbc1495107..05e280497fb 100644 --- a/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.ts +++ b/packages/studio/src/hooks/gsapWholePropertyOffsetCommit.ts @@ -6,7 +6,7 @@ import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; import { resolveTweenStart, resolveTweenDuration } from "../utils/globalTimeCompiler"; import { roundTo3 } from "../utils/rounding"; -import { PROPERTY_DEFAULTS } from "./gsapShared"; +import { keyframeEases, PROPERTY_DEFAULTS } from "./gsapShared"; import { synthesizeFlatTweenKeyframes } from "./gsapTweenSynth"; import { materializeIfDynamic, type GsapDragCommitCallbacks } from "./gsapDragCommit"; @@ -38,7 +38,6 @@ export async function commitWholePropertyOffset( const ts = resolveTweenStart(effectiveAnim); const td = resolveTweenDuration(effectiveAnim); - const ease = effectiveAnim.keyframes?.easeEach ?? effectiveAnim.ease; const keys = Object.keys(newValues); const at = (props: Record, key: string) => typeof props[key] === "number" ? (props[key] as number) : (PROPERTY_DEFAULTS[key] ?? 0); @@ -79,7 +78,7 @@ export async function commitWholePropertyOffset( position: roundTo3(ts ?? 0), duration: roundTo3(td || 1), keyframes: shifted, - ease, + ...keyframeEases(effectiveAnim), }, { label, softReload: true }, ); diff --git a/packages/studio/src/hooks/keyframeCacheAstLoad.ts b/packages/studio/src/hooks/keyframeCacheAstLoad.ts index d36b0a3b340..bb71cc83468 100644 --- a/packages/studio/src/hooks/keyframeCacheAstLoad.ts +++ b/packages/studio/src/hooks/keyframeCacheAstLoad.ts @@ -14,6 +14,7 @@ import { synthesizeFlatTweenKeyframes, type MergeableKeyframe, } from "./gsapTweenSynth"; +import { studioApiFetch } from "../utils/studioApiFetch"; export { resolveSelectorElementIds }; @@ -79,7 +80,7 @@ async function requestParsedAnimations( ): Promise { if (!isPreviewBooted(projectId) && !(await whenPreviewBooted(projectId))) return null; try { - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-animations/${encodeURIComponent(sourceFile)}`, // Always revalidate; an unchanged file answers 304. No per-call timestamp // (a deterministic-render no-no). diff --git a/packages/studio/src/hooks/newTweenTarget.test.ts b/packages/studio/src/hooks/newTweenTarget.test.ts index 33ef3e7dd78..50f54d6ed92 100644 --- a/packages/studio/src/hooks/newTweenTarget.test.ts +++ b/packages/studio/src/hooks/newTweenTarget.test.ts @@ -13,57 +13,30 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { parseGsapScript } from "@hyperframes/core/gsap-parser"; import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; import type { DomEditSelection } from "../components/editor/domEditingTypes"; -import { buildStableSelector, getSelectorIndex } from "../components/editor/domEditingDom"; +import { mountGroupSiblings, stableSelectionFor } from "./domSelectionTestHarness"; import { resolveSelectorElementIds } from "./gsapShared"; import { ensureElementAddressable } from "./gsapScriptCommitHelpers"; import { commitStaticGsapPosition, commitStaticGsapRotation, commitStaticGsapSize, - commitKeyframedSizeFromResize, commitWholePathOffset, findExistingPositionWrite, } from "./gsapDragCommit"; import { promoteSetToKeyframes } from "./useEnableKeyframes"; +import { commitValueAtPlayhead } from "./gsapValueAtPlayhead"; afterEach(() => { document.body.innerHTML = ""; }); -function selectionFor(el: HTMLElement): DomEditSelection { - const selector = buildStableSelector(el); - return { - element: el, - id: el.id || undefined, - hfId: el.getAttribute("data-hf-id") || undefined, - selector, - selectorIndex: getSelectorIndex(document, el, selector, "index.html", null), - sourceFile: "index.html", - dataAttributes: { start: "0", duration: "2" }, - } as unknown as DomEditSelection; -} - -/** Five class-only siblings, each with an id so attribution is nameable. */ -function mountGroupSiblings(): HTMLElement[] { - document.body.innerHTML = ` -
-
-
-
-
-
-
- `; - return Array.from(document.querySelectorAll(".group")); -} - /** * The selection production hands these writers: the element HAS an id in the * DOM (so resolveSelectorElementIds can name it) but the SELECTION carries none, * which is the id-less shape buildStableSelector answers with a bare class. */ function classOnlySelection(el: HTMLElement): DomEditSelection { - return { ...selectionFor(el), id: undefined, selector: ".group" } as DomEditSelection; + return { ...stableSelectionFor(el), id: undefined, selector: ".group" } as DomEditSelection; } /** The elements a written targetSelector actually attributes the tween to. */ @@ -94,7 +67,7 @@ describe("ensureElementAddressable — add-animation button", () => { `; const el = document.querySelectorAll(".group")[1]!; - const selection = selectionFor(el); + const selection = stableSelectionFor(el); expect(selection.selector).toBe(".group"); const { selector, autoId } = ensureElementAddressable(selection); @@ -109,20 +82,20 @@ describe("ensureElementAddressable — add-animation button", () => { document.body.innerHTML = `
`; const el = document.querySelector("#box")!; - expect(ensureElementAddressable(selectionFor(el)).selector).toBe("#box"); + expect(ensureElementAddressable(stableSelectionFor(el)).selector).toBe("#box"); }); it("keeps an already-unique class selector as authored", () => { document.body.innerHTML = `
`; const el = document.querySelector(".header")!; - expect(ensureElementAddressable(selectionFor(el)).selector).toBe(".header"); + expect(ensureElementAddressable(stableSelectionFor(el)).selector).toBe(".header"); }); it("still mints an id when there is no live element to disambiguate against", () => { document.body.innerHTML = `
`; const el = document.querySelector("#scene > div")!; - const selection = { ...selectionFor(el), selector: undefined } as DomEditSelection; + const selection = { ...stableSelectionFor(el), selector: undefined } as DomEditSelection; const { selector, autoId } = ensureElementAddressable(selection); @@ -131,25 +104,28 @@ describe("ensureElementAddressable — add-animation button", () => { }); }); +/** Moves the middle of five class-only siblings with no position yet; returns the selector written. */ +async function positionMiddleSibling(): Promise { + const groups = mountGroupSiblings(5, true); + const { mutations, callbacks } = recorder(); + await commitStaticGsapPosition( + classOnlySelection(groups[2]!), + { x: 10, y: 10 }, + { x: 0, y: 0 }, + ".group", + null, + callbacks, + ); + return writtenTargets(mutations)[0]!; +} + describe("gsapDragCommit — new-tween targets", () => { it("commitStaticGsapPosition authors the new set against one element", async () => { - const groups = mountGroupSiblings(); - const { mutations, callbacks } = recorder(); - - await commitStaticGsapPosition( - classOnlySelection(groups[2]!), - { x: 10, y: 10 }, - { x: 0, y: 0 }, - ".group", - null, - callbacks, - ); - - expect(attributedTo(writtenTargets(mutations)[0]!)).toEqual(["group-2"]); + expect(attributedTo(await positionMiddleSibling())).toEqual(["group-2"]); }); it("commitStaticGsapRotation authors the new set against one element", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const { mutations, callbacks } = recorder(); await commitStaticGsapRotation(classOnlySelection(groups[1]!), 42, ".group", null, callbacks); @@ -158,7 +134,7 @@ describe("gsapDragCommit — new-tween targets", () => { }); it("commitStaticGsapSize authors the new set against one element", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const { mutations, callbacks } = recorder(); await commitStaticGsapSize( @@ -172,34 +148,34 @@ describe("gsapDragCommit — new-tween targets", () => { expect(attributedTo(writtenTargets(mutations)[0]!)).toEqual(["group-4"]); }); - it("commitKeyframedSizeFromResize authors the new keyframe tween against one element", async () => { - const groups = mountGroupSiblings(); + it("a keyframe edit refuses a tween its siblings share instead of moving them all", async () => { + const groups = mountGroupSiblings(5, true); const { mutations, callbacks } = recorder(); - const animatedTween = { + const sharedTween = { id: "t1", targetSelector: ".group", method: "to", - properties: {}, + properties: { width: 120 }, resolvedStart: 0, duration: 2, - keyframes: { keyframes: [{ percentage: 0, properties: { x: 0 } }] }, + ease: "none", } as unknown as GsapAnimation; - const handled = await commitKeyframedSizeFromResize( + const outcome = await commitValueAtPlayhead( classOnlySelection(groups[3]!), - { width: 80, height: 40 }, - ".group", + sharedTween, + { width: 80 }, null, - animatedTween, callbacks, + { label: "Resize" }, ); - expect(handled).toBe(true); - expect(attributedTo(writtenTargets(mutations)[0]!)).toEqual(["group-3"]); + expect(outcome).toMatchObject({ status: "blocked", detail: "shared-tween" }); + expect(mutations).toEqual([]); }); it("commitStaticGsapPosition replaces a corrupt keyframed hold against one element", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const { mutations, callbacks } = recorder(); const corruptHold = { id: "hold-1", @@ -225,7 +201,7 @@ describe("gsapDragCommit — new-tween targets", () => { describe("gsapDragCommit — retargeting an existing tween is left alone", () => { it("commitWholePathOffset keeps the tween's own group target", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const { mutations, callbacks } = recorder(); const groupTween = { id: "t-group", @@ -261,7 +237,7 @@ describe("gsapDragCommit — retargeting an existing tween is left alone", () => */ describe("a re-nudge updates its own previous write instead of stacking a second one", () => { it("finds the write the first nudge authored", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const selection = classOnlySelection(groups[2]!); const first = recorder(); @@ -309,7 +285,7 @@ gsap.set(${JSON.stringify(written)}, { x: 10, y: 10 }); */ describe("useEnableKeyframes — rewriting an existing tween keeps its group target", () => { it("promoteSetToKeyframes leaves a group-authored set aimed at the group", async () => { - const groups = mountGroupSiblings(); + const groups = mountGroupSiblings(5, true); const mutations: Array> = []; const setAnim = { id: "set-group", @@ -339,18 +315,7 @@ describe("useEnableKeyframes — rewriting an existing tween keeps its group tar describe("the written selector survives the real writer and parser", () => { it("re-parses to a tween attributed to the one element it targeted", async () => { - const groups = mountGroupSiblings(); - const { mutations, callbacks } = recorder(); - - await commitStaticGsapPosition( - classOnlySelection(groups[2]!), - { x: 10, y: 10 }, - { x: 0, y: 0 }, - ".group", - null, - callbacks, - ); - const written = writtenTargets(mutations)[0]!; + const written = await positionMiddleSibling(); const script = ` const tl = gsap.timeline({ paused: true }); diff --git a/packages/studio/src/hooks/timelineTimingSync.test.ts b/packages/studio/src/hooks/timelineTimingSync.test.ts index 0d31859dfa8..da4b09b04f5 100644 --- a/packages/studio/src/hooks/timelineTimingSync.test.ts +++ b/packages/studio/src/hooks/timelineTimingSync.test.ts @@ -593,6 +593,7 @@ describe("a timing edit's soft reload restores what GSAP wrote from the files", expect(fetchMock).toHaveBeenCalledWith( expect.stringContaining("/files/compositions%2Fsub.html"), + { credentials: "omit" }, ); expect(reloadPreview).not.toHaveBeenCalled(); expect(wt.getAttribute("style")).toBe("left: 700px;"); diff --git a/packages/studio/src/hooks/timelineTimingSync.ts b/packages/studio/src/hooks/timelineTimingSync.ts index f4e638976f2..2b6b941f737 100644 --- a/packages/studio/src/hooks/timelineTimingSync.ts +++ b/packages/studio/src/hooks/timelineTimingSync.ts @@ -28,12 +28,13 @@ import { serializeStudioFileMutations, type StudioProjectFileWriter, } from "../utils/studioFileMutationCoordinator"; +import { studioApiFetch } from "../utils/studioApiFetch"; export async function readFileContent(projectId: string, targetPath: string): Promise { if (targetPath.includes("\0") || targetPath.includes("..")) { throw new Error(`Unsafe path: ${targetPath}`); } - const response = await fetch( + const response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(targetPath)}`, ); if (!response.ok) { diff --git a/packages/studio/src/hooks/useAskAgentModal.ts b/packages/studio/src/hooks/useAskAgentModal.ts index d986f2aed81..1493303a333 100644 --- a/packages/studio/src/hooks/useAskAgentModal.ts +++ b/packages/studio/src/hooks/useAskAgentModal.ts @@ -7,6 +7,7 @@ import { toProjectAbsolutePath, type AgentModalAnchorPoint } from "../utils/stud import { liveMarkupWithoutPreviewMarks } from "../utils/authoredSource"; import { buildElementAgentPrompt, type DomEditSelection } from "../components/editor/domEditing"; import { usePlayerStore } from "../player"; +import { studioApiFetch } from "../utils/studioApiFetch"; // ── Types ── @@ -55,7 +56,7 @@ export function useAskAgentModal({ const targetPath = selection.sourceFile || activeCompPath || "index.html"; try { - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath(pid, `/files/${encodeURIComponent(targetPath)}`), ); if (!response.ok) return; diff --git a/packages/studio/src/hooks/useBlockCatalog.ts b/packages/studio/src/hooks/useBlockCatalog.ts index 7efaee4d4e8..da076baac23 100644 --- a/packages/studio/src/hooks/useBlockCatalog.ts +++ b/packages/studio/src/hooks/useBlockCatalog.ts @@ -5,6 +5,7 @@ import { type BlockCategory, resolveBlockCategory, } from "../utils/blockCategories"; +import { studioApiFetch } from "../utils/studioApiFetch"; type CatalogItem = RegistryItem & { category: BlockCategory; @@ -14,7 +15,7 @@ let catalogCache: CatalogItem[] | null = null; let catalogRequest: Promise | null = null; function loadCatalog(): Promise { - catalogRequest ??= fetch("/api/registry/blocks") + catalogRequest ??= studioApiFetch("/api/registry/blocks") .then((response) => { if (!response.ok) throw new Error("Failed to load catalog"); return response.json() as Promise; diff --git a/packages/studio/src/hooks/useCaptionDetection.ts b/packages/studio/src/hooks/useCaptionDetection.ts index a53040fc14b..1d188a390d2 100644 --- a/packages/studio/src/hooks/useCaptionDetection.ts +++ b/packages/studio/src/hooks/useCaptionDetection.ts @@ -5,6 +5,7 @@ import { useCaptionStore } from "../captions/store"; import { acceptStudioRuntimeMessage } from "../player/lib/runtimeProtocol"; import { useCaptionSync } from "../captions/hooks/useCaptionSync"; import { parseCaptionComposition } from "../captions/parser"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseCaptionDetectionParams { projectId: string | null; @@ -110,7 +111,7 @@ export function useCaptionDetection({ activating = true; const srcPath = captionSrcPath; - fetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(srcPath)}`)) + studioApiFetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(srcPath)}`)) .then((r) => r.json()) .then((data: { content?: string }) => { if (!data.content || !doc || !win || useCaptionStore.getState().isEditMode) return; diff --git a/packages/studio/src/hooks/useCompositionContentLoader.ts b/packages/studio/src/hooks/useCompositionContentLoader.ts index 09994a3edc2..f3576935ccc 100644 --- a/packages/studio/src/hooks/useCompositionContentLoader.ts +++ b/packages/studio/src/hooks/useCompositionContentLoader.ts @@ -1,5 +1,6 @@ import { buildProjectApiPath } from "../utils/projectRouting"; import { useCallback } from "react"; +import { studioApiFetch } from "../utils/studioApiFetch"; /** * Loads a composition file's content for the source editor when a composition @@ -24,7 +25,7 @@ export function useCompositionContentLoader({ if (!projectId) return; setActiveCompPath(comp.endsWith(".html") ? comp : null); setEditingFile({ path: comp, content: null }); - fetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(comp)}`)) + studioApiFetch(buildProjectApiPath(projectId, `/files/${encodeURIComponent(comp)}`)) .then(async (r) => { if (!r.ok) throw new Error(`Failed to load ${comp} (${r.status})`); return r.json(); diff --git a/packages/studio/src/hooks/useDomEditCommitsHelpers.ts b/packages/studio/src/hooks/useDomEditCommitsHelpers.ts index c164b2a4e5b..9d4af820dc8 100644 --- a/packages/studio/src/hooks/useDomEditCommitsHelpers.ts +++ b/packages/studio/src/hooks/useDomEditCommitsHelpers.ts @@ -7,6 +7,7 @@ import { buildProjectApiPath } from "../utils/projectRouting"; import type { DomEditPatchBatch } from "./domEditCommitTypes"; import { formatFieldsSuffix } from "./gsapScriptCommitHelpers"; import { studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; export function formatUnsafeFieldList(fields: Array<{ path: string }>): string { return fields.map((field) => field.path).join(", "); @@ -99,7 +100,7 @@ function isAtomicElementPatchFile(value: unknown): value is AtomicElementPatchFi export async function patchElementBatches(projectId: string, batches: DomEditPatchBatch[]) { const body = JSON.stringify({ batches }); try { - const response = await fetch( + const response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/file-mutations/patch-element-batches`, { method: "POST", @@ -178,7 +179,7 @@ export async function postPatchElement( body: unknown, showToast: ShowToast, ): Promise { - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath( projectId, `/file-mutations/patch-element/${encodeURIComponent(targetPath)}`, diff --git a/packages/studio/src/hooks/useDomEditSession.test.tsx b/packages/studio/src/hooks/useDomEditSession.test.tsx index 41d8be9dbd3..1a0f23c5dd4 100644 --- a/packages/studio/src/hooks/useDomEditSession.test.tsx +++ b/packages/studio/src/hooks/useDomEditSession.test.tsx @@ -10,6 +10,7 @@ import type { DomEditSelection } from "../components/editor/domEditingTypes"; import type { TimelineElement } from "../player"; import type { UseDomEditSessionParams } from "./useDomEditSession"; import { makeSelection } from "./domSelectionTestHarness"; +import { readTranslatePx } from "../components/editor/plainTranslate"; const styleOp = (property: string, value: string): PatchOperation => ({ type: "inline-style", @@ -66,6 +67,7 @@ const groupSelectionSpy = vi.fn(); const gsapCommitMutation = Object.assign(vi.fn(), { batch: vi.fn() }); const neverParsed = new Promise<{ animations: GsapAnimation[] }>(() => undefined); const parsedFile = { current: neverParsed }; +const groupCommitSpy = vi.fn(async () => {}); function createSessionParams( overrides: Partial = {}, @@ -256,7 +258,7 @@ vi.mock("./usePreviewInteraction", () => ({ vi.mock("./useGsapAwareEditing", () => ({ useGsapAwareEditing: () => ({ handleGsapAwarePathOffsetCommit: vi.fn(), - handleGsapAwareGroupPathOffsetCommit: vi.fn(), + handleGsapAwareGroupPathOffsetCommit: groupCommitSpy, handleGsapAwareBoxSizeCommit: vi.fn(), handleGsapAwareRotationCommit: vi.fn(), commitAnimatedProperty: vi.fn(), @@ -605,3 +607,30 @@ describe("a shadow reload promoted without a host re-render", () => { act(() => root.unmount()); }); }); + +describe("handleDomGroupMoveBy", () => { + it("saves through the group drag's commit, leaving a refusal for the host to explain", async () => { + const { useDomEditSession } = await import("./useDomEditSession"); + const element = document.createElement("div"); + document.body.append(element); + element.getBoundingClientRect = () => { + const { x, y } = readTranslatePx(element); + return new DOMRect(x, y, 40, 20); + }; + const selection = makeSelection("card", element); + let moveBy!: ReturnType["handleDomGroupMoveBy"]; + function Probe() { + moveBy = useDomEditSession(createSessionParams()).handleDomGroupMoveBy; + return null; + } + const root = createRoot(document.createElement("div")); + act(() => root.render()); + await act(() => moveBy([{ selection, delta: { x: 10, y: 0 } }])); + expect(groupCommitSpy).toHaveBeenCalledWith( + [{ selection, next: { x: 10, y: 0 }, plainTranslate: true }], + { refusalToast: false }, + ); + act(() => root.unmount()); + element.remove(); + }); +}); diff --git a/packages/studio/src/hooks/useDomEditSession.ts b/packages/studio/src/hooks/useDomEditSession.ts index 24791bd37a3..6398785bbb0 100644 --- a/packages/studio/src/hooks/useDomEditSession.ts +++ b/packages/studio/src/hooks/useDomEditSession.ts @@ -25,6 +25,7 @@ import { membersForDelete, timelineElementsForDelete } from "./domEditDeleteMemb import type { RecordEditInput } from "./domEditDeleteMembers"; import type { DomEditTimelineParams } from "./useDomSelectionTypes"; import { useLivePreviewIframe } from "./useLivePreviewIframe"; +import { moveDomGroupBy, type DomGroupMove } from "../components/editor/domGroupMoveBy"; // Re-exported: the delete rule lives in its own module; callers and its test import it from here. export { membersForDelete }; @@ -445,6 +446,7 @@ export function useDomEditSession({ domEditSelection, selectedGsapAnimations, gsapCommitMutation, + activeCompPath, previewIframeRef, showToast, bumpGsapCache, @@ -459,6 +461,13 @@ export function useDomEditSession({ setArcPath, updateArcSegment, }); + const handleDomGroupMoveBy = useCallback( + (moves: DomGroupMove[]) => + moveDomGroupBy(moves, (updates) => + handleGsapAwareGroupPathOffsetCommit(updates, { refusalToast: false }), + ), + [handleGsapAwareGroupPathOffsetCommit], + ); const { handleUpdateSegmentEase, handleUpdateKeyframeEase, handleSetAllKeyframeEases } = useKeyframeEaseCommits({ gsapCommitMutation, domEditSelectionRef }); const committable = useCommitPreflightCapabilities({ @@ -497,6 +506,7 @@ export function useDomEditSession({ handleDomAttributeBatchCommit, handleDomPathOffsetCommit: handleGsapAwarePathOffsetCommit, handleDomGroupPathOffsetCommit: handleGsapAwareGroupPathOffsetCommit, + handleDomGroupMoveBy, handleDomZIndexReorderCommit, handleDomBoxSizeCommit: handleGsapAwareBoxSizeCommit, handleDomRotationCommit: handleGsapAwareRotationCommit, diff --git a/packages/studio/src/hooks/useDomEditTextCommits.test.tsx b/packages/studio/src/hooks/useDomEditTextCommits.test.tsx index 85124e5487b..eecac6562cb 100644 --- a/packages/studio/src/hooks/useDomEditTextCommits.test.tsx +++ b/packages/studio/src/hooks/useDomEditTextCommits.test.tsx @@ -350,6 +350,29 @@ describe("useDomEditTextCommits", () => { expect(outcome).toEqual({ ok: true, persistence }); }); + it("saves a style map on a selection as one patch, so it is one undo step", async () => { + const { iframe, element } = previewElement("
Original
", "card"); + const persist = vi.fn().mockResolvedValue({ sourceFile: "index.html", changed: true }); + const hook = renderTextCommitHook( + commitParams({ + previewIframeRef: { current: iframe }, + domEditSelection: null, + persistDomEditOperations: persist, + }), + ); + + await act(async () => { + await hook.handleDomStyleCommitForSelection(selectionFor(element), { + "border-width": "4px", + "border-style": "solid", + }); + }); + + expect(persist).toHaveBeenCalledTimes(1); + expect(element.style.borderWidth).toBe("4px"); + expect(element.style.borderStyle).toBe("solid"); + }); + it("declines a style commit with no selection, without reaching the writer", async () => { const persistDomEditOperations = vi.fn().mockResolvedValue(undefined); const hook = renderTextCommitHook( diff --git a/packages/studio/src/hooks/useDomEditTextCommits.ts b/packages/studio/src/hooks/useDomEditTextCommits.ts index 6c8344e0a39..4f93719c66c 100644 --- a/packages/studio/src/hooks/useDomEditTextCommits.ts +++ b/packages/studio/src/hooks/useDomEditTextCommits.ts @@ -109,7 +109,11 @@ export function useDomEditTextCommits({ }); const handleDomStyleCommitForSelection = useCallback( - (selection: DomEditSelection, property: string, value: string): Promise => + ( + selection: DomEditSelection, + propertyOrStylesAsOnePatch: string | Record, + value = "", + ): Promise => commitDomStyles( { activeCompPath, @@ -121,7 +125,9 @@ export function useDomEditTextCommits({ resync: refreshDomEditSelectionFromPreview, }, selection, - { [property]: value }, + typeof propertyOrStylesAsOnePatch === "string" + ? { [propertyOrStylesAsOnePatch]: value } + : propertyOrStylesAsOnePatch, ), [ activeCompPath, diff --git a/packages/studio/src/hooks/useDomGeometryCommit.ts b/packages/studio/src/hooks/useDomGeometryCommit.ts index 234736ae20f..d8cee8f977e 100644 --- a/packages/studio/src/hooks/useDomGeometryCommit.ts +++ b/packages/studio/src/hooks/useDomGeometryCommit.ts @@ -128,6 +128,7 @@ export function useDomGeometryCommit({ domEditSelection: null, selectedGsapAnimations: NO_SELECTED_ANIMATIONS, gsapCommitMutation: gsap.commitMutation, + activeCompPath, previewIframeRef: iframeRef, showToast, bumpGsapCache, diff --git a/packages/studio/src/hooks/useEditHistoryActions.paint.test.tsx b/packages/studio/src/hooks/useEditHistoryActions.paint.test.tsx index fd83d9b8f3e..401ea0e97ab 100644 --- a/packages/studio/src/hooks/useEditHistoryActions.paint.test.tsx +++ b/packages/studio/src/hooks/useEditHistoryActions.paint.test.tsx @@ -4,7 +4,7 @@ import { createRoot } from "react-dom/client"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { afterEach, beforeEach, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, expect, it, vi, type Mock } from "vitest"; import { createStudioApi, openProjectHistory, @@ -168,6 +168,20 @@ it("an undo pressed while a save is still running waits for the server instead o expect(s.box()).toBe("10px"); }); +it("an undo waits for a save queued before its key, not one queued after", async () => { + const s = await studio(); + await s.edit(); + let land!: () => void; + void s.persistence().queueDomEditSave(() => new Promise((resolve) => (land = resolve))); + await vi.waitFor(() => expect(land).toBeTypeOf("function")); + + const undone = s.actions().undo(); + void s.persistence().queueDomEditSave(() => new Promise(() => {})); + land(); + await act(() => undone); + expect(s.file()).toBe(BEFORE); +}); + it("an undo after an outside write ends with the preview showing the file the server restored", async () => { const s = await studio(); await s.edit(); @@ -202,10 +216,8 @@ function Nudge({ target, save }: { target: HTMLElement; save: () => Promise { - const s = await studio(); - await s.edit(); - resetNudgeKeys(); +/** A nudge save that waits for `finish()`, then writes and records the nudge as the real save does. */ +function queuedNudgeSave(s: Awaited>) { let finish!: () => void; const save = vi.fn(async () => { await new Promise((resolve) => (finish = resolve)); @@ -215,6 +227,24 @@ it("an undo pressed while a nudge waits for more keys never shows the move befor files: { "index.html": { before: AFTER, after: NUDGED } }, }); }); + return { save, finish: () => finish() }; +} + +/** Mounts the nudge, presses ArrowRight once and waits for its save; returns the nudge's translate reader. */ +async function pressNudge(s: Awaited>, save: Mock<() => Promise>) { + s.mount(createElement(Nudge, { target: s.element("box"), save })); + act(() => { + window.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", cancelable: true })); + }); + await vi.waitFor(() => expect(save).toHaveBeenCalledTimes(1)); + return () => s.element("box").style.getPropertyValue("translate"); +} + +it("an undo pressed while a nudge waits for more keys never shows the move before it undone", async () => { + const s = await studio(); + await s.edit(); + resetNudgeKeys(); + const { save, finish } = queuedNudgeSave(s); s.mount(createElement(Nudge, { target: s.element("box"), save })); act(() => { window.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", cancelable: true })); @@ -240,21 +270,8 @@ it("an undo pressed while a nudge's save is queued shows the nudge undone in the const s = await studio(); await s.edit(); resetNudgeKeys(); - let finish!: () => void; - const save = vi.fn(async () => { - await new Promise((resolve) => (finish = resolve)); - writeFileSync(s.path, NUDGED); - await s.history().recordEdit({ - label: "Move layer", - files: { "index.html": { before: AFTER, after: NUDGED } }, - }); - }); - s.mount(createElement(Nudge, { target: s.element("box"), save })); - act(() => { - window.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", cancelable: true })); - }); - await vi.waitFor(() => expect(save).toHaveBeenCalledTimes(1)); - const nudge = () => s.element("box").style.getPropertyValue("translate"); + const { save, finish } = queuedNudgeSave(s); + const nudge = await pressNudge(s, save); expect(nudge()).not.toBe(""); const undone = s.actions().undo(); @@ -267,6 +284,51 @@ it("an undo pressed while a nudge's save is queued shows the nudge undone in the expect(s.box()).toBe("50px"); }); +/** A nudge whose save is queued and then rejects, and the history requests the undo sends. */ +async function failingNudge(s: Awaited>) { + resetNudgeKeys(); + let fail!: () => void; + const save = vi.fn( + () => new Promise((_, reject) => (fail = () => reject(new Error("The save failed.")))), + ); + const nudge = await pressNudge(s, save); + const steps: string[] = []; + const real = globalThis.fetch; + vi.stubGlobal("fetch", (url: string, init?: RequestInit) => { + if (/\/history\/(step|undo)$/.test(url)) steps.push(url); + return real(url, init); + }); + return { fail: () => fail(), steps, nudge }; +} + +it("an undo pressed while a nudge's save fails keeps the nudge undone and steps no older edit", async () => { + const s = await studio(); + await s.edit(); + const n = await failingNudge(s); + expect(n.nudge()).not.toBe(""); + + const undone = s.actions().undo(); + expect(n.nudge()).toBe(""); + n.fail(); + await act(() => undone); + expect(n.steps).toEqual([]); + expect(s.file()).toBe(AFTER); + expect(s.box()).toBe("50px"); + expect(n.nudge()).toBe(""); +}); + +it("an undo pressed while the only edit's save fails leaves the screen as the file, nothing put back", async () => { + const s = await studio(); + s.show(BEFORE); + const n = await failingNudge(s); + + const undone = s.actions().undo(); + n.fail(); + await act(() => undone); + expect(s.file()).toBe(BEFORE); + expect(n.nudge()).toBe(""); +}); + it("an undo pressed while a queued save fails undoes the edit before it, file and box alike", async () => { const s = await studio(); await s.edit(); diff --git a/packages/studio/src/hooks/useEditHistoryActions.test.tsx b/packages/studio/src/hooks/useEditHistoryActions.test.tsx index 402242c4b7f..2a5c3f7cd40 100644 --- a/packages/studio/src/hooks/useEditHistoryActions.test.tsx +++ b/packages/studio/src/hooks/useEditHistoryActions.test.tsx @@ -5,6 +5,7 @@ import { createRoot, type Root } from "react-dom/client"; import { afterEach, describe, expect, it, vi } from "vitest"; import { STUDIO_MOTION_PATH } from "../components/editor/studioMotion"; import { useEditHistoryActions, type EditHistoryHandle } from "./useEditHistoryActions"; +import { trackStudioPendingEdit } from "../utils/studioPendingEdits"; (globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true; @@ -30,6 +31,7 @@ function mount( undo: vi.fn(async () => result), redo: vi.fn(async () => result), predict: () => predicted ?? null, + claims: () => 7, }; const putBack = vi.fn(); const deps = { @@ -60,6 +62,19 @@ const PREDICTED = { id: "e1", files: { "index.html": { previous: "B", restored: const SERVER_FILES = { "index.html": { previous: "B", restored: "A2" } }; describe("useEditHistoryActions", () => { + it("asks for the edit claimed after the key's claim count only when an edit was saving at the key", async () => { + const { deps, actions } = mount({ ok: false, reason: "empty" }); + await act(() => actions.undo()); + expect(deps.editHistory.undo.mock.calls[0]![0].claimedAfter).toBeUndefined(); + + let land!: () => void; + trackStudioPendingEdit(new Promise((resolve) => (land = resolve))); + const undone = actions.undo(); + land(); + await act(() => undone); + expect(deps.editHistory.undo.mock.calls[1]![0].claimedAfter).toBe(7); + }); + it("corrects a shown step from the server's restore, diffed from what the preview shows", async () => { const { deps, actions } = mount( { ok: true, label: "Undid: Move", paths: ["index.html"], undoes: "e1", files: SERVER_FILES }, diff --git a/packages/studio/src/hooks/useEditHistoryActions.ts b/packages/studio/src/hooks/useEditHistoryActions.ts index 9f75d41f63a..14292658df9 100644 --- a/packages/studio/src/hooks/useEditHistoryActions.ts +++ b/packages/studio/src/hooks/useEditHistoryActions.ts @@ -3,7 +3,10 @@ import { useCallback, useMemo } from "react"; import { STUDIO_MOTION_PATH } from "../components/editor/studioMotion"; import { serializeStudioFileMutations } from "../utils/studioFileMutationCoordinator"; import type { RestoreFiles } from "../utils/gsapUndoRestore"; -import { revertNewestStudioPendingEdit } from "../utils/studioPendingEdits"; +import { + hasStudioPendingEdits, + paintBackNewestStudioPendingEdit, +} from "../utils/studioPendingEdits"; interface HistoryResult { ok: boolean; @@ -18,11 +21,13 @@ interface HistoryResult { interface HistoryFileCallbacks { readFile: (path: string) => Promise; serialize?: (paths: readonly string[], task: () => Promise) => Promise; + claimedAfter?: number; } export interface EditHistoryHandle { undo: (cb: HistoryFileCallbacks) => Promise; redo: (cb: HistoryFileCallbacks) => Promise; predict?: (direction: "undo" | "redo") => { id: string; files: RestoreFiles } | null; + claims?: () => number; state: { undo: ReadonlyArray<{ createdAt: number }>; redo: ReadonlyArray<{ createdAt: number }>; @@ -30,7 +35,7 @@ export interface EditHistoryHandle { } export interface UseEditHistoryActionsOptions { - editHistory: Pick; + editHistory: Pick; readOptionalProjectFile: (path: string) => Promise; readProjectFile: (path: string) => Promise; writeProjectFile: (path: string, content: string) => Promise; @@ -77,22 +82,28 @@ export function useEditHistoryActions({ const predicted = editHistory.predict?.(direction) ?? null; const predictedShown = predicted ? (showHistoryRestoreNow?.(predicted.files) ?? null) : null; const pendingEditShown = - !predictedShown && direction === "undo" ? revertNewestStudioPendingEdit() : null; - const putBack = predictedShown ?? pendingEditShown; + !predictedShown && direction === "undo" ? paintBackNewestStudioPendingEdit() : null; + const putBack = predictedShown ?? pendingEditShown?.showAgain; + const claimedAfter = + direction === "undo" && hasStudioPendingEdits() ? editHistory.claims?.() : undefined; let result: HistoryResult = { ok: false, reason: "failed" }; let serverSteppedShown = false; + let revertIsTheUndo = false; try { await waitForPendingDomEditSaves(); + revertIsTheUndo = Boolean(pendingEditShown && !(await pendingEditShown.landed())); + if (revertIsTheUndo) return; result = await editHistory[direction]({ readFile: readHistoryFile, serialize: serializeHistoryFiles, + claimedAfter, }); const stepped = Boolean(result.ok && result.label); serverSteppedShown = predictedShown ? stepped && result.undoes === predicted?.id : stepped && Boolean(pendingEditShown); } finally { - if (putBack && !serverSteppedShown) putBack(); + if (putBack && !serverSteppedShown && !revertIsTheUndo) putBack(); } if (!result.ok && result.reason === "content-mismatch") { showToast( diff --git a/packages/studio/src/hooks/useElementLifecycleOps.ts b/packages/studio/src/hooks/useElementLifecycleOps.ts index 25c934da88b..a4567d9ea3f 100644 --- a/packages/studio/src/hooks/useElementLifecycleOps.ts +++ b/packages/studio/src/hooks/useElementLifecycleOps.ts @@ -24,6 +24,7 @@ import type { CommitDomEditPatchBatches, DomEditPatchBatch } from "./domEditComm import { domEditCommitDeclined, type DomEditCommitOutcome } from "./domEditCommitRunner"; import { cutoverCommittedOrThrow, type CutoverResult } from "../utils/sdkCutover"; import { studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseElementLifecycleOpsParams extends DomEditCommitBaseParams { /** Route delete through SDK when session resolves the hf-id. */ @@ -156,7 +157,7 @@ export function useElementLifecycleOps({ writeFile: writeProjectFile, recordEdit: editHistory.recordEdit, rewrite: async (originalContent) => { - const removeResponse = await fetch( + const removeResponse = await studioApiFetch( buildProjectApiPath( pid, `/file-mutations/remove-elements/${encodeURIComponent(targetPath)}`, diff --git a/packages/studio/src/hooks/useEnableKeyframes.test.ts b/packages/studio/src/hooks/useEnableKeyframes.test.ts index 4334e7e6cda..d1405c0eeac 100644 --- a/packages/studio/src/hooks/useEnableKeyframes.test.ts +++ b/packages/studio/src/hooks/useEnableKeyframes.test.ts @@ -378,7 +378,10 @@ function makeElementSelection(): DomEditSelection { } as DomEditSelection; } -function stubFlatTweenConversion(id: string): { +function stubFlatTweenConversion( + id: string, + easeEach?: string, +): { flat: GsapAnimation; converted: GsapAnimation; } { @@ -393,6 +396,7 @@ function stubFlatTweenConversion(id: string): { { percentage: 0, properties: { x: 0 } }, { percentage: 100, properties: { x: 10 } }, ], + ...(easeEach && { easeEach }), }, }); flatTweenResponses(flat, converted); @@ -437,6 +441,33 @@ describe("useEnableKeyframes — flat tween transaction", () => { expect(convertOptions?.coalesceKey).toEqual(expect.any(String)); }); + it("keeps the converted tween's easeEach when it extends it to the playhead", async () => { + window.location.hash = "#/project/test-project"; + usePlayerStore.setState({ currentTime: 3 }); + const { flat } = stubFlatTweenConversion("flat-1", "none"); + const commitMutation = vi.fn(async () => undefined); + const enable = renderEnableKeyframes({ + domEditSelection: makeElementSelection(), + selectedGsapAnimations: [flat], + previewIframeRef: { + current: { + contentWindow: { gsap: { getProperty: () => 10 } }, + } as unknown as HTMLIFrameElement, + }, + handleGsapAddAnimation: vi.fn(), + handleGsapConvertToKeyframes: vi.fn(async () => undefined), + handleGsapRemoveKeyframe: vi.fn(), + commitMutation, + }); + + await act(async () => enable()); + + expect(commitMutation.mock.calls[0]?.[0]).toMatchObject({ + type: "replace-with-keyframes", + easeEach: "none", + }); + }); + it("passes the convert coalesce key to an inside-range batch edit", async () => { window.location.hash = "#/project/test-project"; usePlayerStore.setState({ currentTime: 1.5 }); diff --git a/packages/studio/src/hooks/useEnableKeyframes.ts b/packages/studio/src/hooks/useEnableKeyframes.ts index 71b7e0f95d8..7ccf8ddfedf 100644 --- a/packages/studio/src/hooks/useEnableKeyframes.ts +++ b/packages/studio/src/hooks/useEnableKeyframes.ts @@ -15,6 +15,7 @@ import { fetchParsedAnimations, getAnimationsForElement } from "./useGsapTweenCa import { existingTweenTargetSelector, computeElementPercentage, + keyframeEases, KEYFRAME_PCT_MATCH, isInstantHold, resolveEditableTweenDuration, @@ -266,7 +267,7 @@ async function extendKeyframedTweenToPlayhead( position: extended.position, duration: extended.duration, keyframes: extended.keyframes, - ease: anim.ease, + ...keyframeEases(anim), }, { label: "Add keyframe", diff --git a/packages/studio/src/hooks/useExternalFileChangeCoordinator.test.tsx b/packages/studio/src/hooks/useExternalFileChangeCoordinator.test.tsx index 3215bb56991..50a7a5136df 100644 --- a/packages/studio/src/hooks/useExternalFileChangeCoordinator.test.tsx +++ b/packages/studio/src/hooks/useExternalFileChangeCoordinator.test.tsx @@ -83,6 +83,25 @@ describe("external file change coordinator", () => { expect(captured.handle?.blocked).toBeNull(); }); + it("keeps one file-change subscription across re-renders and delivers to the latest callbacks", async () => { + const on = vi.fn((_event: string, next: HotHandler) => void (handler = next)); + vi.stubGlobal("__HF_STUDIO_HOT_TEST_ADAPTER__", { on, off: vi.fn() }); + const { options } = await mountCoordinator(); + on.mockClear(); + const root = createRoot(document.createElement("div")); + roots.push(root); + function Probe({ onAccepted }: { onAccepted: () => void }) { + useExternalFileChangeCoordinator({ ...options, onAcceptedPersistedFileChange: onAccepted }); + return null; + } + const latest = vi.fn(); + await act(async () => root.render()); + await act(async () => root.render()); + await act(async () => handler?.({ path: "index.html", content: "external", version: "v2" })); + expect(on).toHaveBeenCalledOnce(); + expect(latest).toHaveBeenCalledOnce(); + }); + // The file tree (useFileTree) is only ever refreshed from Studio's own file // operations (create/delete/rename/upload) — never on an external change. // Without this call, an agent removing or replacing a composition updates diff --git a/packages/studio/src/hooks/useExternalFileChangeCoordinator.ts b/packages/studio/src/hooks/useExternalFileChangeCoordinator.ts index 0ab33dc30fe..5026ab7363a 100644 --- a/packages/studio/src/hooks/useExternalFileChangeCoordinator.ts +++ b/packages/studio/src/hooks/useExternalFileChangeCoordinator.ts @@ -448,9 +448,11 @@ export function useExternalFileChangeCoordinator({ [projectId, pendingTimelineEditPathRef, startDrainLoop, onAcceptedPersistedFileChange], ); + const processChangeRef = useRef(processChange); + processChangeRef.current = processChange; useEffect(() => { // One decoder for all three transports; the rungs only choose the channel. - const handler = (delivery?: unknown) => processChange(decodeFileChange(delivery)); + const handler = (delivery?: unknown) => processChangeRef.current(decodeFileChange(delivery)); const adapter = testHotAdapter(); if (adapter) { adapter.on("hf:file-change", handler); @@ -461,7 +463,7 @@ export function useExternalFileChangeCoordinator({ return () => import.meta.hot?.off?.("hf:file-change", handler); } return sseFileChangeChannel(handler); - }, [processChange]); + }, []); const retry = useCallback(async () => { const current = blockedRef.current; diff --git a/packages/studio/src/hooks/useFileManager.projectOwnership.test.tsx b/packages/studio/src/hooks/useFileManager.projectOwnership.test.tsx index dd5e04c4a14..57f9560be7b 100644 --- a/packages/studio/src/hooks/useFileManager.projectOwnership.test.tsx +++ b/packages/studio/src/hooks/useFileManager.projectOwnership.test.tsx @@ -129,6 +129,7 @@ describe("useFileManager project ownership", () => { expect(fetchMock).toHaveBeenCalledWith( "/api/projects/project-a%2F..%2Fother%3Fx%3D1/files/index.html", + { credentials: "omit" }, ); expect(fetchMock).toHaveBeenCalledWith( "/api/projects/project-a%2F..%2Fother%3Fx%3D1/files/index.html", @@ -136,14 +137,18 @@ describe("useFileManager project ownership", () => { ); expect(fetchMock).toHaveBeenCalledWith( "/api/projects/project-a%2F..%2Fother%3Fx%3D1/files/missing.html", + { credentials: "omit" }, ); expect(fetchMock).toHaveBeenCalledWith( "/api/projects/project-a%2F..%2Fother%3Fx%3D1/files/missing.html", expect.objectContaining({ method: "PUT", body: "A_NEW" }), ); - expect(fetchMock).toHaveBeenCalledWith("/api/projects/project-b%23fragment/files/index.html"); + expect(fetchMock).toHaveBeenCalledWith("/api/projects/project-b%23fragment/files/index.html", { + credentials: "omit", + }); expect(fetchMock).toHaveBeenCalledWith( "/api/projects/project-b%23fragment/files/index.html?optional=1", + { credentials: "omit" }, ); await act(async () => root.unmount()); diff --git a/packages/studio/src/hooks/useFileManager.ts b/packages/studio/src/hooks/useFileManager.ts index d96aa535fdd..23627b2277f 100644 --- a/packages/studio/src/hooks/useFileManager.ts +++ b/packages/studio/src/hooks/useFileManager.ts @@ -8,6 +8,7 @@ import { serializeStudioFileMutation } from "../utils/studioFileMutationCoordina import { useFileTree } from "./useFileTree"; import { useEditorSave } from "./useEditorSave"; import { useProjectFileWriter } from "./useProjectFileWriter"; +import { studioApiFetch } from "../utils/studioApiFetch"; // ── Types ── @@ -133,7 +134,7 @@ export function useFileManager({ setEditingFile({ path, content: null }); return; } - fetch(`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`) + studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`) .then((r) => { if (!r.ok) throw new Error(`Failed to load ${path} (${r.status})`); return r.json(); @@ -167,9 +168,12 @@ export function useFileManager({ const requestId = ++revealRequestIdRef.current; const controller = new AbortController(); revealAbortRef.current = controller; - fetch(`/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(sourceFile)}`, { - signal: controller.signal, - }) + studioApiFetch( + `/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(sourceFile)}`, + { + signal: controller.signal, + }, + ) .then((r) => r.json()) .then((data: { content?: string; version?: string }) => { if (requestId !== revealRequestIdRef.current) return; @@ -200,7 +204,7 @@ export function useFileManager({ const qs = dir ? `?dir=${encodeURIComponent(dir)}` : ""; try { - const res = await fetch(`/api/projects/${encodeURIComponent(pid)}/upload${qs}`, { + const res = await studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/upload${qs}`, { method: "POST", body: formData, }); @@ -246,7 +250,7 @@ export function useFileManager({ content = '\n\n\n \n\n\n\n\n\n'; } - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`, { method: "POST", @@ -270,7 +274,7 @@ export function useFileManager({ async (path: string) => { const pid = projectIdRef.current; if (!pid) return; - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path + "/.gitkeep")}`, { method: "POST", @@ -293,7 +297,7 @@ export function useFileManager({ async (path: string) => { const pid = projectIdRef.current; if (!pid) return; - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(path)}`, { method: "DELETE", @@ -315,7 +319,7 @@ export function useFileManager({ async (oldPath: string, newPath: string) => { const pid = projectIdRef.current; if (!pid) return; - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(pid)}/files/${encodeURIComponent(oldPath)}`, { method: "PATCH", @@ -342,7 +346,7 @@ export function useFileManager({ async (path: string) => { const pid = projectIdRef.current; if (!pid) return; - const res = await fetch(`/api/projects/${encodeURIComponent(pid)}/duplicate-file`, { + const res = await studioApiFetch(`/api/projects/${encodeURIComponent(pid)}/duplicate-file`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ path }), diff --git a/packages/studio/src/hooks/useFileTree.ts b/packages/studio/src/hooks/useFileTree.ts index 3cc8eb87200..ed3c6b6f683 100644 --- a/packages/studio/src/hooks/useFileTree.ts +++ b/packages/studio/src/hooks/useFileTree.ts @@ -3,6 +3,7 @@ import { useState, useCallback, useEffect, useMemo, useRef } from "react"; import { FONT_EXT } from "../utils/mediaTypes"; import { fontFamilyFromAssetPath, type ImportedFontAsset } from "../components/editor/fontAssets"; import { captureProjectProvenance } from "../components/feedback/projectProvenance"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseFileTreeOptions { projectId: string | null; @@ -38,7 +39,7 @@ export function useFileTree({ projectId, projectIdRef }: UseFileTreeOptions) { if (!projectId) return; let cancelled = false; setFetched({ projectId, loaded: false, fileTree: [], compositionPaths: [], projectDir: null }); - fetch(buildProjectApiPath(projectId)) + studioApiFetch(buildProjectApiPath(projectId)) // An unresolvable project answers 404 with a JSON body, so without this // the error path parsed cleanly and the success branch below recorded an // empty tree — and an empty provenance snapshot — for a project that was @@ -84,7 +85,7 @@ export function useFileTree({ projectId, projectIdRef }: UseFileTreeOptions) { refreshAbortRef.current = controller; let data: { files?: string[]; compositions?: string[] }; try { - const res = await fetch(buildProjectApiPath(pid), { signal: controller.signal }); + const res = await studioApiFetch(buildProjectApiPath(pid), { signal: controller.signal }); data = await res.json(); } catch (err) { if (err instanceof DOMException && err.name === "AbortError") return; diff --git a/packages/studio/src/hooks/useFrameCapture.ts b/packages/studio/src/hooks/useFrameCapture.ts index 1deeb544f57..5280211cdb7 100644 --- a/packages/studio/src/hooks/useFrameCapture.ts +++ b/packages/studio/src/hooks/useFrameCapture.ts @@ -2,6 +2,7 @@ import { useMemo, useState, useCallback, useRef, type MouseEvent } from "react"; import { useMountEffect } from "./useMountEffect"; import { liveTime, usePlayerStore } from "../player"; import { buildFrameCaptureFilename, buildFrameCaptureUrl } from "../utils/frameCapture"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseFrameCaptureParams { projectId: string | null; @@ -67,7 +68,10 @@ export function useFrameCapture({ const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 30000); try { - const response = await fetch(href, { cache: "no-store", signal: controller.signal }); + const response = await studioApiFetch(href, { + cache: "no-store", + signal: controller.signal, + }); clearTimeout(timeout); if (!response.ok) { let msg = `Capture failed (${response.status})`; diff --git a/packages/studio/src/hooks/useFreezeFrame.ts b/packages/studio/src/hooks/useFreezeFrame.ts index 4e3d85ac94e..233a6d8b7c3 100644 --- a/packages/studio/src/hooks/useFreezeFrame.ts +++ b/packages/studio/src/hooks/useFreezeFrame.ts @@ -6,6 +6,7 @@ import { buildProjectApiPath } from "../utils/projectRouting"; import { markStudioWriteToken } from "../utils/studioFileVersion"; import { serializeStudioFileMutations } from "../utils/studioFileMutationCoordinator"; import type { RecordEditInput } from "../utils/studioFileHistory"; +import { studioApiFetch } from "../utils/studioApiFetch"; type ProjectFileWriter = (path: string, content: string, expectedContent?: string) => Promise; @@ -31,7 +32,7 @@ function errorOf(value: unknown): string | null { } async function readVersion(projectId: string, path: string): Promise { - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath(projectId, `/files/${encodeURIComponent(path)}`), ); const body: unknown = await response.json().catch(() => null); @@ -53,7 +54,7 @@ export async function requestFreezeFrame(input: { const expectedVersion = await readVersion(input.projectId, input.path); const transactionToken = `freeze:${crypto.randomUUID()}`; markStudioWriteToken(transactionToken); - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath(input.projectId, "/file-mutations/freeze-frame"), { method: "POST", diff --git a/packages/studio/src/hooks/useGroupCommits.ts b/packages/studio/src/hooks/useGroupCommits.ts index 29628dcb82e..56324485b0d 100644 --- a/packages/studio/src/hooks/useGroupCommits.ts +++ b/packages/studio/src/hooks/useGroupCommits.ts @@ -16,6 +16,7 @@ import { type ElementMatchSelection, } from "../utils/studioHelpers"; import type { TimelineElement } from "../player"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseGroupCommitsParams extends DomEditCommitBaseParams { /** Resync the SDK session after a server-side write (the wrapper/unwrap changes @@ -132,7 +133,7 @@ async function commitStructuralMutation( writeFile: deps.writeProjectFile, recordEdit: deps.editHistory.recordEdit, rewrite: async (originalContent) => { - const mutateResponse = await fetch( + const mutateResponse = await studioApiFetch( buildProjectApiPath(pid, `/file-mutations/${route}/${encodeURIComponent(targetPath)}`), { method: "POST", diff --git a/packages/studio/src/hooks/useGsapAwareEditing.groupPlan.test.tsx b/packages/studio/src/hooks/useGsapAwareEditing.groupPlan.test.tsx new file mode 100644 index 00000000000..aa2ada2bff7 --- /dev/null +++ b/packages/studio/src/hooks/useGsapAwareEditing.groupPlan.test.tsx @@ -0,0 +1,160 @@ +// @vitest-environment happy-dom + +import { act } from "react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import type { GsapAnimation } from "@hyperframes/core/gsap-parser"; +import type { DomEditSelection } from "../components/editor/domEditingTypes"; +import type { DomEditGroupPathOffsetCommit } from "../components/editor/domEditOverlayGestures"; +import { usePlayerStore } from "../player/store/playerStore"; +import { trackStudioEditBlocked } from "../utils/studioSaveDiagnostics"; +import { GSAP_EDIT_BLOCK_COPY } from "./gsapEditOutcome"; +import { mountGsapAwareEditing } from "./useGsapAwareEditing.testHelpers"; + +vi.mock("../utils/studioSaveDiagnostics", async (importOriginal) => ({ + ...(await importOriginal()), + trackStudioEditBlocked: vi.fn(), + trackStudioSaveFailure: vi.fn(), +})); + +(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +beforeEach(() => { + usePlayerStore.setState({ autoKeyframeEnabled: true, currentTime: 1, activeKeyframePct: null }); +}); + +afterEach(() => { + vi.clearAllMocks(); + document.body.innerHTML = ""; + Reflect.deleteProperty(window, "__timelines"); +}); + +const positionTween = (id: string, extra: Partial = {}) => + ({ + id: `#${id}-to-0-position`, + targetSelector: `#${id}`, + propertyGroup: "position", + method: "to", + properties: { x: 100 }, + position: 0, + resolvedStart: 0, + duration: 2, + ease: "none", + ...extra, + }) as unknown as GsapAnimation; + +/** Three members GSAP is visibly moving, one `to` tween each in the file. */ +function mountGroup(animations: GsapAnimation[]) { + const elements = ["a", "b", "c"].map((id) => { + const el = Object.assign(document.createElement("div"), { id }); + document.body.append(el); + return el; + }); + const live = elements.map((el) => ({ + targets: () => [el], + vars: { x: 100, duration: 2 }, + duration: () => 2, + startTime: () => 0, + })); + const timelines = { root: { getChildren: () => live, duration: () => 2 } }; + Reflect.set(window, "__timelines", timelines); + const iframe = { + contentWindow: { gsap: { getProperty: () => 0, set: vi.fn() }, __timelines: timelines }, + contentDocument: document, + } as unknown as HTMLIFrameElement; + const commitMutation = Object.assign(vi.fn().mockResolvedValue(undefined), { + batch: vi.fn().mockResolvedValue(undefined), + }); + const showToast = vi.fn(); + const stageElementPositionOffset = vi.fn(() => ({ save: vi.fn(), rollback: vi.fn() })); + const { editing, root } = mountGsapAwareEditing({ + gsapCommitMutation: commitMutation, + activeCompPath: "index.html", + previewIframeRef: { current: iframe }, + showToast, + makeFetchFallback: () => async () => animations, + stageElementPositionOffset, + }); + const groupCommit = (updates: DomEditGroupPathOffsetCommit[]) => + editing().handleGsapAwareGroupPathOffsetCommit(updates); + const updates = elements.map((element) => ({ + selection: { + element, + id: element.id, + selector: `#${element.id}`, + } as unknown as DomEditSelection, + next: { x: 30, y: 0 }, + })); + const written = () => [ + ...commitMutation.mock.calls.map((call) => call[1]), + ...commitMutation.batch.mock.calls.flatMap(([calls]) => + calls.map((c: { mutation: unknown }) => c.mutation), + ), + ]; + return { elements, iframe, updates, groupCommit, commitMutation, written, showToast, root }; +} + +describe("a group drag plans every member before its first write", () => { + it("refuses the whole group when one member's tween cannot take a keyframe", async () => { + const h = mountGroup([ + positionTween("a"), + positionTween("b", { ease: undefined }), + positionTween("c"), + ]); + const styles = h.elements.map((el) => el.getAttribute("style")); + + await expect(h.groupCommit(h.updates)).rejects.toMatchObject({ + name: "GsapEditBlockedError", + reason: "keyframes-uneditable", + detail: "unknown-ease", + }); + + expect(h.written()).toEqual([]); + expect(h.commitMutation.batch).not.toHaveBeenCalled(); + const gsap = (h.iframe.contentWindow as unknown as { gsap: { set: unknown } }).gsap; + expect(gsap.set).not.toHaveBeenCalled(); + expect(h.elements.map((el) => el.getAttribute("style"))).toEqual(styles); + expect(h.showToast).toHaveBeenCalledTimes(1); + expect(h.showToast).toHaveBeenCalledWith(GSAP_EDIT_BLOCK_COPY["keyframes-uneditable"], "error"); + expect(trackStudioEditBlocked).toHaveBeenCalledTimes(1); + expect(trackStudioEditBlocked).toHaveBeenCalledWith(expect.objectContaining({ targetId: "b" })); + act(() => h.root.unmount()); + }); + + it("refuses members animated in two files, since the batch writes one file", async () => { + const h = mountGroup(["a", "b", "c"].map((id) => positionTween(id))); + const updates = h.updates.map((u, i) => ({ + ...u, + selection: { ...u.selection, sourceFile: i === 2 ? "scenes/intro.html" : "index.html" }, + })); + + await expect(h.groupCommit(updates)).rejects.toMatchObject({ reason: "mixed-files" }); + + expect(h.written()).toEqual([]); + expect(trackStudioEditBlocked).toHaveBeenCalledWith(expect.objectContaining({ targetId: "c" })); + act(() => h.root.unmount()); + }); + + it("writes a group whose members name the open file or leave it implied", async () => { + const h = mountGroup(["a", "b", "c"].map((id) => positionTween(id))); + const updates = h.updates.map((u, i) => ({ + ...u, + selection: { ...u.selection, sourceFile: i === 0 ? "" : "index.html" }, + })); + + await h.groupCommit(updates); + + expect(h.written()).toHaveLength(3); + act(() => h.root.unmount()); + }); + + it("writes every member when each plan holds", async () => { + const h = mountGroup(["a", "b", "c"].map((id) => positionTween(id))); + + await h.groupCommit(h.updates); + + const ids = h.written().map((m) => (m as { animationId?: string }).animationId); + expect(ids).toEqual(["#a-to-0-position", "#b-to-0-position", "#c-to-0-position"]); + expect(h.showToast).not.toHaveBeenCalled(); + act(() => h.root.unmount()); + }); +}); diff --git a/packages/studio/src/hooks/useGsapAwareEditing.test.tsx b/packages/studio/src/hooks/useGsapAwareEditing.test.tsx index 22818afe7cf..9568bfda5e9 100644 --- a/packages/studio/src/hooks/useGsapAwareEditing.test.tsx +++ b/packages/studio/src/hooks/useGsapAwareEditing.test.tsx @@ -119,18 +119,21 @@ function mountResizeHandler( type AwareEditingParams = Parameters[0]; function mountGroupHandler({ - gsapCommitMutation, - makeFetchFallback, + gsapCommitMutation = vi.fn().mockResolvedValue(undefined), + makeFetchFallback = () => vi.fn().mockResolvedValue([]), trackGsapInteractionFailure = vi.fn(), stageElementPositionOffset = vi.fn(), handleDomRotationCommit = vi.fn(), -}: Pick & - Partial< - Pick< - AwareEditingParams, - "trackGsapInteractionFailure" | "stageElementPositionOffset" | "handleDomRotationCommit" - > - >) { +}: Partial< + Pick< + AwareEditingParams, + | "gsapCommitMutation" + | "makeFetchFallback" + | "trackGsapInteractionFailure" + | "stageElementPositionOffset" + | "handleDomRotationCommit" + > +> = {}) { let groupCommit!: ( updates: DomEditGroupPathOffsetCommit[], ) => Promise; @@ -216,8 +219,6 @@ describe("useGsapAwareEditing keeps the route a gesture chose at press", () => { const save = vi.fn().mockResolvedValue(undefined); const stageElementPositionOffset = vi.fn(() => ({ save, rollback: vi.fn() })); const { pathOffsetCommit, groupCommit, root } = mountGroupHandler({ - gsapCommitMutation: vi.fn().mockResolvedValue(undefined), - makeFetchFallback: () => vi.fn().mockResolvedValue([]), stageElementPositionOffset, }); const box = { @@ -236,11 +237,7 @@ describe("useGsapAwareEditing keeps the route a gesture chose at press", () => { describe("useGsapAwareEditing refuses a group GSAP took over before writing any member", () => { it("writes no member when one CSS-route member has been folded since the press", async () => { const stageElementPositionOffset = vi.fn(() => ({ save: vi.fn(), rollback: vi.fn() })); - const { groupCommit, root } = mountGroupHandler({ - gsapCommitMutation: vi.fn().mockResolvedValue(undefined), - makeFetchFallback: () => vi.fn().mockResolvedValue([]), - stageElementPositionOffset, - }); + const { groupCommit, root } = mountGroupHandler({ stageElementPositionOffset }); const card = { element: document.createElement("div"), id: "card", @@ -268,7 +265,6 @@ describe("useGsapAwareEditing rotation routing", () => { const gsapCommitMutation = vi.fn(); const h = mountGroupHandler({ gsapCommitMutation, - makeFetchFallback: () => vi.fn().mockResolvedValue([]), handleDomRotationCommit, }); const box = { element, id: "box", selector: "#box" } as unknown as DomEditSelection; @@ -332,7 +328,6 @@ describe("useGsapAwareEditing shared-tween moves", () => { const commitMutation = vi.fn(); const { pathOffsetCommit, root } = mountGroupHandler({ gsapCommitMutation: commitMutation, - makeFetchFallback: () => vi.fn().mockResolvedValue([]), stageElementPositionOffset, }); const word = { element: gsapPositioned("span"), hfId: "w0", selector: ".w" }; @@ -351,11 +346,7 @@ describe("useGsapAwareEditing shared-tween moves", () => { }); const save = vi.fn().mockResolvedValue(undefined); const stageElementPositionOffset = vi.fn(() => ({ save, rollback: vi.fn() })); - const { groupCommit, root } = mountGroupHandler({ - gsapCommitMutation: vi.fn().mockResolvedValue(undefined), - makeFetchFallback: () => vi.fn().mockResolvedValue([]), - stageElementPositionOffset, - }); + const { groupCommit, root } = mountGroupHandler({ stageElementPositionOffset }); const word = { element: gsapPositioned("span"), hfId: "w0", selector: ".w" }; const box = { element: gsapPositioned("div"), id: "box", selector: "#box" }; const plain = { element: document.createElement("div"), id: "plain", selector: "#plain" }; @@ -406,6 +397,7 @@ describe("useGsapAwareEditing anchored resize", () => { null, expect.any(Function), expect.any(Function), + undefined, ); act(() => h.root.unmount()); }); @@ -658,7 +650,6 @@ describe("useGsapAwareEditing anchored resize", () => { ); const { groupCommit, root } = mountGroupHandler({ gsapCommitMutation: commitMutation, - makeFetchFallback: () => vi.fn().mockResolvedValue([]), }); const updates = [ { @@ -759,11 +750,7 @@ describe("useGsapAwareEditing anchored resize", () => { mocks.drag.mockImplementation(async (selection) => { throw selection.id === "a" ? failures[0] : failures[1]; }); - const { groupCommit, root } = mountGroupHandler({ - gsapCommitMutation: vi.fn().mockResolvedValue(undefined), - makeFetchFallback: () => vi.fn().mockResolvedValue([]), - trackGsapInteractionFailure, - }); + const { groupCommit, root } = mountGroupHandler({ trackGsapInteractionFailure }); const updates = [ { selection: { element: gsapPositioned("div"), id: "a", selector: "#a" }, @@ -782,6 +769,7 @@ describe("useGsapAwareEditing anchored resize", () => { updates[0]?.selection, "drag", "Move animated layer (group)", + true, ); mocks.drag.mockReset(); if (priorDragImplementation) mocks.drag.mockImplementation(priorDragImplementation); diff --git a/packages/studio/src/hooks/useGsapAwareEditing.testHelpers.tsx b/packages/studio/src/hooks/useGsapAwareEditing.testHelpers.tsx new file mode 100644 index 00000000000..d4bce836394 --- /dev/null +++ b/packages/studio/src/hooks/useGsapAwareEditing.testHelpers.tsx @@ -0,0 +1,42 @@ +import { vi } from "vitest"; +import { mountReactHarness } from "./domSelectionTestHarness"; +import { useGsapAwareEditing } from "./useGsapAwareEditing"; +import { useGsapInteractionFailureTelemetry } from "./useGsapInteractionFailureTelemetry"; + +type Params = Parameters[0]; + +/** + * Mounts useGsapAwareEditing with no-op callbacks for every param not given, and the real + * failure telemetry toasting through `showToast`. `editing()` reads the latest render. + */ +export function mountGsapAwareEditing( + params: Partial> & Pick, +) { + let editing!: ReturnType; + function Harness() { + editing = useGsapAwareEditing({ + domEditSelection: null, + selectedGsapAnimations: [], + gsapCommitMutation: vi.fn().mockResolvedValue(undefined), + previewIframeRef: { current: null }, + bumpGsapCache: vi.fn(), + makeFetchFallback: () => vi.fn().mockResolvedValue([]), + stageElementPositionOffset: vi.fn(), + handleDomBoxSizeCommit: vi.fn(), + handleDomRotationCommit: vi.fn(), + commitPositionPatchToHtml: vi.fn(), + addGsapAnimation: vi.fn(), + convertToKeyframes: vi.fn(), + setArcPath: vi.fn(), + updateArcSegment: vi.fn(), + ...params, + trackGsapInteractionFailure: useGsapInteractionFailureTelemetry( + "index.html", + params.showToast, + ), + }); + return null; + } + const root = mountReactHarness(); + return { editing: () => editing, root }; +} diff --git a/packages/studio/src/hooks/useGsapAwareEditing.ts b/packages/studio/src/hooks/useGsapAwareEditing.ts index 824b882aebc..e86722c2fe1 100644 --- a/packages/studio/src/hooks/useGsapAwareEditing.ts +++ b/packages/studio/src/hooks/useGsapAwareEditing.ts @@ -49,6 +49,7 @@ export interface UseGsapAwareEditingParams { domEditSelection: DomEditSelection | null; selectedGsapAnimations: GsapAnimation[]; gsapCommitMutation: CommitMutation | null; + activeCompPath?: string | null; previewIframeRef: React.RefObject; showToast: (message: string, tone?: "error" | "info") => void; bumpGsapCache: () => void; @@ -61,6 +62,7 @@ export interface UseGsapAwareEditingParams { selection: DomEditSelection | null, mutationType: string, label: string, + toast?: boolean, ) => void; // DOM fallbacks (from useDomEditCommits) stageElementPositionOffset: ( @@ -117,6 +119,7 @@ export function useGsapAwareEditing({ domEditSelection, selectedGsapAnimations, gsapCommitMutation, + activeCompPath, previewIframeRef, showToast, bumpGsapCache, @@ -190,6 +193,7 @@ export function useGsapAwareEditing({ const handleGsapAwareGroupPathOffsetCommit = useGsapAwareGroupMove({ gsapCommitMutation, + activeCompPath, previewIframeRef, makeFetchFallback, trackGsapInteractionFailure, @@ -285,6 +289,7 @@ export function useGsapAwareEditing({ previewIframeRef.current, commitMutation, makeFetchFallback(selection), + offset, ); assertGsapEditPersisted(outcome); // Saved before the buffered GSAP writes, so their reload stays the gesture's last render. diff --git a/packages/studio/src/hooks/useGsapAwareGroupMove.ts b/packages/studio/src/hooks/useGsapAwareGroupMove.ts index 7b2154ffd56..a7f115c1e20 100644 --- a/packages/studio/src/hooks/useGsapAwareGroupMove.ts +++ b/packages/studio/src/hooks/useGsapAwareGroupMove.ts @@ -9,24 +9,14 @@ import { gsapWritesPosition } from "./gsapRuntimeKeyframes"; import { refuseGsapTakeover } from "./elementOffsetStager"; import { tryGsapDragIntercept } from "./gsapRuntimeBridge"; import { assertGsapEditPersisted } from "./gsapEditOutcome"; +import { firstPreflightFailure } from "./gsapGroupPreflight"; // A distinct key keeps consecutive group drags in separate undo entries. let groupDragCommitCounter = 0; -function firstPreflightFailure( - results: PromiseSettledResult[], - updates: DomEditGroupPathOffsetCommit[], -): { error: unknown; selection: DomEditSelection } | null { - for (const [index, result] of results.entries()) { - if (result.status !== "rejected") continue; - const selection = updates[index]?.selection; - if (selection) return { error: result.reason, selection }; - } - return null; -} - export function useGsapAwareGroupMove({ gsapCommitMutation, + activeCompPath, previewIframeRef, makeFetchFallback, trackGsapInteractionFailure, @@ -35,6 +25,7 @@ export function useGsapAwareGroupMove({ }: Pick< UseGsapAwareEditingParams, | "gsapCommitMutation" + | "activeCompPath" | "previewIframeRef" | "makeFetchFallback" | "trackGsapInteractionFailure" @@ -44,10 +35,12 @@ export function useGsapAwareGroupMove({ const handleGsapAwareGroupPathOffsetCommit = useCallback( async ( updates: DomEditGroupPathOffsetCommit[], + options: { refusalToast?: boolean } = {}, ): Promise => { const writes = observeGsapGesture(gsapCommitMutation); const writer = writes.commit; if (!writer) return { ok: true, changed: false }; + const toastRefusal = options.refusalToast !== false; // One coalesce key across slow writes keeps the group drag in one undo entry. const coalesceKey = `group-drag:${++groupDragCommitCounter}`; // Hold the render until every member is saved, or unwritten members snap back. @@ -87,16 +80,16 @@ export function useGsapAwareGroupMove({ // mutation, so a blocked member never leaves earlier siblings partially moved. Preflights // write nothing and share one in-flight parse per file, so they run together. const preflightResults = await Promise.allSettled( - updates.map(async ({ selection, plainTranslate }) => { + updates.map(async ({ selection, next, plainTranslate }) => { if (plainTranslate ?? !gsapWritesPosition(selection.element)) { - refuseGsapTakeover(selection.element, showToast); + refuseGsapTakeover(selection.element, toastRefusal ? showToast : () => {}); return void offsetMembers.set(selection, true); } const animations = await makeFetchFallback(selection, { failOnFetchError: true })(); preflightAnimations.set(selection, animations); const outcome = await tryGsapDragIntercept( selection, - { x: 0, y: 0 }, + next, animations, previewIframeRef.current, coalescedCommit, @@ -107,13 +100,19 @@ export function useGsapAwareGroupMove({ assertGsapEditPersisted(outcome); }), ); - const preflightFailure = firstPreflightFailure(preflightResults, updates); + const preflightFailure = firstPreflightFailure( + preflightResults, + updates, + offsetMembers, + activeCompPath, + ); if (preflightFailure) { trackGsapInteractionFailure( preflightFailure.error, preflightFailure.selection, "drag", "Move animated layer (group)", + toastRefusal, ); throw preflightFailure.error; } @@ -167,6 +166,7 @@ export function useGsapAwareGroupMove({ }, [ gsapCommitMutation, + activeCompPath, previewIframeRef, makeFetchFallback, trackGsapInteractionFailure, diff --git a/packages/studio/src/hooks/useGsapInteractionFailureTelemetry.ts b/packages/studio/src/hooks/useGsapInteractionFailureTelemetry.ts index 6a1bebdc83f..b2342d622a5 100644 --- a/packages/studio/src/hooks/useGsapInteractionFailureTelemetry.ts +++ b/packages/studio/src/hooks/useGsapInteractionFailureTelemetry.ts @@ -4,8 +4,8 @@ import { trackStudioEditBlocked, trackStudioSaveFailure } from "../utils/studioS import { isGsapEditBlockedError } from "./gsapEditOutcome"; import { wasAlreadyToasted } from "./domEditPersistFailure"; -function failureToast(error: unknown): string | null { - if (wasAlreadyToasted(error)) return null; +function failureToast(error: unknown, toast: boolean): string | null { + if (!toast || wasAlreadyToasted(error)) return null; return isGsapEditBlockedError(error) ? error.message : "Failed to save animated edit."; } @@ -14,7 +14,13 @@ export function useGsapInteractionFailureTelemetry( showToast: (message: string, tone?: "error" | "info") => void, ) { return useCallback( - (error: unknown, selection: DomEditSelection | null, mutationType: string, label: string) => { + ( + error: unknown, + selection: DomEditSelection | null, + mutationType: string, + label: string, + toast?: boolean, + ) => { const report = isGsapEditBlockedError(error) ? trackStudioEditBlocked : trackStudioSaveFailure; @@ -28,7 +34,7 @@ export function useGsapInteractionFailureTelemetry( targetSelector: selection?.selector, targetSourceFile: selection?.sourceFile, }); - const message = failureToast(error); + const message = failureToast(error, toast !== false); if (message) showToast(message, "error"); }, [activeCompPath, showToast], diff --git a/packages/studio/src/hooks/useGsapScriptCommits.test.tsx b/packages/studio/src/hooks/useGsapScriptCommits.test.tsx index 3207a25cd01..caba304cfa2 100644 --- a/packages/studio/src/hooks/useGsapScriptCommits.test.tsx +++ b/packages/studio/src/hooks/useGsapScriptCommits.test.tsx @@ -698,7 +698,9 @@ describe("runCommit — instantPatch wiring", () => { await deps.api.commitMutation(selection, { x: 10 }, { label: "drag", softReload: true }); }); - expect(fetch).toHaveBeenCalledWith(expect.stringContaining("/files/compositions%2Fsub.html")); + expect(fetch).toHaveBeenCalledWith(expect.stringContaining("/files/compositions%2Fsub.html"), { + credentials: "omit", + }); expect(applySoftReload).toHaveBeenCalledWith( expect.anything(), NESTED_SCRIPT, diff --git a/packages/studio/src/hooks/useGsapScriptCommits.ts b/packages/studio/src/hooks/useGsapScriptCommits.ts index eebfb668541..10fc5e2622d 100644 --- a/packages/studio/src/hooks/useGsapScriptCommits.ts +++ b/packages/studio/src/hooks/useGsapScriptCommits.ts @@ -28,12 +28,13 @@ import { formatGsapMutationRejectionToast, readJsonResponseBody, } from "./gsapScriptCommitHelpers"; -import type { - CommitMutation, - CommitMutationCall, - CommitMutationOptions, - GsapScriptCommitsParams, - MutationResult, +import { + gsapWriteFile, + type CommitMutation, + type CommitMutationCall, + type CommitMutationOptions, + type GsapScriptCommitsParams, + type MutationResult, } from "./gsapScriptCommitTypes"; import { useGsapAnimationOps } from "./useGsapAnimationOps"; import { useGsapArcPathOps } from "./useGsapArcPathOps"; @@ -44,13 +45,14 @@ import { useSafeGsapCommitMutation, } from "./useSafeGsapCommitMutation"; import { studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; async function mutateGsapScript( projectId: string, sourceFile: string, mutation: Record, ): Promise { - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-mutations/${encodeURIComponent(sourceFile)}`, { method: "POST", @@ -69,7 +71,7 @@ async function mutateGsapScriptBatch( sourceFile: string, mutations: Record[], ): Promise { - const res = await fetch( + const res = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/gsap-mutations-batch/${encodeURIComponent(sourceFile)}`, { method: "POST", @@ -442,14 +444,14 @@ export function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIfra }; const commit: CommitMutation = trackedStudioEdit((selection, mutation, options) => { if (!activeProjectId) return Promise.resolve(); - const file = selection.sourceFile || activeCompPath || "index.html"; + const file = gsapWriteFile(selection, activeCompPath); return serializeCommit(file, options.serializeKey, () => runCommit(activeProjectId, activeCompPath, file, selection, mutation, options), ); }) as CommitMutation; commit.batch = trackedStudioEdit((calls: CommitMutationCall[], options: CommitMutationOptions) => { if (!activeProjectId) return Promise.resolve(); - const file = calls[0]?.selection.sourceFile || activeCompPath || "index.html"; + const file = calls[0] ? gsapWriteFile(calls[0].selection, activeCompPath) : "index.html"; return serializeCommit(file, options.serializeKey, () => runBatchCommit(activeProjectId, activeCompPath, file, calls, options), ); diff --git a/packages/studio/src/hooks/useLintModal.ts b/packages/studio/src/hooks/useLintModal.ts index b4466b9e090..10d3672914e 100644 --- a/packages/studio/src/hooks/useLintModal.ts +++ b/packages/studio/src/hooks/useLintModal.ts @@ -3,6 +3,7 @@ import { useState, useCallback, useEffect, useRef, useMemo } from "react"; import type { LintFinding } from "../components/LintModal"; import { usePlayerStore } from "../player"; import { isPreviewBooted, whenPreviewBooted } from "../player/store/playerStore"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface RawFinding { severity?: string; @@ -25,7 +26,7 @@ function parseFinding(f: RawFinding): LintFinding & { elementId?: string; file?: } async function fetchLintFindings(projectId: string) { - const res = await fetch(buildProjectApiPath(projectId, `/lint`)); + const res = await studioApiFetch(buildProjectApiPath(projectId, `/lint`)); const data = await res.json(); return ((data.findings ?? []) as RawFinding[]).map(parseFinding); } diff --git a/packages/studio/src/hooks/usePersistentEditHistory.test.ts b/packages/studio/src/hooks/usePersistentEditHistory.test.ts index a8a618ba814..65d97f1b3bd 100644 --- a/packages/studio/src/hooks/usePersistentEditHistory.test.ts +++ b/packages/studio/src/hooks/usePersistentEditHistory.test.ts @@ -88,6 +88,234 @@ it("an edit Studio saved is undone and redone by the project's history, with the expect(file()).toBe("B"); }); +it("undoes the edit claimed since the key, not a later edit the server took in first", async () => { + const { dir, hook, file, save, readFile } = await studio(); + const atKey = hook().claims(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + writeFileSync(join(dir, "card.html"), "Y"); + const later = hook().recordEdit({ + label: "Added Card", + files: { "card.html": { before: "", after: "Y" } }, + }); + const afterLater = async (_paths: readonly string[], task: () => Promise) => { + await later; + return task(); + }; + + const undone = await act(() => + hook().undo({ readFile, serialize: afterLater, claimedAfter: atKey }), + ); + expect(undone).toMatchObject({ ok: true, label: "Undid: Moved Title" }); + expect(file()).toBe("A"); + expect(readFileSync(join(dir, "card.html"), "utf8")).toBe("Y"); +}); + +it("a second undo pressed while the same edit saves undoes the edit before it", async () => { + const { hook, file, save, readFile } = await studio(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => expect(hook().undoLabel).toBe("Moved Title")); + const atKey = hook().claims(); + save("C"); + await act(() => + hook().recordEdit({ + label: "Moved Card", + files: { "index.html": { before: "B", after: "C" } }, + }), + ); + + let queue: Promise = Promise.resolve(); + const serialize = (_paths: readonly string[], task: () => Promise) => { + const run = queue.then(task); + queue = run.catch(() => undefined); + return run; + }; + const press = () => hook().undo({ readFile, claimedAfter: atKey, serialize }); + + const [first, second] = await act(() => Promise.all([press(), press()])); + + expect([first, second]).toMatchObject([ + { ok: true, label: "Undid: Moved Card" }, + { ok: true, label: "Undid: Moved Title" }, + ]); + expect(file()).toBe("A"); +}); + +it("keeps the claim when its undo fails, so the next press targets that edit again", async () => { + const { hook, save, readFile } = await studio(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => expect(hook().undoLabel).toBe("Moved Title")); + const atKey = hook().claims(); + save("C"); + await act(() => + hook().recordEdit({ + label: "Moved Card", + files: { "index.html": { before: "B", after: "C" } }, + }), + ); + const posted: string[] = []; + const fetch = globalThis.fetch; + vi.stubGlobal("fetch", (url: string, init?: RequestInit) => { + if (init?.method === "POST") posted.push(url.slice(url.lastIndexOf("/") + 1)); + return fetch(url, init); + }); + + save("edited elsewhere"); + const failed = await act(() => hook().undo({ readFile, claimedAfter: atKey })); + save("C"); + const retried = await act(() => hook().undo({ readFile, claimedAfter: atKey })); + + expect(failed.ok).toBe(false); + expect(retried).toMatchObject({ ok: true, label: "Undid: Moved Card" }); + expect(posted.filter((p) => p === "undo" || p === "step")).toEqual(["undo", "undo"]); +}); + +it("does not undo again an edit another press already undid", async () => { + const { hook, file, save, readFile } = await studio(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => expect(hook().undoLabel).toBe("Moved Title")); + const atKey = hook().claims(); + save("C"); + await act(() => + hook().recordEdit({ + label: "Moved Card", + files: { "index.html": { before: "B", after: "C" } }, + }), + ); + let calls = 0; + let queue: Promise = Promise.resolve(); + const serialize = (_paths: readonly string[], task: () => Promise) => { + calls += 1; + if (calls === 1) return Promise.reject(new Error("save failed")); + const run = queue.then(task); + queue = run.catch(() => undefined); + return run; + }; + const press = () => hook().undo({ readFile, claimedAfter: atKey, serialize }); + + const [first, second] = await act(() => Promise.allSettled([press(), press()])); + const third = await act(() => press()); + + expect(first.status).toBe("rejected"); + expect(second).toMatchObject({ + status: "fulfilled", + value: { ok: true, label: "Undid: Moved Card" }, + }); + expect(third).toMatchObject({ ok: true, label: "Undid: Moved Title" }); + expect(file()).toBe("A"); +}); + +it("does not undo again an edit a later press undid first", async () => { + const { hook, file, save, readFile } = await studio(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => expect(hook().undoLabel).toBe("Moved Title")); + const atKey = hook().claims(); + save("C"); + await act(() => + hook().recordEdit({ + label: "Moved Card", + files: { "index.html": { before: "B", after: "C" } }, + }), + ); + let fail!: (error: Error) => void; + const held = (_paths: readonly string[], _task: () => Promise) => + new Promise((_resolve, reject) => { + fail = reject; + }); + const failed = hook() + .undo({ readFile, claimedAfter: atKey, serialize: held }) + .catch(() => undefined); + + const second = await act(() => hook().undo({ readFile, claimedAfter: atKey })); + fail(new Error("save failed")); + await failed; + const third = await act(() => hook().undo({ readFile, claimedAfter: atKey })); + + expect(second).toMatchObject({ ok: true, label: "Undid: Moved Card" }); + expect(third).toMatchObject({ ok: true, label: "Undid: Moved Title" }); + expect(file()).toBe("A"); +}); + +it("refuses a second press whose edit is undone once an edit was made after the press", async () => { + const { dir, hook, file, save, readFile } = await studio(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => expect(hook().undoLabel).toBe("Moved Title")); + const atKey = hook().claims(); + save("C"); + await act(() => + hook().recordEdit({ + label: "Moved Card", + files: { "index.html": { before: "B", after: "C" } }, + }), + ); + let open!: () => void; + const opened = new Promise((resolve) => { + open = resolve; + }); + let queue: Promise = Promise.resolve(); + let queued = 0; + const serialize = (_paths: readonly string[], task: () => Promise) => { + queued += 1; + const wait = queued === 2 ? opened : Promise.resolve(); + const run = queue.then(() => wait).then(task); + queue = run.catch(() => undefined); + return run; + }; + const press = () => hook().undo({ readFile, claimedAfter: atKey, serialize }); + const presses = Promise.all([press(), press()]); + await vi.waitFor(() => expect(file()).toBe("B")); + writeFileSync(join(dir, "card.html"), "Y"); + await act(() => + hook().recordEdit({ + label: "Added Card", + files: { "card.html": { before: "", after: "Y" } }, + }), + ); + + open(); + const [first, second] = await act(() => presses); + + expect(first).toMatchObject({ ok: true, label: "Undid: Moved Card" }); + expect(second).toMatchObject({ ok: false, reason: "content-mismatch" }); + expect(readFileSync(join(dir, "card.html"), "utf8")).toBe("Y"); + expect(file()).toBe("B"); +}); + it("a drag's edits under one key undo as one step, even before the drag goes idle", async () => { const { hook, file, save, readFile } = await studio(); const writes: Array<[before: string, after: string]> = [ @@ -115,6 +343,32 @@ it("a drag's edits under one key undo as one step, even before the drag goes idl expect(file()).toBe("A"); }); +it("an undo before the history view shows a drag's held claim still waits on the files it wrote", async () => { + const { hook, save, readFile } = await studio(); + const server = globalThis.fetch; + vi.stubGlobal("fetch", (url: string, init?: RequestInit) => + init?.method === "POST" + ? server(url, init) + : Promise.resolve(new Response(null, { status: 503 })), + ); + save("B"); + await act(() => + hook().recordEdit({ + label: "Dragged Title", + coalesceKey: "drag", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + let waitedOn: readonly string[] = []; + const serialize = (paths: readonly string[], task: () => Promise) => { + waitedOn = paths; + return task(); + }; + + await act(() => hook().undo({ readFile, serialize })); + expect(waitedOn).toEqual(["index.html"]); +}); + it("an agent's edit made seconds before Studio's stays the agent's: Cmd+Z undoes only Studio's", async () => { const { hook, file, save, readFile } = await studio(); save("B"); @@ -159,7 +413,11 @@ it("without a history on the server an edit still saves, and there is nothing to }); /** Answers requests to `route` with `reply` instead of the engine, every other request as before; returns the undo. */ -function answer(route: "/history/step" | "/history/claim", status: number, reply: object | string) { +function answer( + route: "/history" | "/history/step" | "/history/claim", + status: number, + reply: object | string, +) { const real = globalThis.fetch; vi.stubGlobal("fetch", (url: string, init?: RequestInit) => url.endsWith(route) @@ -230,6 +488,24 @@ it("a step whose reply cannot be read says so, instead of throwing", async () => }); }); +it("an edit whose history reply cannot be read is still saved, and the reply is its own error", async () => { + const { hook, file, save } = await studio(); + const logged = vi.spyOn(console, "error").mockImplementation(() => {}); + cleanup.push(() => logged.mockRestore()); + answer("/history", 200, ""); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + await vi.waitFor(() => + expect(logged).toHaveBeenCalledWith("The history's reply was unreadable."), + ); + expect(file()).toBe("B"); +}); + it("a step that cannot reach the server says so", async () => { const { hook, readFile } = await studio(); const real = globalThis.fetch; diff --git a/packages/studio/src/hooks/usePersistentEditHistory.ts b/packages/studio/src/hooks/usePersistentEditHistory.ts index 417212cb254..3aa99e1455c 100644 --- a/packages/studio/src/hooks/usePersistentEditHistory.ts +++ b/packages/studio/src/hooks/usePersistentEditHistory.ts @@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { HistoryListItem, HistoryResult } from "@hyperframes/studio-server"; import { studioFileContentVersion, studioWriteHeaders } from "../utils/studioFileVersion"; import type { RestoreFiles } from "../utils/gsapUndoRestore"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface RecordEditInput { label: string; @@ -13,6 +14,7 @@ interface RecordEditInput { interface ApplyCallbacks { readFile: (path: string) => Promise; serialize?: (paths: readonly string[], task: () => Promise) => Promise; + claimedAfter?: number; } export interface UsePersistentEditHistoryOptions { @@ -53,6 +55,8 @@ function createOwnHistory() { const own = new Map(); let next: Record<"undo" | "redo", NextStep | null> | null = null; let changes = 0; + let claimed = { count: 0, id: "" }; + const undoneIds = new Set(); const remember = (id: string, files: OwnFiles) => { const known = own.get(id) ?? {}; for (const [path, { before, after }] of Object.entries(files)) { @@ -73,7 +77,16 @@ function createOwnHistory() { if (seen === changes) next = { undo: view.back, redo: view.forward }; }, changes: () => changes, + claimCount: () => claimed.count, + claimedAfter: (count: number) => (claimed.count > count && claimed.id ? claimed.id : null), + targetFor: (id: string | null, pressedAt: number) => + !id || !undoneIds.has(id) ? id : claimed.count > pressedAt ? false : null, + noteClaim: (id: string) => { + claimed = { count: claimed.count + 1, id }; + }, stepped: (entry: { id: string; undoes?: string }) => { + if (entry.undoes) undoneIds.add(entry.undoes); + if (undoneIds.size > OWN_ENTRIES_KEPT) undoneIds.delete(undoneIds.values().next().value!); const undone = entry.undoes ? own.get(entry.undoes) : undefined; if (!undone) return; const swapped = Object.entries(undone).map(([path, f]) => [ @@ -102,6 +115,7 @@ function createOwnHistory() { }, clear: () => { own.clear(); + undoneIds.clear(); next = null; changes += 1; }, @@ -113,12 +127,20 @@ function historyUrl(projectId: string, path = ""): string { return `/api/projects/${encodeURIComponent(projectId)}/history${path}`; } +async function cantUndo(paths: string[] | undefined): Promise { + return { ok: false, reason: "content-mismatch", paths: paths ?? [] }; +} + +function unionPaths(...lists: Array): string[] { + return [...new Set(lists.flatMap((list) => list ?? []))]; +} + async function post( url: string, body: object, headers: Record = {}, ): Promise<{ ok: true; body: unknown } | { ok: false; status: number; error: string }> { - const response = await fetch(url, { + const response = await studioApiFetch(url, { method: "POST", headers: { "Content-Type": "application/json", ...headers }, body: JSON.stringify(body), @@ -194,9 +216,12 @@ export function usePersistentEditHistory({ projectId }: UsePersistentEditHistory const refresh = useCallback(async () => { if (!projectId) return; const seen = own.changes(); - const response = await fetch(historyUrl(projectId)).catch(() => null); - const next = response?.ok ? ((await response.json()) as HistoryView) : EMPTY; + const response = await studioApiFetch(historyUrl(projectId)).catch(() => null); + const next = response?.ok + ? ((await response.json().catch(() => null)) as HistoryView | null) + : EMPTY; if (projectIdRef.current !== projectId) return; + if (!next) return console.error("The history's reply was unreadable."); setView(next); own.offered(seen, next); }, [projectId, own]); @@ -221,7 +246,10 @@ export function usePersistentEditHistory({ projectId }: UsePersistentEditHistory ...(coalesceKey && { coalesceKey, idleMs: coalesceMs ?? DEFAULT_COALESCE_MS }), }); const claimed = claimHeld(reply, label); - if (claimed) own.remember(claimed, files); + if (claimed) { + own.remember(claimed, files); + own.noteClaim(claimed); + } heldClaimRef.current = claimed && coalesceKey ? { paths, at: Date.now() } : null; await refresh(); }, @@ -231,14 +259,20 @@ export function usePersistentEditHistory({ projectId }: UsePersistentEditHistory const step = useCallback( async (direction: "undo" | "redo", callbacks: ApplyCallbacks): Promise => { if (!projectId) return { ok: false, reason: "empty" }; + const candidate = + direction === "undo" && callbacks.claimedAfter !== undefined + ? own.claimedAfter(callbacks.claimedAfter) + : null; const next = direction === "undo" ? view.back : view.forward; - const paths = [...new Set([...(next?.paths ?? []), ...(heldClaimRef.current?.paths ?? [])])]; + const stepPaths = candidate ? Object.keys(own.afterOf(candidate)) : next?.paths; + const paths = unionPaths(stepPaths, heldClaimRef.current?.paths); + const pressedAt = own.claimCount(); own.overtake(); - const run = async (): Promise => { + const attempt = async (target: string | null): Promise => { const previous = await readAll(paths, callbacks.readFile); const posted = await post( - historyUrl(projectId, "/step"), - { direction: direction === "undo" ? "back" : "forward" }, + historyUrl(projectId, target ? "/undo" : "/step"), + target ? { entryId: target } : { direction: direction === "undo" ? "back" : "forward" }, studioWriteHeaders(), ); heldClaimRef.current = null; @@ -266,6 +300,10 @@ export function usePersistentEditHistory({ projectId }: UsePersistentEditHistory ), }; }; + const run = () => { + const target = own.targetFor(candidate, pressedAt); + return target === false ? cantUndo(stepPaths) : attempt(target); + }; return callbacks.serialize ? callbacks.serialize(paths, run) : run(); }, [projectId, view, refresh, own], @@ -301,6 +339,7 @@ export function usePersistentEditHistory({ projectId }: UsePersistentEditHistory undo, redo, predict: own.predict, + claims: own.claimCount, noteOutsideChange, }; } diff --git a/packages/studio/src/hooks/usePreviewPersistence.history.test.tsx b/packages/studio/src/hooks/usePreviewPersistence.history.test.tsx index 57d839d5b88..72c85a3367d 100644 --- a/packages/studio/src/hooks/usePreviewPersistence.history.test.tsx +++ b/packages/studio/src/hooks/usePreviewPersistence.history.test.tsx @@ -79,12 +79,13 @@ describe("undo that re-runs the top-level script over an element of a nested com }; } - async function undo(fileOk: boolean) { + async function undo(fileOk: boolean, projectId: string | null = "p1") { const { iframe, nwid } = nestedPreview(); const reloadPreview = vi.fn(); const fetch = vi.fn(async () => ({ ok: fileOk, json: async () => ({ content: SUB }) })); vi.stubGlobal("fetch", fetch); - usePlayerStore.getState().beginTimelineSession("p1"); + if (projectId) usePlayerStore.getState().beginTimelineSession(projectId); + else usePlayerStore.setState({ timelineProjectId: null }); let sync: ReturnType["syncHistoryPreviewAfterApply"] | null = null; function Harness() { @@ -109,7 +110,9 @@ describe("undo that re-runs the top-level script over an element of a nested com it("restores the element from its own composition file", async () => { const { nwid, reloadPreview, fetch } = await undo(true); - expect(fetch).toHaveBeenCalledWith(expect.stringContaining("/files/compositions%2Fsub.html")); + expect(fetch).toHaveBeenCalledWith(expect.stringContaining("/files/compositions%2Fsub.html"), { + credentials: "omit", + }); expect(reloadPreview).not.toHaveBeenCalled(); expect(nwid.getAttribute("style")).toBe("left: 40px;"); }); @@ -120,4 +123,12 @@ describe("undo that re-runs the top-level script over an element of a nested com expect(reloadPreview).toHaveBeenCalledTimes(1); expect(nwid.getAttribute("style")).toBe("left: 40px; width: 337px"); }); + + it("reloads the preview in full when no project is open to read that file from", async () => { + const { nwid, reloadPreview, fetch } = await undo(true, null); + + expect(fetch).not.toHaveBeenCalled(); + expect(reloadPreview).toHaveBeenCalledTimes(1); + expect(nwid.getAttribute("style")).toBe("left: 40px; width: 337px"); + }); }); diff --git a/packages/studio/src/hooks/usePreviewPersistence.ts b/packages/studio/src/hooks/usePreviewPersistence.ts index 5908a6dd812..c749ddbc987 100644 --- a/packages/studio/src/hooks/usePreviewPersistence.ts +++ b/packages/studio/src/hooks/usePreviewPersistence.ts @@ -163,8 +163,9 @@ export function usePreviewPersistence({ }, [drainPendingDomEditSaves]); const settlePendingEdits = useCallback(async (): Promise => { - await flushStudioPendingEdits(); - await domEditSaveQueueRef.current?.waitForIdle(); + const queued = domEditSaveQueueRef.current?.waitForIdle(); + await flushStudioPendingEdits({ onlyCurrent: true }); + await queued; }, []); const resetDomEditSaveQueueBreaker = useCallback(() => { @@ -209,14 +210,15 @@ export function usePreviewPersistence({ // multi-file, sub-comp, or a permanent soft-reload failure. const projectId = usePlayerStore.getState().timelineProjectId; const nestedFiles = await settleNestedReads( - projectId - ? readUndoNestedFiles( - previewIframeRef.current, - activeCompPathRef.current, - restore.files, - (path) => readProjectFileContent(projectId, path), - ) - : null, + readUndoNestedFiles( + previewIframeRef.current, + activeCompPathRef.current, + restore.files, + (path) => + projectId + ? readProjectFileContent(projectId, path) + : Promise.reject(new Error("No project is open to read nested files from.")), + ), ); const strategy = applyUndoRestoreToPreview( previewIframeRef.current, @@ -258,7 +260,7 @@ export function usePreviewPersistence({ // ── Migrate legacy studio-motion.json ── // Projects that used the old JSON-file approach may still have a populated - // `.hyperframes/studio-motion.json`. The studio no longer reads from it, but + // studio-motion.json in the project's .hyperframes folder. The studio no longer reads it, but // the legacy render-script injection in `preview.ts` / `vite.studioMotion.ts` // could still fire alongside the new seek-reapply runtime. Empty the file so // the legacy codepath no-ops. diff --git a/packages/studio/src/hooks/useProjectFileWriter.ts b/packages/studio/src/hooks/useProjectFileWriter.ts index 93d10b8833a..50499aa4de1 100644 --- a/packages/studio/src/hooks/useProjectFileWriter.ts +++ b/packages/studio/src/hooks/useProjectFileWriter.ts @@ -6,11 +6,22 @@ import { StudioSaveNetworkError, } from "../utils/studioSaveDiagnostics"; import { studioExpectedFileVersion, studioWriteHeaders } from "../utils/studioFileVersion"; +import { studioApiFetch } from "../utils/studioApiFetch"; export interface UseProjectFileWriterOptions { projectId: string | null; } +async function fetchProjectFile(projectId: string | null, path: string, query: string) { + if (!projectId) throw new Error("No active project"); + const response = await studioApiFetch( + `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}${query}`, + ); + if (!response.ok) throw new Error(`Failed to read ${path}`); + const data = (await response.json()) as { content?: string; version?: string }; + return { content: data.content, version: data.version ?? response.headers.get("etag") }; +} + // The etag-guarded project-file read/write pair every Studio save path // shares. A host mounting hand editing outside Studio needs only this, not // the full file manager (file tree, editor tabs, uploads, font assets). @@ -30,29 +41,19 @@ export function useProjectFileWriter({ projectId }: UseProjectFileWriterOptions) const readProjectFile = useCallback( async (path: string): Promise => { - if (!projectId) throw new Error("No active project"); - const response = await fetch( - `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}`, - ); - if (!response.ok) throw new Error(`Failed to read ${path}`); - const data = (await response.json()) as { content?: string; version?: string }; - if (typeof data.content !== "string") throw new Error(`Missing file contents for ${path}`); - fileVersions.set(path, data.version ?? response.headers.get("etag")); - return data.content; + const { content, version } = await fetchProjectFile(projectId, path, ""); + if (typeof content !== "string") throw new Error(`Missing file contents for ${path}`); + fileVersions.set(path, version); + return content; }, [fileVersions, projectId], ); const readOptionalProjectFile = useCallback( async (path: string): Promise => { - if (!projectId) throw new Error("No active project"); - const response = await fetch( - `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}?optional=1`, - ); - if (!response.ok) throw new Error(`Failed to read ${path}`); - const data = (await response.json()) as { content?: string; version?: string }; - fileVersions.set(path, data.version ?? response.headers.get("etag")); - return typeof data.content === "string" ? data.content : ""; + const { content, version } = await fetchProjectFile(projectId, path, "?optional=1"); + fileVersions.set(path, version); + return typeof content === "string" ? content : ""; }, [fileVersions, projectId], ); @@ -63,7 +64,7 @@ export function useProjectFileWriter({ projectId }: UseProjectFileWriterOptions) const writeProjectId = projectId; let expectedVersion = await studioExpectedFileVersion(fileVersions, path, expectedContent); if (expectedVersion === undefined) { - const preflight = await fetch( + const preflight = await studioApiFetch( `/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`, ); if (preflight.ok) { @@ -86,7 +87,7 @@ export function useProjectFileWriter({ projectId }: UseProjectFileWriterOptions) // the retry can produce a second filesystem receipt that must be suppressed independently. let response: Response; try { - response = await fetch( + response = await studioApiFetch( `/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`, { method: "PUT", diff --git a/packages/studio/src/hooks/useRemoveBackground.ts b/packages/studio/src/hooks/useRemoveBackground.ts index c55a81e2558..dd10b84d31f 100644 --- a/packages/studio/src/hooks/useRemoveBackground.ts +++ b/packages/studio/src/hooks/useRemoveBackground.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef } from "react"; import { waitForMediaJob } from "../components/studioMediaJobs"; import type { BackgroundRemovalProgress } from "../components/editor/propertyPanelTypes"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface RemoveBackgroundOptions { createBackgroundPlate?: boolean; @@ -31,7 +32,7 @@ export function useRemoveBackground( return useCallback( // fallow-ignore-next-line complexity async (inputPath: string, options: RemoveBackgroundOptions) => { - const response = await fetch( + const response = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/media/remove-background`, { method: "POST", diff --git a/packages/studio/src/hooks/useSdkSession.ts b/packages/studio/src/hooks/useSdkSession.ts index 98efb71b901..c32cee2b291 100644 --- a/packages/studio/src/hooks/useSdkSession.ts +++ b/packages/studio/src/hooks/useSdkSession.ts @@ -6,6 +6,7 @@ import { trackStudioEvent } from "../utils/studioTelemetry"; import type { PublishSdkSession } from "../utils/sdkCutover"; import { addExternalFileReloadListener } from "./externalFileReloadBus"; import { whenPreviewBooted } from "../player/store/playerStore"; +import { studioApiFetch } from "../utils/studioApiFetch"; /** * Why an optional project-file read produced no usable content. `stage: "read"` @@ -194,7 +195,7 @@ async function readProjectFileOptional( let res: Response; const fetchStarted = performance.now(); try { - res = await fetch( + res = await studioApiFetch( `/api/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}?optional=1`, ); } catch { diff --git a/packages/studio/src/hooks/useServerConnection.ts b/packages/studio/src/hooks/useServerConnection.ts index a1928348ee6..180dee6b9eb 100644 --- a/packages/studio/src/hooks/useServerConnection.ts +++ b/packages/studio/src/hooks/useServerConnection.ts @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { buildProjectHash, parseProjectIdFromHash } from "../utils/projectRouting"; import { useMountEffect } from "./useMountEffect"; import { trackStudioEvent } from "../utils/studioTelemetry"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface ServerConnectionState { projectId: string | null; @@ -37,7 +38,7 @@ type ProjectHashVerdict = { async function resolveHashProject(id: string): Promise { try { - const res = await fetch(`/api/projects/${encodeURIComponent(id)}`); + const res = await studioApiFetch(`/api/projects/${encodeURIComponent(id)}`); if (res.ok) return { outcome: "ok", status: res.status }; return { outcome: res.status === 404 ? "missing" : "unknown", status: res.status }; } catch { @@ -72,7 +73,7 @@ function replaceProjectHash(projectId: string): void { */ async function firstProjectId(): Promise { try { - const res = await fetch("/api/projects"); + const res = await studioApiFetch("/api/projects"); const data = (await res.json()) as { projects?: Array<{ id?: string }> }; return data.projects?.[0]?.id ?? null; } catch { @@ -107,7 +108,7 @@ export function useServerConnection(): ServerConnectionState { } function tryConnect() { - fetch("/api/projects") + studioApiFetch("/api/projects") .then((r) => r.json()) .then(async (data) => { if (cancelled) return; diff --git a/packages/studio/src/hooks/useStudioSelectionPublisher.ts b/packages/studio/src/hooks/useStudioSelectionPublisher.ts index c4d2e09f2ea..b5c4deae094 100644 --- a/packages/studio/src/hooks/useStudioSelectionPublisher.ts +++ b/packages/studio/src/hooks/useStudioSelectionPublisher.ts @@ -3,6 +3,7 @@ import type { DomEditSelection } from "../components/editor/domEditing"; import { usePlayerStore } from "../player"; import { buildStudioSelectionSnapshot } from "../utils/studioSelectionSnapshot"; import { trackStudioEvent } from "../utils/studioTelemetry"; +import { studioApiFetch } from "../utils/studioApiFetch"; interface UseStudioSelectionPublisherParams { projectId: string | null; @@ -26,7 +27,7 @@ function reportSelectionPublishError(error: unknown): void { } function putSelection(projectId: string, selection: unknown, signal?: AbortSignal): Promise { - return fetch(`/api/projects/${encodeURIComponent(projectId)}/selection`, { + return studioApiFetch(`/api/projects/${encodeURIComponent(projectId)}/selection`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ selection }), diff --git a/packages/studio/src/hooks/useTimelineDeleteOps.ts b/packages/studio/src/hooks/useTimelineDeleteOps.ts index b4ff3bec82b..12c480cec42 100644 --- a/packages/studio/src/hooks/useTimelineDeleteOps.ts +++ b/packages/studio/src/hooks/useTimelineDeleteOps.ts @@ -21,6 +21,7 @@ import type { TimelineGroupCommitOptions, TimelineGroupMoveChange, } from "./useTimelineGroupEditing"; +import { studioApiFetch } from "../utils/studioApiFetch"; /** Apply already-resolved ripple changes to the surviving elements for the * optimistic store update after a delete. Pure — no IO. */ @@ -130,7 +131,7 @@ export function useTimelineDeleteOps({ } return patchTarget; }); - const removeResponse = await fetch( + const removeResponse = await studioApiFetch( buildProjectApiPath( pid, `/file-mutations/remove-elements/${encodeURIComponent(targetPath)}`, diff --git a/packages/studio/src/index.ts b/packages/studio/src/index.ts index ed1b257ae6f..126ecd89d5b 100644 --- a/packages/studio/src/index.ts +++ b/packages/studio/src/index.ts @@ -208,6 +208,8 @@ export type { DomEditZOrder } from "./components/editor/useDomEditZOrder"; export type { ZOrderAction } from "./components/editor/canvasContextMenuZOrder"; export type { DomEditCapabilities, DomEditSelection } from "./components/editor/domEditingTypes"; export { useDomStyleCommit } from "./hooks/useDomStyleCommit"; +export { ColorField } from "./components/editor/propertyPanelColor"; +export { GradientField } from "./components/editor/propertyPanelFill"; export type { UseDomStyleCommitOptions } from "./hooks/useDomStyleCommit"; export type { DomEditCommitDeclineReason, DomEditCommitOutcome } from "./hooks/domEditCommitRunner"; export { resolveDomEditSelection } from "./components/editor/domEditingLayers"; diff --git a/packages/studio/src/player/components/AudioWaveform.tsx b/packages/studio/src/player/components/AudioWaveform.tsx index 0a2ce9dee4a..37c9dfb7797 100644 --- a/packages/studio/src/player/components/AudioWaveform.tsx +++ b/packages/studio/src/player/components/AudioWaveform.tsx @@ -5,6 +5,7 @@ import { useThumbnailLease } from "../../hooks/useThumbnailLease"; import { createThumbnailKey, type ThumbnailPriority } from "../lib/thumbnailScheduler"; import { decimatePeaks, loudnessToOpacity } from "./audioWaveformPeaks"; import { ClipFadesContext, type ClipFadeShape } from "./TimelineClipFades"; +import { studioApiFetch } from "../../utils/studioApiFetch"; export interface AudioWaveformProps { audioUrl: string; @@ -124,7 +125,7 @@ async function loadWaveform( } async function fetchWaveformPeaks(url: string, signal: AbortSignal): Promise { - const response = await fetch(url, { signal }); + const response = await studioApiFetch(url, { signal }); if (!response.ok) throw new Error(`Waveform request failed (${response.status})`); const data: unknown = await response.json(); if ( @@ -140,7 +141,7 @@ async function fetchWaveformPeaks(url: string, signal: AbortSignal): Promise { - const response = await fetch(url, { signal }); + const response = await studioApiFetch(url, { signal }); if (!response.ok) throw new Error(`Audio request failed (${response.status})`); const buffer = await response.arrayBuffer(); if (signal.aborted) throw new DOMException("Aborted", "AbortError"); diff --git a/packages/studio/src/player/components/CompositionThumbnail.tsx b/packages/studio/src/player/components/CompositionThumbnail.tsx index 8f3eaf924f2..d0da0f9eb6d 100644 --- a/packages/studio/src/player/components/CompositionThumbnail.tsx +++ b/packages/studio/src/player/components/CompositionThumbnail.tsx @@ -8,6 +8,7 @@ import { } from "../lib/thumbnailScheduler"; import { TIMELINE_VIEWPORT_BUDGETS } from "../lib/timelineViewportBudgets"; import { computeThumbnailStrip, probeImageAspect } from "./thumbnailUtils"; +import { studioApiFetch } from "../../utils/studioApiFetch"; interface CompositionThumbnailProps { previewUrl: string; @@ -106,7 +107,7 @@ export function compositionThumbnailRequest( } async function loadCompositionImage(url: string, signal: AbortSignal) { - const response = await fetch(url, { signal }); + const response = await studioApiFetch(url, { signal }); if (!response.ok) throw new Error(`Composition thumbnail failed (${response.status})`); const blob = await response.blob(); if (signal.aborted) throw new DOMException("Aborted", "AbortError"); diff --git a/packages/studio/src/player/components/clipMenuNormalize.ts b/packages/studio/src/player/components/clipMenuNormalize.ts index 50b6e50dd9c..83ffc02ae81 100644 --- a/packages/studio/src/player/components/clipMenuNormalize.ts +++ b/packages/studio/src/player/components/clipMenuNormalize.ts @@ -4,6 +4,7 @@ import { resolveMediaPreviewUrl } from "./thumbnailUtils"; import type { TimelineElement } from "../store/timelineElement"; import { parseAutomation, VOLUME_TARGET } from "@hyperframes/core/audio-automation"; import type { TimelineEditOutcome } from "../../hooks/timelineEditPermission"; +import { studioApiFetch } from "../../utils/studioApiFetch"; export interface NormalizePlan { targetLufs: number; @@ -74,7 +75,7 @@ function isNormalizePlan(value: unknown): value is NormalizePlan { export async function requestNormalizePlan( projectId: string, el: TimelineElement, - fetchImpl: typeof fetch = fetch, + fetchImpl: typeof studioApiFetch = studioApiFetch, ): Promise { const origin = window.location.origin; const relative = resolvePreviewRelative( diff --git a/packages/studio/src/player/components/clipPeakMap.ts b/packages/studio/src/player/components/clipPeakMap.ts index e6eeaee6bbc..01ee899fa30 100644 --- a/packages/studio/src/player/components/clipPeakMap.ts +++ b/packages/studio/src/player/components/clipPeakMap.ts @@ -1,4 +1,5 @@ import { buildProjectApiPath } from "../../utils/projectRouting"; +import { studioApiFetch } from "../../utils/studioApiFetch"; import { resolvePreviewRelative } from "../../utils/previewRelativePath"; import type { TimelineElement } from "../store/timelineElement"; import { clipSourcePeak, isPeakMap, type ClipSourceWindow, type PeakMap } from "./clipPeakRuns"; @@ -10,7 +11,7 @@ const peakMapRequests = new Map>(); export function loadPeakMap(url: string): Promise { const pending = peakMapRequests.get(url); if (pending) return pending; - const request = fetch(url) + const request = studioApiFetch(url) .then((res) => (res.ok ? res.json() : null)) .then((body: unknown) => (isPeakMap(body) ? body : null)) .catch(() => null); diff --git a/packages/studio/src/player/hooks/useTimelinePlayer.ts b/packages/studio/src/player/hooks/useTimelinePlayer.ts index 5b5384efcc1..597d1c03ebb 100644 --- a/packages/studio/src/player/hooks/useTimelinePlayer.ts +++ b/packages/studio/src/player/hooks/useTimelinePlayer.ts @@ -36,6 +36,7 @@ import { hasTimelinePerformanceFixtureLease } from "../lib/timelinePerformanceFi import { applyCachedSourceDurations, probeMissingSourceDurations } from "../lib/mediaProbe"; import { shouldResumeForwardPlaybackAfterSeek, shouldStopAfterSeek } from "../lib/playbackSeek"; import { applyPreviewVariablesToUrl } from "../../hooks/previewVariablesStore"; +import { isStudioManualEditGestureLiveIn } from "../../components/editor/manualEditsDom"; import { createPreviewMessageHandler } from "./previewMessageRouter"; import { timelineElementsChanged } from "./timelinePlayerSync"; import { safeContentDocument } from "./timelineSyncHydration"; @@ -486,7 +487,10 @@ export function useTimelinePlayer({ // A newer edit, or anything replacing the live preview (a reload, a composition switch), wins. const isCurrent = () => gen === refreshGenRef.current && slot === previewGeneration(); const swap = sceneSwapFor(iframe); - if (!swap || isRefreshingRef.current) return reloadWholeFilm(url.toString()); + const swapWouldReplaceGestureNode = + !!iframe.contentDocument && isStudioManualEditGestureLiveIn(iframe.contentDocument); + if (!swap || isRefreshingRef.current || swapWouldReplaceGestureNode) + return reloadWholeFilm(url.toString()); swap(url.toString(), isCurrent, cancel.signal).catch((error: unknown) => { if (!isCurrent()) return; logReload("scene-swap-refused", { reason: String(error) }); diff --git a/packages/studio/src/player/lib/thumbnailScheduler.test.ts b/packages/studio/src/player/lib/thumbnailScheduler.test.ts index ee98c98d7c3..4705c70081f 100644 --- a/packages/studio/src/player/lib/thumbnailScheduler.test.ts +++ b/packages/studio/src/player/lib/thumbnailScheduler.test.ts @@ -219,6 +219,22 @@ describe("ThumbnailScheduler", () => { expect(scheduler.getDiagnostics()).toMatchObject({ queued: 0, active: 0, leases: 0 }); }); + it("frees an aborted job's slot at once, even when its loader ignores the abort", async () => { + const scheduler = new ThumbnailScheduler( + resolveTimelineViewportBudgets({ concurrentVideoDecodes: 1 }), + ); + const stuck = deferred(); + const lease = scheduler.acquire( + request("stuck", () => stuck.promise, "visible", { kind: "video" }), + vi.fn(), + ); + lease.release(); + const nextLoad = vi.fn(async () => result("next")); + scheduler.acquire(request("next", nextLoad, "visible", { kind: "video" }), vi.fn()); + await flush(); + expect(nextLoad).toHaveBeenCalledTimes(1); + }); + it("disposes a late result exactly once after its final lease releases", async () => { const scheduler = new ThumbnailScheduler(); const pending = deferred(); diff --git a/packages/studio/src/player/lib/thumbnailScheduler.ts b/packages/studio/src/player/lib/thumbnailScheduler.ts index be379ce0822..a0eb6774651 100644 --- a/packages/studio/src/player/lib/thumbnailScheduler.ts +++ b/packages/studio/src/player/lib/thumbnailScheduler.ts @@ -310,6 +310,15 @@ export class ThumbnailScheduler { entry.controller = controller; this.activeByBucket[bucket]++; this.activeByKind[entry.request.kind]++; + let slotFree = false; + const freeSlot = () => { + if (slotFree) return; + slotFree = true; + this.activeByBucket[bucket]--; + this.activeByKind[entry.request.kind]--; + this.pump(); + }; + controller.signal.addEventListener("abort", freeSlot, { once: true }); this.notify(entry); const pending = this.loadWithTimeout(entry, controller); @@ -331,8 +340,7 @@ export class ThumbnailScheduler { }) .finally(() => { if (entry.controller === controller) entry.controller = null; - this.activeByBucket[bucket]--; - this.activeByKind[entry.request.kind]--; + freeSlot(); this.pump(); }); } diff --git a/packages/studio/src/player/sceneSwap.ts b/packages/studio/src/player/sceneSwap.ts index a7320e702cf..94bfda0ba29 100644 --- a/packages/studio/src/player/sceneSwap.ts +++ b/packages/studio/src/player/sceneSwap.ts @@ -1,3 +1,4 @@ +import { studioApiFetch } from "../utils/studioApiFetch"; type SwapWindow = Window & { __hfSwapScenes?: (html: string, signal?: AbortSignal) => Promise; }; @@ -72,7 +73,7 @@ export function sceneSwapFor( ); cancel?.addEventListener("abort", () => deadline.abort(cancel.reason), { once: true }); const swapping = (async () => { - const response = await fetch(url, { signal: deadline.signal }); + const response = await studioApiFetch(url, { signal: deadline.signal }); if (!response.ok) throw new Error(`preview request failed with ${response.status}`); const html = await response.text(); if (!isCurrent()) throw new Error("superseded by a newer reload"); diff --git a/packages/studio/src/telemetry/client.ts b/packages/studio/src/telemetry/client.ts index a7068ac545f..0480de7008b 100644 --- a/packages/studio/src/telemetry/client.ts +++ b/packages/studio/src/telemetry/client.ts @@ -9,6 +9,7 @@ import { browserTelemetryAllowed } from "./policy"; import { getBrowserSystemMeta } from "./system"; import { canaryEventProperties } from "./canary"; import { recordBreadcrumb } from "./breadcrumbs"; +import { studioApiFetch } from "../utils/studioApiFetch"; // Write-only PostHog project key, safe to embed in client code. const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx"; @@ -83,7 +84,7 @@ function send(url: string, payload: string): void { // Prefer fetch with keepalive (survives page navigation). sendBeacon is a // fallback for older runtimes where fetch isn't available. try { - void fetch(url, { + void studioApiFetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: payload, diff --git a/packages/studio/src/utils/blockInstaller.ts b/packages/studio/src/utils/blockInstaller.ts index f4cf59a9249..256a8c80c8a 100644 --- a/packages/studio/src/utils/blockInstaller.ts +++ b/packages/studio/src/utils/blockInstaller.ts @@ -12,6 +12,7 @@ import { saveProjectFilesWithHistory } from "./studioFileHistory"; import { serializeStudioFileMutation } from "./studioFileMutationCoordinator"; import { extendRootDurationInSource } from "./rootDuration"; import { deriveTimelineStoreKeyForDomId } from "../player/lib/timelineElementHelpers"; +import { studioApiFetch } from "./studioApiFetch"; function getMaxZIndexFromIframe(iframe: HTMLIFrameElement | null): number { try { @@ -65,7 +66,7 @@ async function installRegistryItem({ block: RegistryItem; compositionFile: string; } | null> { - const response = await fetch(buildProjectApiPath(projectId, `/registry/install`), { + const response = await studioApiFetch(buildProjectApiPath(projectId, `/registry/install`), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ blockName }), diff --git a/packages/studio/src/utils/elementGsap.test.ts b/packages/studio/src/utils/elementGsap.test.ts new file mode 100644 index 00000000000..78f7c0a6b5d --- /dev/null +++ b/packages/studio/src/utils/elementGsap.test.ts @@ -0,0 +1,9 @@ +// @vitest-environment happy-dom +import { expect, it } from "vitest"; +import { elementTargets } from "./elementGsap"; + +it("keeps only the targets GSAP styles: not a plain object, not an XML-namespace element", () => { + const box = document.createElement("div"); + const item = document.createElementNS("urn:x", "item"); + expect(elementTargets({ targets: () => [{}, item, box, null] })).toEqual([box]); +}); diff --git a/packages/studio/src/utils/elementGsap.ts b/packages/studio/src/utils/elementGsap.ts index c4d1df58909..80e20de952d 100644 --- a/packages/studio/src/utils/elementGsap.ts +++ b/packages/studio/src/utils/elementGsap.ts @@ -43,3 +43,10 @@ export function readElementGsapNumber(element: HTMLElement, prop: string): numbe const value = Number(gsapOf(element)?.getProperty?.(element, prop)); return Number.isFinite(value) ? value : null; } + +/** The targets CSSPlugin styles: not plain objects (the runtime's filler) or XML-namespace elements. */ +export function elementTargets(tween: { targets?: () => unknown[] }): Element[] { + return (tween.targets?.() ?? []).filter((t): t is Element => + Boolean((t as HTMLElement | null)?.style && (t as Node).nodeType), + ); +} diff --git a/packages/studio/src/utils/gsapSoftReload.ts b/packages/studio/src/utils/gsapSoftReload.ts index 5c94e3931ed..405d9d764d5 100644 --- a/packages/studio/src/utils/gsapSoftReload.ts +++ b/packages/studio/src/utils/gsapSoftReload.ts @@ -209,7 +209,6 @@ export interface SoftReloadOptions { currentTimeOverride?: number; /** After-write file HTML — the primary source for the authored opacity and transform restore. */ authoredHtml?: string; - reparse?: Element[]; /** Other composition files a reset element is written in, by path; null when one could not be read. */ nestedFiles?: Map | null; } @@ -274,7 +273,7 @@ export function applySoftReload( scriptText: string, options: SoftReloadOptions = {}, ): SoftReloadResult { - const { onAsyncFailure, currentTimeOverride, authoredHtml, reparse = [] } = options; + const { onAsyncFailure, currentTimeOverride, authoredHtml } = options; if (!iframe || !scriptText) return "cannot-soft-reload"; const win = iframe.contentWindow as IframeWindow | null; @@ -347,7 +346,7 @@ export function applySoftReload( // fallow-ignore-next-line complexity const doReload = () => { const timelines = win.__timelines; - const targets = collectResetTargets(win, doc, targetKeys, reparse); + const targets = collectResetTargets(win, doc, targetKeys); // Kill ONLY the target composition's timeline(s) — leaving every other // composition's timeline (and its children on the global timeline) intact. diff --git a/packages/studio/src/utils/gsapUndoRestore.browser.test.ts b/packages/studio/src/utils/gsapUndoRestore.browser.test.ts index 09612bbedde..611f7691cc0 100644 --- a/packages/studio/src/utils/gsapUndoRestore.browser.test.ts +++ b/packages/studio/src/utils/gsapUndoRestore.browser.test.ts @@ -43,54 +43,60 @@ beforeAll(async () => { afterAll(() => browser?.close()); +// The first case opens the cold browser's first page, which overran 5 s on a loaded CI runner. it.each([ { gsap: "hold", placement: "px", rotation: 0 }, { gsap: "tween", placement: "px", rotation: 0 }, { gsap: "tween", placement: "xpercent", rotation: 30 }, -])("an undone crop leaves a $gsap $placement r$rotation layer where it was", async (spec) => { - const dir = join(mkdtempSync(join(tmpdir(), "undo-gsap-")), "case"); - writeFixture({ gesture: "crop", nesting: "root", zoom: 100, ...spec }, dir); - const restored = readFileSync(join(dir, "index.html"), "utf8"); - const previous = restored.replace( - `
- request.url().endsWith("/gsap.min.js") - ? request.respond({ body: readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8") }) - : request.continue(), - ); - await page.setContent(restored, { waitUntil: "load" }); - await page.evaluate(readFileSync(require.resolve("@hyperframes/core/runtime"), "utf8")); - await page.waitForFunction(() => "__player" in window); - await page.evaluate(undoBundle); +])( + "an undone crop leaves a $gsap $placement r$rotation layer where it was", + async (spec) => { + const dir = join(mkdtempSync(join(tmpdir(), "undo-gsap-")), "case"); + writeFixture({ gesture: "crop", nesting: "root", zoom: 100, ...spec }, dir); + const restored = readFileSync(join(dir, "index.html"), "utf8"); + const previous = restored.replace( + `
+ request.url().endsWith("/gsap.min.js") + ? request.respond({ body: readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8") }) + : request.abort("blockedbyclient"), + ); + await page.setContent(restored, { waitUntil: "load" }); + await page.evaluate(readFileSync(require.resolve("@hyperframes/core/runtime"), "utf8")); + await page.waitForFunction(() => "__player" in window); + await page.evaluate(undoBundle); - const box = () => - page.evaluate(() => { - const { left, top, width, height } = document - .getElementById("target")! - .getBoundingClientRect(); - return [left, top, width, height].map((n) => Math.round(n * 100) / 100); - }); - await page.evaluate(() => - (window as unknown as { __player: { seek(t: number): void } }).__player.seek(1), - ); - const before = await box(); - const outcome = await page.evaluate( - (files, crop) => { - document.getElementById("target")!.style.setProperty("clip-path", crop); - const undo = (window as unknown as { hfUndo: typeof import("./gsapUndoRestore") }).hfUndo; - const iframe = { contentDocument: document, contentWindow: window } as HTMLIFrameElement; - return undo.applyUndoRestoreToPreview(iframe, "index.html", files, 1, () => {}); - }, - { "index.html": { previous, restored } }, - CROP, - ); + const box = () => + page.evaluate(() => { + const { left, top, width, height } = document + .getElementById("target")! + .getBoundingClientRect(); + return [left, top, width, height].map((n) => Math.round(n * 100) / 100); + }); + await page.evaluate(() => + (window as unknown as { __player: { seek(t: number): void } }).__player.seek(1), + ); + const before = await box(); + const outcome = await page.evaluate( + (files, crop) => { + document.getElementById("target")!.style.setProperty("clip-path", crop); + const undo = (window as unknown as { hfUndo: typeof import("./gsapUndoRestore") }).hfUndo; + const iframe = { contentDocument: document, contentWindow: window } as HTMLIFrameElement; + return undo.applyUndoRestoreToPreview(iframe, "index.html", files, 1, () => {}); + }, + { "index.html": { previous, restored } }, + CROP, + ); - expect(outcome).toBe("soft"); - expect(await box()).toEqual(before); - await page.close(); -}); + expect(outcome).toBe("soft"); + expect(await box()).toEqual(before); + await page.close(); + }, + 30_000, +); diff --git a/packages/studio/src/utils/gsapUndoRestore.ts b/packages/studio/src/utils/gsapUndoRestore.ts index 04513d5d0e9..5814a59afc5 100644 --- a/packages/studio/src/utils/gsapUndoRestore.ts +++ b/packages/studio/src/utils/gsapUndoRestore.ts @@ -398,20 +398,17 @@ export function applyUndoRestoreToPreview( const active = files[activeDocPath]; const restoredScript = active ? extractGsapScriptText(active.restored) : null; const previousScript = active ? extractGsapScriptText(active.previous) : null; - const reparse = plan.scripted - ? plan.targets.map(({ live }) => live).filter((el) => "_gsap" in el) - : []; - if (reparse.length && !restoredScript) { + const reparse = plan.scripted && plan.targets.some(({ live }) => "_gsap" in live); + if (reparse && !restoredScript) { reloadPreview(); return "full"; } - if (restoredScript && (restoredScript !== previousScript || reparse.length)) { + if (restoredScript && (restoredScript !== previousScript || reparse)) { syncStaleEditMarks(doc, active); const result = applySoftReload(iframe, restoredScript, { onAsyncFailure: reloadPreview, currentTimeOverride: currentTime, authoredHtml: active.restored, - reparse, nestedFiles, }); if (result === "cannot-soft-reload") { diff --git a/packages/studio/src/utils/previewPrefetch.ts b/packages/studio/src/utils/previewPrefetch.ts index 67916c9f9e8..baec70ec961 100644 --- a/packages/studio/src/utils/previewPrefetch.ts +++ b/packages/studio/src/utils/previewPrefetch.ts @@ -1,5 +1,6 @@ import { applyPreviewVariablesToUrl } from "../hooks/previewVariablesStore"; import { buildProjectApiPath, parseProjectIdFromHash } from "./projectRouting"; +import { studioApiFetch } from "./studioApiFetch"; let prefetched: string | null = null; @@ -10,5 +11,5 @@ export function prefetchPreviewForHash(hash: string): void { prefetched = projectId; const url = new URL(buildProjectApiPath(projectId, "/preview"), window.location.origin); applyPreviewVariablesToUrl(url); - fetch(url).catch(() => undefined); + studioApiFetch(url).catch(() => undefined); } diff --git a/packages/studio/src/utils/razorSplitTransaction.ts b/packages/studio/src/utils/razorSplitTransaction.ts index c3e3a395e7e..bc139b7a2ab 100644 --- a/packages/studio/src/utils/razorSplitTransaction.ts +++ b/packages/studio/src/utils/razorSplitTransaction.ts @@ -6,6 +6,7 @@ import { serializeStudioFileMutations } from "./studioFileMutationCoordinator"; import { buildProjectApiPath } from "./projectRouting"; import { markStudioWriteToken } from "./studioFileVersion"; import { resolveElementTrack } from "./studioHelpers"; +import { studioApiFetch } from "./studioApiFetch"; type ProjectFileWriter = (path: string, content: string, expectedContent?: string) => Promise; @@ -101,7 +102,7 @@ export function buildAtomicCutIntents( } async function readFileVersion(projectId: string, path: string): Promise { - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath(projectId, `/files/${encodeURIComponent(path)}`), ); if (!response.ok) throw new Error(`Failed to read ${path} before cut (${response.status})`); @@ -124,14 +125,17 @@ async function requestAtomicCut( } const transactionToken = `cut:${crypto.randomUUID()}`; markStudioWriteToken(transactionToken); - const response = await fetch(buildProjectApiPath(projectId, "/file-mutations/split-batch"), { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-Hyperframes-Write-Token": transactionToken, + const response = await studioApiFetch( + buildProjectApiPath(projectId, "/file-mutations/split-batch"), + { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-Hyperframes-Write-Token": transactionToken, + }, + body: JSON.stringify({ files, transactionToken }), }, - body: JSON.stringify({ files, transactionToken }), - }); + ); const body = (await response.json().catch(() => null)) as | (Partial & { error?: string; outcome?: string }) | null; diff --git a/packages/studio/src/utils/softReloadTargets.ts b/packages/studio/src/utils/softReloadTargets.ts index 46bdd9c7b7f..836ba25939a 100644 --- a/packages/studio/src/utils/softReloadTargets.ts +++ b/packages/studio/src/utils/softReloadTargets.ts @@ -48,10 +48,8 @@ export function collectResetTargets( win: { __timelines?: Record }, doc: Document, targetKeys: string[], - reparse: Element[] = [], ): Map> { - // Elements the caller needs GSAP to parse again, with nothing tweened yet. - const targets = new Map>(reparse.map((el) => [el, new Set()])); + const targets = new Map>(); const timelines = (win.__timelines ?? {}) as Record; const others = new Set( Object.entries(timelines).flatMap(([key, tl]) => (targetKeys.includes(key) ? [] : [tl])), diff --git a/packages/studio/src/utils/studioApiFetch.test.ts b/packages/studio/src/utils/studioApiFetch.test.ts new file mode 100644 index 00000000000..e952f908865 --- /dev/null +++ b/packages/studio/src/utils/studioApiFetch.test.ts @@ -0,0 +1,75 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +async function loadWithEnv(env: Record) { + vi.resetModules(); + for (const [key, value] of Object.entries(env)) vi.stubEnv(key, value); + return import("./studioApiFetch"); +} + +describe("studioApiFetch", () => { + afterEach(() => { + vi.unstubAllGlobals(); + vi.unstubAllEnvs(); + vi.resetModules(); + }); + + it("sends Studio's requests without credentials, keeping the caller's options", async () => { + const fetchMock = vi.fn(async () => new Response("ok")); + vi.stubGlobal("fetch", fetchMock); + const { studioApiFetch } = await loadWithEnv({}); + const signal = new AbortController().signal; + + await studioApiFetch("/api/projects/demo/history/step", { method: "POST", signal }); + + expect(fetchMock).toHaveBeenCalledWith("/api/projects/demo/history/step", { + method: "POST", + signal, + credentials: "omit", + }); + }); + + it.each([ + ["the CLI or Studio dev server", "http://localhost:5190/"], + ["Desktop's own server", "http://127.0.0.1:43117/"], + ["IPv6 loopback", "http://[::1]:8080/"], + ])("leaves cookies out when Studio is served from %s", async (_, page) => { + const fetchMock = vi.fn(async () => new Response("ok")); + vi.stubGlobal("fetch", fetchMock); + vi.stubGlobal("location", new URL(page)); + const { studioApiFetch } = await loadWithEnv({}); + + await studioApiFetch("/api/projects/demo/files/index.html"); + + expect(fetchMock).toHaveBeenCalledWith("/api/projects/demo/files/index.html", { + credentials: "omit", + }); + }); + + it("keeps same-origin cookies off loopback, where a proxy or tunnel may authenticate with them", async () => { + const fetchMock = vi.fn(async () => new Response("ok")); + vi.stubGlobal("fetch", fetchMock); + vi.stubGlobal("location", new URL("https://studio.example.com/editor")); + const { studioApiFetch } = await loadWithEnv({}); + + await studioApiFetch("/api/projects/demo/files/index.html"); + + expect(fetchMock).toHaveBeenCalledWith("/api/projects/demo/files/index.html", { + credentials: "same-origin", + }); + }); + + it("sends same-origin credentials on loopback for a host that opted out", async () => { + vi.stubGlobal("location", new URL("http://localhost:5190/")); + const fetchMock = vi.fn(async () => new Response("ok")); + vi.stubGlobal("fetch", fetchMock); + const { studioApiFetch } = await loadWithEnv({ + VITE_STUDIO_API_SAME_ORIGIN_CREDENTIALS: "true", + }); + + await studioApiFetch("/api/projects/demo/files/index.html"); + + expect(fetchMock).toHaveBeenCalledWith("/api/projects/demo/files/index.html", { + credentials: "same-origin", + }); + }); +}); diff --git a/packages/studio/src/utils/studioApiFetch.ts b/packages/studio/src/utils/studioApiFetch.ts new file mode 100644 index 00000000000..88990ada224 --- /dev/null +++ b/packages/studio/src/utils/studioApiFetch.ts @@ -0,0 +1,13 @@ +import { STUDIO_API_SAME_ORIGIN_CREDENTIALS } from "../components/editor/manualEditingAvailability"; + +const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]); + +function studioApiCredentials(): RequestCredentials { + if (STUDIO_API_SAME_ORIGIN_CREDENTIALS) return "same-origin"; + const host = globalThis.location?.hostname; + return !host || LOOPBACK_HOSTS.has(host) ? "omit" : "same-origin"; +} + +export function studioApiFetch(input: RequestInfo | URL, init?: RequestInit): Promise { + return globalThis.fetch(input, { ...init, credentials: studioApiCredentials() }); +} diff --git a/packages/studio/src/utils/studioFileHistory.ts b/packages/studio/src/utils/studioFileHistory.ts index bdbb58d23ab..4ecf43cf571 100644 --- a/packages/studio/src/utils/studioFileHistory.ts +++ b/packages/studio/src/utils/studioFileHistory.ts @@ -2,6 +2,7 @@ import { buildProjectApiPath } from "./projectRouting"; import type { MutableRefObject } from "react"; import { serializeStudioFileMutations } from "./studioFileMutationCoordinator"; import { createStudioSaveHttpError } from "./studioSaveDiagnostics"; +import { studioApiFetch } from "./studioApiFetch"; export interface RecordEditInput { label: string; @@ -49,7 +50,9 @@ interface SaveProjectFilesWithHistoryInput { } export async function readProjectFileContent(pid: string, path: string): Promise { - const response = await fetch(buildProjectApiPath(pid, `/files/${encodeURIComponent(path)}`)); + const response = await studioApiFetch( + buildProjectApiPath(pid, `/files/${encodeURIComponent(path)}`), + ); if (!response.ok) { throw await createStudioSaveHttpError(response, `Failed to read ${path}`); } diff --git a/packages/studio/src/utils/studioHelpers.ts b/packages/studio/src/utils/studioHelpers.ts index adfb3bd77b2..bc644d03396 100644 --- a/packages/studio/src/utils/studioHelpers.ts +++ b/packages/studio/src/utils/studioHelpers.ts @@ -4,6 +4,7 @@ import type { TimelineElement } from "../player/store/playerStore"; import type { DomEditSelection } from "../components/editor/domEditing"; import type { TimelineAssetKind } from "./timelineAssetDrop"; import { roundToCenti } from "./rounding"; +import { studioApiFetch } from "./studioApiFetch"; export interface EditingFile { path: string; @@ -91,6 +92,11 @@ export function isImageBackgroundValue(value: string): boolean { return /^url\(/i.test(value.trim()); } +export function cssPropertyName(property: string): string { + if (property.startsWith("--")) return property; + return property.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^ms-/, "-ms-"); +} + export function isManualGeometryStyleProperty(property: string): boolean { return property === "left" || property === "top" || property === "width" || property === "height"; } @@ -401,7 +407,7 @@ export async function resolveAssetHasAudio( assetPath: string, ): Promise { try { - const response = await fetch(mediaMetadataUrl(projectId, assetPath)); + const response = await studioApiFetch(mediaMetadataUrl(projectId, assetPath)); if (!response.ok) return null; const data: unknown = await response.json(); const metadata = isPlainRecord(data) ? data.metadata : undefined; diff --git a/packages/studio/src/utils/studioPendingEdits.test.ts b/packages/studio/src/utils/studioPendingEdits.test.ts index d518294fb8e..7712828ac1f 100644 --- a/packages/studio/src/utils/studioPendingEdits.test.ts +++ b/packages/studio/src/utils/studioPendingEdits.test.ts @@ -5,7 +5,7 @@ import { beginStudioPendingEdit, flushStudioPendingEdits, hasStudioPendingEdits, - revertNewestStudioPendingEdit, + paintBackNewestStudioPendingEdit, trackStudioPendingEdit, trackedStudioEdit, } from "./studioPendingEdits"; @@ -227,12 +227,12 @@ describe("a pending edit undo can paint back", () => { shown.length = 0; const first = edit("first"); const second = edit("second"); - const again = revertNewestStudioPendingEdit(); + const again = paintBackNewestStudioPendingEdit(); expect(shown).toEqual(["second undone"]); expect(second.reverted()).toBe(true); expect(first.reverted()).toBe(false); - expect(revertNewestStudioPendingEdit()).toBeNull(); - again!(); + expect(paintBackNewestStudioPendingEdit()).toBeNull(); + again!.showAgain(); expect(shown).toEqual(["second undone", "second again"]); first.settle(); second.settle(); @@ -243,7 +243,7 @@ describe("a pending edit undo can paint back", () => { const move = edit("move"); let saved!: () => void; trackStudioPendingEdit(new Promise((resolve) => (saved = resolve))); - expect(revertNewestStudioPendingEdit()).toBeNull(); + expect(paintBackNewestStudioPendingEdit()).toBeNull(); expect(shown).toEqual([]); saved(); move.settle(); @@ -258,7 +258,7 @@ describe("a pending edit undo can paint back", () => { trackStudioPendingEdit(new Promise((resolve) => (saved = resolve))), ); move.settle(save); - revertNewestStudioPendingEdit(); + paintBackNewestStudioPendingEdit(); expect(shown).toEqual(["move undone"]); saved(); await expect(flushStudioPendingEdits()).resolves.toEqual({ status: "clean" }); @@ -295,3 +295,20 @@ describe("the package's public revert", () => { } }); }); + +describe("a drain of only the current edits", () => { + it("ends once the edits pending at its start land, without waiting for one started after", async () => { + let landFirst!: () => void; + let landLater!: () => void; + trackStudioPendingEdit(new Promise((resolve) => (landFirst = resolve))); + let drained = false; + const drain = flushStudioPendingEdits({ onlyCurrent: true }).then(() => (drained = true)); + await Promise.resolve(); + trackStudioPendingEdit(new Promise((resolve) => (landLater = resolve))); + landFirst(); + await drain; + expect(drained).toBe(true); + expect(hasStudioPendingEdits()).toBe(true); + landLater(); + }); +}); diff --git a/packages/studio/src/utils/studioPendingEdits.ts b/packages/studio/src/utils/studioPendingEdits.ts index 69369805d1f..890040f8bb9 100644 --- a/packages/studio/src/utils/studioPendingEdits.ts +++ b/packages/studio/src/utils/studioPendingEdits.ts @@ -11,7 +11,13 @@ export type StudioPendingEditsDrainResult = StudioSaveDrainResult; export type StudioEditRevert = () => () => void; -const pendingEdits = new Map, { revert: StudioEditRevert | null }>(); +interface PendingEdit { + revert: StudioEditRevert | null; + landed: () => Promise; +} + +const pendingEdits = new Map, PendingEdit>(); +const NOT_SAVED = () => Promise.resolve(false); let adopting = false; function waitForPostBlurEffects(): Promise { @@ -67,7 +73,7 @@ export function trackStudioPendingEdit( if (!result) return undefined; const promise = Promise.resolve(result); if (adopting) return promise; - pendingEdits.set(promise, { revert: null }); + pendingEdits.set(promise, { revert: null, landed: NOT_SAVED }); promise.then( () => pendingEdits.delete(promise), () => pendingEdits.delete(promise), @@ -90,6 +96,8 @@ export function beginStudioPendingEdit(revert: StudioEditRevert | null) { const promise = trackStudioPendingEdit(new Promise((resolve) => (settle = resolve)))!; const entry = pendingEdits.get(promise)!; entry.revert = revert; + let landed = Promise.resolve(false); + entry.landed = () => landed; return { settle, reverted: () => entry.revert === null && revert !== null, @@ -97,7 +105,12 @@ export function beginStudioPendingEdit(revert: StudioEditRevert | null) { adopt(start: () => T): T { adopting = true; try { - return start(); + const committed = start(); + landed = Promise.resolve(committed).then( + () => true, + () => false, + ); + return committed; } catch (error) { settle(); throw error; @@ -108,15 +121,24 @@ export function beginStudioPendingEdit(revert: StudioEditRevert | null) { }; } -export function revertNewestStudioPendingEdit(): (() => void) | null { +export function paintBackNewestStudioPendingEdit(): { + showAgain: () => void; + landed: () => Promise; +} | null { const newest = [...pendingEdits.values()].at(-1); const revert = newest?.revert; if (!newest || !revert) return null; newest.revert = null; - return revert(); + return { showAgain: revert(), landed: newest.landed }; +} + +export function revertNewestStudioPendingEdit(): (() => void) | null { + return paintBackNewestStudioPendingEdit()?.showAgain ?? null; } -export async function flushStudioPendingEdits(): Promise { +export async function flushStudioPendingEdits({ + onlyCurrent = false, +} = {}): Promise { const active = focusedField(); if (active) { active.blur(); @@ -128,10 +150,12 @@ export async function flushStudioPendingEdits(): Promise(STUDIO_FLUSH_PENDING_EDITS_EVENT, { detail }), ); + const current = onlyCurrent ? new Set(pendingEdits.keys()) : null; + const waiting = () => [...pendingEdits.keys()].filter((edit) => !current || current.has(edit)); let conflict: StudioFileConflictError | undefined; let firstFailure: PromiseRejectedResult | undefined; - while (detail.promises.length > 0 || pendingEdits.size > 0) { - const promises = [...detail.promises, ...pendingEdits.keys()]; + while (detail.promises.length > 0 || waiting().length > 0) { + const promises = [...detail.promises, ...waiting()]; detail.promises = []; const batchFailures = inspectDrainFailures(await Promise.allSettled(promises)); conflict ??= batchFailures.conflict; diff --git a/packages/studio/src/utils/studioTelemetry.ts b/packages/studio/src/utils/studioTelemetry.ts index aa59b0184cb..e9baf91e93a 100644 --- a/packages/studio/src/utils/studioTelemetry.ts +++ b/packages/studio/src/utils/studioTelemetry.ts @@ -4,6 +4,7 @@ import { browserTelemetryAllowed } from "../telemetry/policy"; import { canaryEventProperties } from "../telemetry/canary"; import { agentRuntimeProperty } from "../telemetry/agentRuntime"; import { tabIdProperty } from "../telemetry/tabId"; +import { studioApiFetch } from "./studioApiFetch"; // PostHog public ingest key — write-only, safe to ship in the client bundle const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx"; @@ -149,7 +150,7 @@ async function flushEvents(): Promise { const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS); try { - await fetch(`${POSTHOG_HOST}/batch/`, { + await studioApiFetch(`${POSTHOG_HOST}/batch/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: POSTHOG_API_KEY, batch }), diff --git a/packages/studio/src/utils/timelineCompositionInsert.ts b/packages/studio/src/utils/timelineCompositionInsert.ts index de54fb21bee..b29e26c82a7 100644 --- a/packages/studio/src/utils/timelineCompositionInsert.ts +++ b/packages/studio/src/utils/timelineCompositionInsert.ts @@ -4,6 +4,7 @@ import type { RecordEditInput } from "./studioFileHistory"; import { buildProjectApiPath } from "./projectRouting"; import { studioWriteHeaders } from "./studioFileVersion"; import { deriveTimelineStoreKeyForDomId } from "../player/lib/timelineElementHelpers"; +import { studioApiFetch } from "./studioApiFetch"; interface TimelineCompositionInsertionResult { path: string; @@ -20,7 +21,7 @@ async function insertTimelineComposition(input: { start: number; track: number; }): Promise { - const current = await fetch( + const current = await studioApiFetch( buildProjectApiPath(input.projectId, `/files/${encodeURIComponent(input.targetPath)}`), ); if (!current.ok) { @@ -29,7 +30,7 @@ async function insertTimelineComposition(input: { const snapshot = (await current.json()) as { version?: string }; if (typeof snapshot.version !== "string") throw new Error("Missing composition file version"); - const response = await fetch( + const response = await studioApiFetch( buildProjectApiPath( input.projectId, `/file-mutations/insert-composition/${encodeURIComponent(input.targetPath)}`, diff --git a/packages/studio/src/webmcp/StudioAgentTools.tsx b/packages/studio/src/webmcp/StudioAgentTools.tsx index 808e332e715..3eeed1ca585 100644 --- a/packages/studio/src/webmcp/StudioAgentTools.tsx +++ b/packages/studio/src/webmcp/StudioAgentTools.tsx @@ -12,6 +12,7 @@ import { captureStudioBoxSize, restoreStudioBoxSize, } from "../components/editor/manualEdits"; +import { studioApiFetch } from "../utils/studioApiFetch"; export function readLiveSelectionBox( doc: Document | null | undefined, @@ -141,7 +142,7 @@ export function StudioAgentTools() { // fetches the URL itself. probeFrame: async (url) => { try { - const response = await fetch(url, { method: "HEAD" }); + const response = await studioApiFetch(url, { method: "HEAD" }); return { ok: response.ok, status: response.status }; } catch { return { ok: false, status: 0 }; diff --git a/packages/studio/tests/e2e/edit-accuracy/baseline.json b/packages/studio/tests/e2e/edit-accuracy/baseline.json index c3ed663e322..1c21d11a7de 100644 --- a/packages/studio/tests/e2e/edit-accuracy/baseline.json +++ b/packages/studio/tests/e2e/edit-accuracy/baseline.json @@ -1,1570 +1,1570 @@ { - "studio": "e049c15", - "build": "980bd7b890ae", - "bench": "e049c15", + "studio": "10cb471", + "build": "da9b9a112089", + "bench": "10cb471", "grid": "full (CI)", "cases": { - "crop-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17}, - "crop-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.03,"drop":0.09,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.6}, - "crop-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.36,"frameP95":17.41}, - "crop-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":18.8}, - "crop-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.1,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":17.41}, - "crop-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.44,"frameP95":17.21}, - "crop-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.06,"reload":0.06,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":17.81}, - "crop-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.02,"drop":0.09,"reload":0.09,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.3}, - "crop-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.02,"drop":0.03,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":18.41}, - "crop-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.02,"drop":0.04,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.03,"frameP95":19.31}, - "crop-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.02,"drop":0.13,"reload":0.12,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.37,"frameP95":17.6}, - "crop-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.02,"drop":0.11,"reload":0.12,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17.71}, - "crop-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.29,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":18.1}, - "crop-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.29,"drop":0.08,"reload":0.08,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.1}, - "crop-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.29,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":18.4}, - "crop-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.29,"drop":0.04,"reload":0.04,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":17.11}, - "crop-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.29,"drop":0.14,"reload":0.11,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":20.7}, - "crop-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.29,"drop":0.08,"reload":0.07,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":17.6}, - "crop-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.27,"drop":0.06,"reload":0.06,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.21}, - "crop-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.27,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.17,"frameP95":17.2}, - "crop-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.27,"drop":0.02,"reload":0.04,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":18.5}, - "crop-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.27,"drop":0.02,"reload":0.05,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.6}, - "crop-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.27,"drop":0.14,"reload":0.11,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":18.81}, - "crop-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.27,"drop":0.14,"reload":0.11,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.2}, - "crop-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":17}, - "crop-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17}, - "crop-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":17.91}, - "crop-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.1}, - "crop-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.91}, - "crop-hold-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.45,"frameP95":17.11}, - "crop-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.04,"frameP95":18.21}, - "crop-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":17.11}, - "crop-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17.31}, - "crop-hold-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.6}, - "crop-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17}, - "crop-hold-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.41}, - "crop-hold-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.1}, - "crop-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.12,"frameP95":17.2}, - "crop-hold-pct-r0-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.1}, - "crop-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.54,"frameP95":17}, - "crop-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.34,"frameP95":19}, - "crop-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.1}, - "crop-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":18}, - "crop-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":16.9}, - "crop-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.14,"reload":0.11,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":17.71}, - "crop-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.22,"frameP95":16.91}, - "crop-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":18.61}, - "crop-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.12,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":18.21}, - "crop-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.68,"frameP95":18.4}, - "crop-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.9}, - "crop-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.97,"frameP95":17.1}, - "crop-hold-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.11}, - "crop-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":17.91}, - "crop-hold-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.48,"frameP95":17.11}, - "crop-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":19.11}, - "crop-hold-px-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "crop-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.14,"reload":0.11,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":17}, - "crop-hold-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17}, - "crop-hold-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":17.1}, - "crop-hold-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.12,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.31}, - "crop-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.7,"frameP95":17.8}, - "crop-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":17}, - "crop-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":17.4}, - "crop-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.37,"frameP95":17.8}, - "crop-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":19.31}, - "crop-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.4}, - "crop-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":18.5}, - "crop-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":16.91}, - "crop-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":17.41}, - "crop-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.55,"frameP95":17.11}, - "crop-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.21}, - "crop-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.21}, - "crop-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.1}, - "crop-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.3,"frameP95":17}, - "crop-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.13,"frameP95":17.1}, - "crop-idle-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17}, - "crop-idle-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":17.5}, - "crop-idle-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17.1}, - "crop-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":18}, - "crop-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.21}, - "crop-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":17.1}, - "crop-idle-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":17.21}, - "crop-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.04,"frameP95":17.3}, - "crop-idle-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":17.41}, - "crop-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.85,"frameP95":18.1}, - "crop-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.6}, - "crop-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.21}, - "crop-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":17.5}, - "crop-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.2}, - "crop-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.27,"frameP95":17.1}, - "crop-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":19.21}, - "crop-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.21}, - "crop-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.1}, - "crop-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":16.91}, - "crop-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":16.91}, - "crop-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.4}, - "crop-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.86,"frameP95":17.1}, - "crop-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":16.9}, - "crop-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.7}, - "crop-idle-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.16,"frameP95":20.21}, - "crop-idle-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":18.4}, - "crop-idle-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":17.5}, - "crop-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":19.1}, - "crop-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.21}, - "crop-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.14,"reload":0.11,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17}, - "crop-idle-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":16.91}, - "crop-idle-px-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.31}, - "crop-idle-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"drop":0.14,"reload":0.14,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.1}, - "crop-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.2}, - "crop-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.5}, - "crop-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.98,"frameP95":19.31}, - "crop-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.03,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":18.91}, - "crop-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.03,"drop":0.16,"reload":0.13,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":18.5}, - "crop-keys-px-r0-nested-z50-on": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, - "crop-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.09,"keys":true,"css":true,"renderKey":0.03,"drop":0.09,"reload":0.09,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":18.31}, - "crop-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.07,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":18.2}, - "crop-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.21}, - "crop-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.03,"drop":0.03,"reload":0.03,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":18.6}, - "crop-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.16,"keys":true,"css":true,"renderKey":0.03,"drop":0.18,"reload":0.15,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.32,"frameP95":17.31}, - "crop-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.03,"drop":0.12,"reload":0.12,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.7}, - "crop-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.25,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":18}, - "crop-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.25,"drop":0.06,"reload":0.06,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":17.5}, - "crop-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.25,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":18}, - "crop-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.25,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":17.1}, - "crop-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.25,"drop":0.14,"reload":0.15,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":18.5}, - "crop-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.25,"drop":0.18,"reload":0.11,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.41,"frameP95":17.31}, - "crop-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.24,"drop":0.11,"reload":0.11,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.2}, - "crop-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.24,"drop":0.06,"reload":0.06,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.6}, - "crop-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.24,"drop":0.04,"reload":0.05,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":19.6}, - "crop-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.24,"drop":0.03,"reload":0.03,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.31}, - "crop-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.17,"keys":true,"css":true,"renderKey":0.24,"drop":0.19,"reload":0.18,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":17.1}, - "crop-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.24,"drop":0.16,"reload":0.13,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.86,"frameP95":17.91}, - "crop-none-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":18.4}, - "crop-none-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":17.5}, - "crop-none-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.4,"frameP95":18.81}, - "crop-none-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":1,"workMax":4.26,"frameP95":17.4}, - "crop-none-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.2,"frameP95":18.5}, - "crop-none-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":19.4}, - "crop-none-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":18}, - "crop-none-center-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "crop-none-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":18.31}, - "crop-none-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":17.5}, - "crop-none-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.1}, - "crop-none-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17.5}, - "crop-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":19.3}, - "crop-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":18.7}, - "crop-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":18.8}, - "crop-none-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":18.4}, - "crop-none-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.29,"frameP95":17.4}, - "crop-none-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":18.21}, - "crop-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":17.5}, - "crop-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18.8}, - "crop-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.3}, - "crop-none-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":17.9}, - "crop-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.5}, - "crop-none-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":18.6}, - "crop-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.17,"frameP95":18.8}, - "crop-none-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.9,"frameP95":18}, - "crop-none-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18}, - "crop-none-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.09,"frameP95":17.6}, - "crop-none-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":18.2}, - "crop-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":19.4}, - "crop-none-px-r30-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.3,"undo":true,"dropped":1,"controlDropped":0,"workMax":4.7,"frameP95":19.5}, - "crop-none-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":18.9}, - "crop-none-px-r30-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.14,"reload":0.11,"render":0.3,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.48,"frameP95":18.5}, - "crop-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":17.9}, - "crop-none-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":17.3}, - "crop-none-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"drop":0.14,"reload":0.14,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.55,"frameP95":18.2}, - "crop-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.09,"reload":0.09,"render":0.99,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":18.91}, - "crop-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.01,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":18.41}, - "crop-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":18.91}, - "crop-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.01,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.3}, - "crop-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.02,"drop":0.12,"reload":0.15,"render":0.99,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.5}, - "crop-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.01,"drop":0.11,"reload":0.11,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":18.5}, - "crop-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.02,"drop":0.08,"reload":0.08,"render":0.99,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18.6}, - "crop-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.2}, - "crop-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.41}, - "crop-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.1}, - "crop-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.02,"drop":0.12,"reload":0.13,"render":0.99,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":19}, - "crop-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.11,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.8}, - "crop-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.25,"drop":0.11,"reload":0.11,"render":0.78,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.2}, - "crop-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.23,"drop":0.06,"reload":0.06,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.1}, - "crop-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.24,"drop":0.05,"reload":0.06,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.41}, - "crop-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.23,"drop":0.04,"reload":0.03,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":17.1}, - "crop-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.24,"drop":0.16,"reload":0.16,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":17.81}, - "crop-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.23,"drop":0.06,"reload":0.1,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":18.21}, - "crop-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.22,"drop":0.08,"reload":0.08,"render":0.78,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.61}, - "crop-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.21,"drop":0.09,"reload":0.09,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":17.1}, - "crop-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.04,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.23,"frameP95":18.6}, - "crop-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.5}, - "crop-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.22,"drop":0.16,"reload":0.13,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":17.41}, - "crop-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.21,"drop":0.06,"reload":0.09,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":16.91}, - "crop-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":18.61}, - "crop-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":18}, - "crop-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.83,"frameP95":17.91}, - "crop-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.21}, - "crop-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.03,"drop":0.19,"reload":0.15,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":17.6}, - "crop-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.1}, - "crop-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":19.6}, - "crop-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.41}, - "crop-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.2}, - "crop-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":17.31}, - "crop-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.16,"keys":true,"css":true,"renderKey":0.03,"drop":0.24,"reload":0.18,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.3,"frameP95":17.6}, - "crop-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.03,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":16.91}, - "crop-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.2,"drop":0.07,"reload":0.07,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.11}, - "crop-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.2,"drop":0.06,"reload":0.06,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.1}, - "crop-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.2,"drop":0.06,"reload":0.07,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.81}, - "crop-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.2,"drop":0.05,"reload":0.05,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17.2}, - "crop-size-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.2,"drop":0.17,"reload":0.17,"render":0.18,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.71,"frameP95":20.41}, - "crop-size-px-r30-nested-z50-on": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.2,"drop":0.17,"reload":0.1,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.81}, - "crop-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.22,"drop":0.08,"reload":0.08,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.12,"frameP95":18.81}, - "crop-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.22,"drop":0.09,"reload":0.09,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":19.7}, - "crop-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.06,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.71}, - "crop-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.06,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":18.91}, - "crop-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.18,"keys":true,"css":true,"renderKey":0.22,"drop":0.23,"reload":0.21,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":17.5}, - "crop-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.22,"drop":0.17,"reload":0.15,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.4,"frameP95":16.91}, - "crop-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":18}, - "crop-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":18.2}, - "crop-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":19}, - "crop-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":18.31}, - "crop-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.1,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.39,"frameP95":17.31}, - "crop-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.94,"frameP95":17.7}, - "crop-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.06,"reload":0.06,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":18.7}, - "crop-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.04,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":18.5}, - "crop-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.03,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.39,"frameP95":17.31}, - "crop-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17.41}, - "crop-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"keys":true,"css":true,"renderKey":0.21,"drop":0.17,"reload":0.12,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.41}, - "crop-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.21,"drop":0.15,"reload":0.1,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":18.1}, - "crop-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.06,"reload":0.06,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.32,"frameP95":18.31}, - "crop-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.2}, - "crop-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.04,"reload":0.05,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.09,"frameP95":17.5}, - "crop-spin-px-r30-nested-z200-on": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "crop-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.1,"reload":0.11,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":18.2}, - "crop-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.11}, - "crop-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.07,"reload":0.07,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.41}, - "crop-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.04,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":18.41}, - "crop-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.05,"reload":0.07,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":18.6}, - "crop-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.03,"frameP95":17.2}, - "crop-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"keys":true,"css":true,"renderKey":0.21,"drop":0.14,"reload":0.11,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.1}, - "crop-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.21,"drop":0.15,"reload":0.1,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.2}, - "crop-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.03,"frameP95":17.5}, - "crop-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":19.3}, - "crop-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.3}, - "crop-tween-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.66,"frameP95":17.11}, - "crop-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":17.41}, - "crop-tween-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":17.1}, - "crop-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":19.7}, - "crop-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.25,"frameP95":16.91}, - "crop-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":18.4}, - "crop-tween-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":18.91}, - "crop-tween-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":16.91}, - "crop-tween-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":17.21}, - "crop-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.3}, - "crop-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.1}, - "crop-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.1}, - "crop-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.63,"frameP95":17}, - "crop-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.91}, - "crop-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.34,"frameP95":17.21}, - "crop-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":19.1}, - "crop-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.11}, - "crop-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":17.1}, - "crop-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.05,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":17.11}, - "crop-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.52,"frameP95":17}, - "crop-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":18}, - "crop-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.09,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.12,"frameP95":17.3}, - "crop-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":17.6}, - "crop-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.07,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":17.11}, - "crop-tween-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17.11}, - "crop-tween-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0,"reload":0.02,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":17.41}, - "crop-tween-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.97,"frameP95":17.61}, - "crop-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.44,"frameP95":18.1}, - "crop-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.3}, - "crop-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":17}, - "crop-tween-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.55,"frameP95":17.41}, - "crop-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":17.5}, - "crop-tween-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17.21}, - "crop-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":18.81}, - "crop-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":17.5}, - "crop-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.11}, - "crop-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":17.8}, - "crop-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.21}, - "crop-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.11}, - "crop-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":17.9}, - "crop-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.17,"frameP95":16.91}, - "crop-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":17}, - "crop-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.61}, - "crop-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":17.41}, - "crop-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.98,"frameP95":17.9}, - "move-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":18.6}, - "move-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.82,"frameP95":17.41}, - "move-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.37,"frameP95":17.61}, - "move-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.97,"frameP95":17.7}, - "move-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":17.6}, - "move-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":18.7}, - "move-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.41}, - "move-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.34,"frameP95":17.5}, - "move-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.31}, - "move-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":17.5}, - "move-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":17.7}, - "move-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18.2}, - "move-fromto-px-r30-nested-z100-mid": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.2}, - "move-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":18.61}, - "move-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":17.91}, - "move-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.83,"frameP95":18}, - "move-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.48,"frameP95":20.1}, - "move-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.2,"frameP95":18.3}, - "move-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":false,"css":true,"renderKey":0.03,"drop":135.76,"reload":135.76,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.57,"frameP95":18}, - "move-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":65.89,"keys":false,"css":true,"renderKey":0.07,"drop":138.68,"reload":138.68,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.66,"frameP95":17.61}, - "move-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":false,"css":true,"renderKey":0.03,"drop":135.74,"reload":135.74,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":19.1}, - "move-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":65.89,"keys":false,"css":true,"renderKey":0.07,"drop":138.71,"reload":138.7,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":19.11}, - "move-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":false,"css":true,"renderKey":0.03,"drop":135.84,"reload":135.73,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.21}, - "move-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":false,"teleportPx":65.89,"keys":false,"css":true,"renderKey":0.07,"drop":138.7,"reload":138.67,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.34,"frameP95":17.91}, - "move-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.31}, - "move-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":17.8}, - "move-hold-center-r0-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.1}, - "move-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":17.9}, - "move-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":17.81}, - "move-hold-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.2}, - "move-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.34,"frameP95":19.21}, - "move-hold-center-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.3}, - "move-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":17.41}, - "move-hold-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.6}, - "move-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.81}, - "move-hold-center-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.26,"frameP95":18.91}, - "move-hold-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.47,"frameP95":17.5}, - "move-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":18.7}, - "move-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.55,"frameP95":17}, - "move-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.19,"frameP95":17.3}, - "move-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":17.71}, - "move-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":17.31}, - "move-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.04,"frameP95":18.91}, - "move-hold-pct-r30-nested-z200": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, - "move-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.12,"frameP95":18.11}, - "move-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":17.8}, - "move-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":18.41}, - "move-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":18.1}, - "move-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":19.41}, - "move-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.97,"frameP95":18.21}, - "move-hold-px-r0-nested-z50": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.21}, - "move-hold-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.49,"frameP95":17.41}, - "move-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.4,"frameP95":19.21}, - "move-hold-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":17.2}, - "move-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.98,"frameP95":18.61}, - "move-hold-px-r30-nested-z200": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "move-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.09,"frameP95":18.41}, - "move-hold-px-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, - "move-hold-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":17.71}, - "move-hold-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":17.41}, - "move-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.31}, - "move-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.4}, - "move-hold-xpercent-r0-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "move-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":18.21}, - "move-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":17.91}, - "move-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.83,"frameP95":17.5}, - "move-hold-xpercent-r30-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.13,"frameP95":19.1}, - "move-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.69,"frameP95":18.61}, - "move-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.61}, - "move-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":17.11}, - "move-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17.81}, - "move-hold-xpercent-r30-root-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.23,"frameP95":19.3}, - "move-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":17.5}, - "move-idle-center-r0-nested-z200": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.59,"frameP95":19.21}, - "move-idle-center-r0-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "move-idle-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.75,"frameP95":18.6}, - "move-idle-center-r0-root-z200": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.05,"frameP95":17.71}, - "move-idle-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.35,"frameP95":17.8}, - "move-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.35,"frameP95":20.21}, - "move-idle-center-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, - "move-idle-center-r30-nested-z50": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.47,"frameP95":17.41}, - "move-idle-center-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.11}, - "move-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":18}, - "move-idle-center-r30-root-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":18.4}, - "move-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.8}, - "move-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18}, - "move-idle-pct-r0-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "move-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":17.6}, - "move-idle-pct-r0-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.82,"frameP95":19.9}, - "move-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.86,"frameP95":17}, - "move-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.86,"frameP95":19.4}, - "move-idle-pct-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.3}, - "move-idle-pct-r30-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.33,"frameP95":17.7}, - "move-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.2}, - "move-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.5}, - "move-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":18.6}, - "move-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.7}, - "move-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.49,"frameP95":18.1}, - "move-idle-px-r0-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.4}, - "move-idle-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":18.6}, - "move-idle-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":17.5}, - "move-idle-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.47,"frameP95":17.5}, - "move-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":19.4}, - "move-idle-px-r30-nested-z200": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.71}, - "move-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.14,"frameP95":18.5}, - "move-idle-px-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "move-idle-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.3}, - "move-idle-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.13,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.22,"frameP95":18.81}, - "move-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":18.1}, - "move-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":18.91}, - "move-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":17.91}, - "move-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.09,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.79,"frameP95":17.5}, - "move-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":17.3}, - "move-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.1,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.54,"frameP95":17.4}, - "move-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":18}, - "move-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.55,"frameP95":18.3}, - "move-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.63,"frameP95":17.31}, - "move-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.08,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":17.41}, - "move-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.67,"frameP95":18.6}, - "move-keys-px-r0-root-z50-on": {"smooth":true,"tracking":108.17,"pressJump":0,"teleport":false,"teleportPx":100.01,"keys":false,"css":true,"renderKey":0.02,"drop":237.73,"reload":237.73,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":18.41}, - "move-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":18.1}, - "move-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.06,"drop":0.07,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":17.2}, - "move-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":1,"workMax":7.1,"frameP95":18.7}, - "move-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.06,"drop":0.08,"reload":0.08,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":17.81}, - "move-keys-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0.1,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.19,"frameP95":18.5}, - "move-keys-px-r30-nested-z50-on": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.06,"drop":0.19,"reload":0.14,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.12,"frameP95":18.2}, - "move-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":false,"teleportPx":86.17,"keys":false,"css":true,"renderKey":0.03,"drop":159.91,"reload":159.91,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.12,"frameP95":18.2}, - "move-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":90.56,"keys":true,"css":true,"renderKey":0.03,"drop":168.54,"reload":168.49,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":17.91}, - "move-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":86.15,"keys":false,"css":true,"renderKey":0.03,"drop":159.95,"reload":159.96,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.41}, - "move-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":90.55,"keys":true,"css":true,"renderKey":0.03,"drop":168.57,"reload":168.5,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.09,"frameP95":18.31}, - "move-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":false,"teleportPx":86.16,"keys":false,"css":true,"renderKey":0.03,"drop":159.91,"reload":159.91,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":18.11}, - "move-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":90.56,"keys":true,"css":true,"renderKey":0.03,"drop":168.65,"reload":168.59,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.25,"frameP95":17.91}, - "move-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.61}, - "move-none-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":18.91}, - "move-none-center-r0-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "move-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":18.81}, - "move-none-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.34,"frameP95":19.1}, - "move-none-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":19.5}, - "move-none-center-r30-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.79,"frameP95":18.71}, - "move-none-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.44,"frameP95":18.6}, - "move-none-center-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":18.9}, - "move-none-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18}, - "move-none-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":19.8}, - "move-none-center-r30-root-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.71,"frameP95":19.1}, - "move-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":18.5}, - "move-none-pct-r0-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":5.59,"frameP95":19.9}, - "move-none-pct-r0-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.6}, - "move-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":17.9}, - "move-none-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":17.7}, - "move-none-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.5}, - "move-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":18.31}, - "move-none-pct-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.9}, - "move-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.97,"frameP95":19}, - "move-none-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":18.1}, - "move-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":17.5}, - "move-none-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.49,"frameP95":18.21}, - "move-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":17.31}, - "move-none-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":18.71}, - "move-none-px-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.2,"frameP95":17.3}, - "move-none-px-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.21,"frameP95":23.1}, - "move-none-px-r0-root-z200": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.03,"frameP95":19}, - "move-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":19.2}, - "move-none-px-r30-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.08,"frameP95":20.8}, - "move-none-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":18.4}, - "move-none-px-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":18.7}, - "move-none-px-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.8}, - "move-none-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.71}, - "move-none-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.13,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.12,"frameP95":21}, - "move-scale-px-r0-nested-z100-mid": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.19,"frameP95":18.9}, - "move-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":17.7}, - "move-scale-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.65,"frameP95":19.1}, - "move-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":18.41}, - "move-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.6}, - "move-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.39,"frameP95":18.11}, - "move-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":17.81}, - "move-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":17.31}, - "move-scale-px-r0-root-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":11.12,"frameP95":17.71}, - "move-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.68,"frameP95":17.3}, - "move-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.2,"frameP95":17.41}, - "move-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":17.31}, - "move-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.66,"frameP95":18.5}, - "move-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.59,"frameP95":17.3}, - "move-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.04,"frameP95":18.2}, - "move-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.59,"frameP95":19.6}, - "move-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.73,"frameP95":17.91}, - "move-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.36,"frameP95":18.5}, - "move-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":18.31}, - "move-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":17.5}, - "move-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":20.31}, - "move-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.06,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":18.41}, - "move-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":17.6}, - "move-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.71,"frameP95":18.9}, - "move-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":17.5}, - "move-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":17.21}, - "move-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.38,"frameP95":19.31}, - "move-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.24,"frameP95":17.91}, - "move-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":18.1}, - "move-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.97,"frameP95":19.81}, - "move-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":17.1}, - "move-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":17}, - "move-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18.11}, - "move-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.14,"frameP95":19.1}, - "move-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":17}, - "move-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.86,"frameP95":17.2}, - "move-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":17.71}, - "move-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":18.31}, - "move-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":18.41}, - "move-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.16,"frameP95":18.5}, - "move-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18.61}, - "move-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.11,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.39,"frameP95":18.2}, - "move-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":18.1}, - "move-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":17.1}, - "move-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.78,"frameP95":18}, - "move-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.8,"frameP95":18.21}, - "move-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":18.8}, - "move-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18.7}, - "move-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":19}, - "move-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.94,"frameP95":17.3}, - "move-spin-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.09,"render":0.23,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.17,"frameP95":17.7}, - "move-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":17.91}, - "move-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":18.41}, - "move-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.7}, - "move-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":18.1}, - "move-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":18}, - "move-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.71}, - "move-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":19.5}, - "move-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":18.6}, - "move-spin-px-r0-root-z50-on": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.13,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.9,"frameP95":18.3}, - "move-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":18.41}, - "move-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":17.61}, - "move-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":18.6}, - "move-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":17.6}, - "move-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":19.6}, - "move-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.7}, - "move-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":18.2}, - "move-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.31}, - "move-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":19.3}, - "move-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":18.7}, - "move-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.53,"frameP95":17.7}, - "move-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.13,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":17.71}, - "move-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":18}, - "move-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.7,"frameP95":17.9}, - "move-tween-center-r0-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, - "move-tween-center-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":17.8}, - "move-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.15,"frameP95":17.91}, - "move-tween-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.38,"frameP95":17}, - "move-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.72,"frameP95":19.81}, - "move-tween-center-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.2}, - "move-tween-center-r30-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.99,"frameP95":18.91}, - "move-tween-center-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, - "move-tween-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":17.3}, - "move-tween-center-r30-root-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.61,"frameP95":18.91}, - "move-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18.91}, - "move-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":18.3}, - "move-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":17.21}, - "move-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.41}, - "move-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.02,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.26,"frameP95":18.3}, - "move-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":17.4}, - "move-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.21,"frameP95":19.8}, - "move-tween-pct-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18}, - "move-tween-pct-r30-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.61,"frameP95":17.31}, - "move-tween-pct-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.91}, - "move-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.01,"frameP95":18}, - "move-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8,"frameP95":18}, - "move-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":17.71}, - "move-tween-px-r0-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.08,"frameP95":18.6}, - "move-tween-px-r0-nested-z50": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "move-tween-px-r0-root-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.84,"frameP95":18.21}, - "move-tween-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.69,"frameP95":18.41}, - "move-tween-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.42,"frameP95":17.31}, - "move-tween-px-r30-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.62,"frameP95":20.1}, - "move-tween-px-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.91}, - "move-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":18.5}, - "move-tween-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.48,"frameP95":17.5}, - "move-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7,"frameP95":17.5}, - "move-tween-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.68,"frameP95":18.4}, - "move-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.5}, - "move-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":17.5}, - "move-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17}, - "move-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.99,"frameP95":18.1}, - "move-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.47,"frameP95":17.9}, - "move-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.48,"frameP95":17.1}, - "move-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.44,"frameP95":19.4}, - "move-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":19.1}, - "move-tween-xpercent-r30-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.08,"frameP95":18.1}, - "move-tween-xpercent-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18}, - "move-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":18}, - "move-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":19}, - "nudge-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17.5}, - "nudge-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":16.81}, - "nudge-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":17.2}, - "nudge-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.73,"frameP95":17.41}, - "nudge-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.41}, - "nudge-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":17.5}, - "nudge-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.5}, - "nudge-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.05,"frameP95":18.31}, - "nudge-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.01,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.41}, - "nudge-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.02,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.5,"frameP95":17.41}, - "nudge-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.91,"frameP95":17.2}, - "nudge-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.41}, - "nudge-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.27,"frameP95":17.2}, - "nudge-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.41}, - "nudge-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.22,"frameP95":17.2}, - "nudge-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0.02,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.31,"frameP95":17.11}, - "nudge-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.12,"frameP95":17.31}, - "nudge-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.75,"frameP95":17.3}, - "nudge-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":87.92,"reload":87.92,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.2,"frameP95":22.1}, - "nudge-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":89.86,"reload":89.86,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":18}, - "nudge-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":87.91,"reload":87.89,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":19.61}, - "nudge-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":89.86,"reload":89.85,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.4,"frameP95":18.11}, - "nudge-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":88.01,"reload":87.92,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.13,"frameP95":17.5}, - "nudge-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":89.85,"reload":89.85,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.5}, - "nudge-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":16.91}, - "nudge-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.11}, - "nudge-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.2}, - "nudge-hold-center-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.91,"frameP95":17.41}, - "nudge-hold-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.01,"frameP95":17.3}, - "nudge-hold-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.4}, - "nudge-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":17.1}, - "nudge-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.41}, - "nudge-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":17.5}, - "nudge-hold-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.31}, - "nudge-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17}, - "nudge-hold-center-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.31}, - "nudge-hold-pct-r0-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.38,"frameP95":20.31}, - "nudge-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.94,"frameP95":17.3}, - "nudge-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":17.21}, - "nudge-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.3}, - "nudge-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.85,"frameP95":17.41}, - "nudge-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17}, - "nudge-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.79,"frameP95":17.1}, - "nudge-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.1}, - "nudge-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.6,"frameP95":18.1}, - "nudge-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.21}, - "nudge-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":17}, - "nudge-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.07,"frameP95":17.3}, - "nudge-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":17.4}, - "nudge-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.26,"frameP95":17.5}, - "nudge-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.5}, - "nudge-hold-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.15,"frameP95":17.3}, - "nudge-hold-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17}, - "nudge-hold-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.31}, - "nudge-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":16.81}, - "nudge-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17.5}, - "nudge-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":17}, - "nudge-hold-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.41}, - "nudge-hold-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.11}, - "nudge-hold-px-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.8,"frameP95":17.1}, - "nudge-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":17.41}, - "nudge-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.9,"frameP95":17.2}, - "nudge-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.3}, - "nudge-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.2}, - "nudge-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.5,"frameP95":17}, - "nudge-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.5}, - "nudge-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17.41}, - "nudge-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.1}, - "nudge-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":17}, - "nudge-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.4}, - "nudge-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.1}, - "nudge-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.89,"frameP95":17.21}, - "nudge-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.12,"frameP95":17.1}, - "nudge-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.41}, - "nudge-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":16.9}, - "nudge-idle-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.31,"frameP95":17.21}, - "nudge-idle-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.73,"frameP95":17.21}, - "nudge-idle-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.91,"frameP95":17.1}, - "nudge-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":17.21}, - "nudge-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":17.3}, - "nudge-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.35,"frameP95":17.31}, - "nudge-idle-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":17.5}, - "nudge-idle-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":17}, - "nudge-idle-center-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":20.7}, - "nudge-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":16.81}, - "nudge-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.88,"frameP95":17.21}, - "nudge-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17}, - "nudge-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.81,"frameP95":17.21}, - "nudge-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":17.31}, - "nudge-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17}, - "nudge-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":17.41}, - "nudge-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.5}, - "nudge-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.7}, - "nudge-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":17.5}, - "nudge-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":18.5}, - "nudge-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":17.41}, - "nudge-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.03,"frameP95":16.91}, - "nudge-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.88,"frameP95":17.5}, - "nudge-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.2,"frameP95":18.71}, - "nudge-idle-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.3}, - "nudge-idle-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":17.81}, - "nudge-idle-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.31}, - "nudge-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.87,"frameP95":17.21}, - "nudge-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.41}, - "nudge-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":17.41}, - "nudge-idle-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.3}, - "nudge-idle-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":17}, - "nudge-idle-px-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.35,"frameP95":19.4}, - "nudge-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":20.6}, - "nudge-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17.4}, - "nudge-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":17.1}, - "nudge-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0.03,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.05,"frameP95":17.21}, - "nudge-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.41}, - "nudge-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.74,"frameP95":17.2}, - "nudge-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.41}, - "nudge-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.62,"frameP95":17.2}, - "nudge-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.01,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.21}, - "nudge-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.41}, - "nudge-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.45,"frameP95":17.11}, - "nudge-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.4,"frameP95":20.11}, - "nudge-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":17.41}, - "nudge-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.31}, - "nudge-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":18.81}, - "nudge-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0.03,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.69,"frameP95":17.5}, - "nudge-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":17.31}, - "nudge-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.8,"frameP95":17.2}, - "nudge-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.29,"reload":108.29,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":20.3}, - "nudge-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.19,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.53,"frameP95":17.5}, - "nudge-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.28,"reload":108.29,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":17.31}, - "nudge-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.17,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":18.5}, - "nudge-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.26,"reload":108.28,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.4}, - "nudge-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.15,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":17.11}, - "nudge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17.1}, - "nudge-none-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":17.3}, - "nudge-none-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":17.31}, - "nudge-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":19.2}, - "nudge-none-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.8}, - "nudge-none-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.14,"frameP95":17.5}, - "nudge-none-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":18}, - "nudge-none-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.4}, - "nudge-none-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.3}, - "nudge-none-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.5}, - "nudge-none-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":18.8}, - "nudge-none-center-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":18.1}, - "nudge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":19.91}, - "nudge-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":17.6}, - "nudge-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":17.2}, - "nudge-none-pct-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.54,"frameP95":17.3}, - "nudge-none-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":18.21}, - "nudge-none-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":18.6}, - "nudge-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.4}, - "nudge-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.8}, - "nudge-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.2,"frameP95":17.4}, - "nudge-none-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":19.6}, - "nudge-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":16.9}, - "nudge-none-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.6}, - "nudge-none-px-r0-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.66,"frameP95":31.8}, - "nudge-none-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.12,"frameP95":17.2}, - "nudge-none-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.3}, - "nudge-none-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":19.7}, - "nudge-none-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.54,"frameP95":17.71}, - "nudge-none-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":21.8}, - "nudge-none-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":18.21}, - "nudge-none-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.8}, - "nudge-none-px-r30-nested-z50": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.71,"frameP95":96.6}, - "nudge-none-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":18.7}, - "nudge-none-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.85,"frameP95":17.3}, - "nudge-none-px-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":18.4}, - "nudge-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.1}, - "nudge-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.6}, - "nudge-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.5}, - "nudge-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.44,"frameP95":17.2}, - "nudge-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.41}, - "nudge-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.45,"frameP95":17.1}, - "nudge-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":17.4}, - "nudge-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.97,"frameP95":17.31}, - "nudge-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17}, - "nudge-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.5}, - "nudge-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.41}, - "nudge-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17.2}, - "nudge-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":17.2}, - "nudge-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.5}, - "nudge-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":19.31}, - "nudge-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.83,"frameP95":17.2}, - "nudge-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":17.4}, - "nudge-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.43,"frameP95":17.21}, - "nudge-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":17.21}, - "nudge-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.2}, - "nudge-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":20.91}, - "nudge-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.06,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":17.3}, - "nudge-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.5}, - "nudge-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":17.6}, - "nudge-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":17.1}, - "nudge-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":21.41}, - "nudge-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.5}, - "nudge-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.15,"frameP95":17}, - "nudge-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.5}, - "nudge-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.79,"frameP95":17.3}, - "nudge-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":17.1}, - "nudge-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.74,"frameP95":17.2}, - "nudge-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.22,"frameP95":17.41}, - "nudge-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.21}, - "nudge-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":17.41}, - "nudge-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":17.7}, - "nudge-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":17.5}, - "nudge-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17.31}, - "nudge-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.4}, - "nudge-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.22,"frameP95":17.8}, - "nudge-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.6}, - "nudge-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.76,"frameP95":17.2}, - "nudge-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.21}, - "nudge-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.74,"frameP95":17.21}, - "nudge-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.41}, - "nudge-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.2,"frameP95":17.6}, - "nudge-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":19.4}, - "nudge-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.79,"frameP95":17}, - "nudge-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":17.3}, - "nudge-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.55,"frameP95":17.11}, - "nudge-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.03,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.66,"frameP95":17}, - "nudge-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":20}, - "nudge-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.6}, - "nudge-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.78,"frameP95":17.2}, - "nudge-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17.1}, - "nudge-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.99,"frameP95":17}, - "nudge-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":18.1}, - "nudge-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":17.1}, - "nudge-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.1}, - "nudge-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.31,"frameP95":17.31}, - "nudge-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.41}, - "nudge-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.31,"frameP95":17.31}, - "nudge-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":17.5}, - "nudge-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":18.3}, - "nudge-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.5}, - "nudge-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.75,"frameP95":17.2}, - "nudge-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":17.5}, - "nudge-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.65,"frameP95":17.11}, - "nudge-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":17.3}, - "nudge-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":17.31}, - "nudge-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.41,"frameP95":17.41}, - "nudge-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.2}, - "nudge-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":17.5}, - "nudge-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.83,"frameP95":17.21}, - "nudge-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.4,"frameP95":17.41}, - "nudge-tween-center-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.21}, - "nudge-tween-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":16.91}, - "nudge-tween-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17.3}, - "nudge-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.01,"frameP95":17.1}, - "nudge-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.5}, - "nudge-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.94,"frameP95":17.1}, - "nudge-tween-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":17.2}, - "nudge-tween-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":24.71}, - "nudge-tween-center-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.07,"frameP95":17.5}, - "nudge-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17}, - "nudge-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":17.5}, - "nudge-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.91,"frameP95":17.41}, - "nudge-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17}, - "nudge-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17.11}, - "nudge-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":17.2}, - "nudge-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17.2}, - "nudge-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":18.8}, - "nudge-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":19}, - "nudge-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.3}, - "nudge-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.1}, - "nudge-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":20.2}, - "nudge-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.61}, - "nudge-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.2}, - "nudge-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":17.41}, - "nudge-tween-px-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.4}, - "nudge-tween-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":17.3}, - "nudge-tween-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":17.2}, - "nudge-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":18.8}, - "nudge-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":17.1}, - "nudge-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":17.91}, - "nudge-tween-px-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.6,"frameP95":17.3}, - "nudge-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.83,"frameP95":18.3}, - "nudge-tween-px-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.11}, - "nudge-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.33,"frameP95":17.41}, - "nudge-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":17.21}, - "nudge-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.09,"frameP95":17.4}, - "nudge-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":16.91}, - "nudge-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.93,"frameP95":17.21}, - "nudge-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.5}, - "nudge-tween-xpercent-r30-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.44,"frameP95":18.4}, - "nudge-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.69,"frameP95":17.2}, - "nudge-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":17.21}, - "nudge-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.3}, - "nudge-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.3}, - "nudge-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":17.5}, - "pathcircle-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":18}, - "pathcircle-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.27,"frameP95":17.9}, - "pathcircle-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.84,"frameP95":17.9}, - "pathcircle-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":18.1}, - "pathcircle-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":18.5}, - "pathcircle-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":17.4}, - "pathcircle-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.7}, - "pathcircle-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.32,"frameP95":17.8}, - "pathcircle-none-px-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.16,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.02,"frameP95":17.8}, - "pathedge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.31,"frameP95":19.3}, - "pathedge-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.2}, - "pathedge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":18.1}, - "pathedge-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.2}, - "pathedge-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":18.5}, - "pathedge-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":19.5}, - "pathedge-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":18.4}, - "pathedge-none-px-r0-root-z50": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":17.6}, - "pathedge-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":19.3}, - "pathflick-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.7}, - "pathflick-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":18.8}, - "pathflick-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":18.7}, - "pathflick-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.86,"frameP95":17.4}, - "pathflick-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":17.2}, - "pathflick-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.38,"frameP95":17}, - "pathflick-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":18}, - "pathflick-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.39,"frameP95":17.1}, - "pathflick-none-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.2}, - "pathpause-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.8}, - "pathpause-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.68,"frameP95":17.6}, - "pathpause-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.17,"frameP95":18.5}, - "pathpause-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.48,"frameP95":17.5}, - "pathpause-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":18.4}, - "pathpause-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.23,"frameP95":17.4}, - "pathpause-none-px-r0-root-z200": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, - "pathpause-none-px-r0-root-z50": {"smooth":true,"tracking":0,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.6,"frameP95":17.2}, - "pathpause-none-px-r30-root-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":12.82,"frameP95":17.4}, - "pathstray-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.99,"frameP95":17.9}, - "pathstray-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":17.5}, - "pathstray-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":18.2}, - "pathstray-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.21,"frameP95":17.6}, - "pathstray-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":17.8}, - "pathstray-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.77,"frameP95":17.7}, - "pathstray-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7,"frameP95":17.8}, - "pathstray-none-px-r0-root-z50": {"smooth":true,"tracking":0,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.21,"frameP95":17.2}, - "pathstray-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":17.4}, - "pathzigzag-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":17.7}, - "pathzigzag-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":17.5}, - "pathzigzag-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.66,"frameP95":18}, - "pathzigzag-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.41,"frameP95":17.7}, - "pathzigzag-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.74,"frameP95":17.8}, - "pathzigzag-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":17.1}, - "pathzigzag-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":17.7}, - "pathzigzag-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":17.5}, - "pathzigzag-none-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":17.8}, - "resize-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.78,"frameP95":18.6}, - "resize-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":19}, - "resize-fromto-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.4}, - "resize-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.02,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.52,"frameP95":18.21}, - "resize-fromto-px-r0-nested-z50-mid": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, - "resize-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.07,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.22,"frameP95":17.91}, - "resize-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":18.5}, - "resize-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.78,"frameP95":17.81}, - "resize-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.36,"frameP95":18.2}, - "resize-fromto-px-r0-root-z200-on": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.29,"frameP95":18}, - "resize-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":19.91}, - "resize-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":18.31}, - "resize-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.12,"frameP95":17.8}, - "resize-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.82,"frameP95":18.6}, - "resize-fromto-px-r30-nested-z200-mid": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.91}, - "resize-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.03,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":20.2}, - "resize-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.1,"frameP95":17.7}, - "resize-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":18.31}, - "resize-fromto-px-r30-root-z100-mid": {"smooth":false,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":94.42,"keys":false,"css":true,"renderKey":0.03,"drop":136.77,"reload":136.77,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18}, - "resize-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":false,"teleportPx":95.43,"keys":false,"css":true,"renderKey":0.07,"drop":131.59,"reload":131.59,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":18}, - "resize-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":94.42,"keys":false,"css":true,"renderKey":0.03,"drop":136.73,"reload":136.76,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.22,"frameP95":21.31}, - "resize-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":95.44,"keys":false,"css":true,"renderKey":0.07,"drop":131.57,"reload":131.59,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":18.2}, - "resize-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":94.43,"keys":false,"css":true,"renderKey":0.03,"drop":136.74,"reload":136.74,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":18.11}, - "resize-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":95.43,"keys":false,"css":true,"renderKey":0.07,"drop":131.6,"reload":131.6,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.47,"frameP95":18.2}, - "resize-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.99,"frameP95":18.8}, - "resize-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":17.5}, - "resize-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.87,"frameP95":19.71}, - "resize-hold-center-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":17.8}, - "resize-hold-center-r0-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":17.5}, - "resize-hold-center-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":17.5}, - "resize-hold-center-r30-nested-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":5.9,"frameP95":18.4}, - "resize-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":20.3}, - "resize-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":18.2}, - "resize-hold-center-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.64,"frameP95":19.3}, - "resize-hold-center-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.72,"frameP95":18.41}, - "resize-hold-center-r30-root-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":17.6}, - "resize-hold-pct-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.61,"frameP95":19.4}, - "resize-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":17.71}, - "resize-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.1,"frameP95":18.8}, - "resize-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":17.91}, - "resize-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.64,"frameP95":18.41}, - "resize-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":17.5}, - "resize-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.51,"frameP95":21.3}, - "resize-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":19.41}, - "resize-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":17.91}, - "resize-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":18.1}, - "resize-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.72,"frameP95":18.21}, - "resize-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.94,"frameP95":18.5}, - "resize-hold-px-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.91,"frameP95":18.91}, - "resize-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":18.8}, - "resize-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":19.1}, - "resize-hold-px-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.91}, - "resize-hold-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.81}, - "resize-hold-px-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":17.8}, - "resize-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":19.21}, - "resize-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18.41}, - "resize-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.8}, - "resize-hold-px-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.91,"frameP95":20.71}, - "resize-hold-px-r30-root-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.77,"frameP95":21.6}, - "resize-hold-px-r30-root-z50": {"smooth":false,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.23,"frameP95":19.1}, - "resize-hold-xpercent-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":11.29,"frameP95":19.3}, - "resize-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.5}, - "resize-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.95,"frameP95":18}, - "resize-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":17.7}, - "resize-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.6}, - "resize-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.56,"frameP95":18.21}, - "resize-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.35,"frameP95":18.6}, - "resize-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":18.6}, - "resize-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.76,"frameP95":17.81}, - "resize-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":17.9}, - "resize-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.91,"frameP95":18}, - "resize-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.56,"frameP95":19.2}, - "resize-idle-center-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.83,"frameP95":18.91}, - "resize-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.4}, - "resize-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.56,"frameP95":19.2}, - "resize-idle-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.86,"frameP95":17.8}, - "resize-idle-center-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":17.5}, - "resize-idle-center-r0-root-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.01,"frameP95":17.31}, - "resize-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":19.8}, - "resize-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":17.71}, - "resize-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":17.5}, - "resize-idle-center-r30-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":18.41}, - "resize-idle-center-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":17.6}, - "resize-idle-center-r30-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":18.71}, - "resize-idle-pct-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.2,"frameP95":19.2}, - "resize-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":17.5}, - "resize-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18.4}, - "resize-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":18.3}, - "resize-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.29,"frameP95":18.5}, - "resize-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":17.4}, - "resize-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.72,"frameP95":19.71}, - "resize-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.41,"frameP95":19.41}, - "resize-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":17.2}, - "resize-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.76,"frameP95":18.1}, - "resize-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.48,"frameP95":18.31}, - "resize-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.2,"frameP95":17.5}, - "resize-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.36,"frameP95":18.71}, - "resize-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":19.8}, - "resize-idle-px-r0-nested-z50": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":9.24,"frameP95":19.41}, - "resize-idle-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":19.5}, - "resize-idle-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18}, - "resize-idle-px-r0-root-z50": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.33,"frameP95":20.9}, - "resize-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.37,"frameP95":19.71}, - "resize-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18.1}, - "resize-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":18.4}, - "resize-idle-px-r30-root-z100": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":19.4}, - "resize-idle-px-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7,"frameP95":18.21}, - "resize-idle-px-r30-root-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.66,"frameP95":18.81}, - "resize-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":60.06,"keys":false,"css":true,"renderKey":0.03,"drop":59.97,"reload":102.02,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":22}, - "resize-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":false,"teleportPx":60.24,"keys":false,"css":true,"renderKey":0.03,"drop":60.06,"reload":104.01,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.17,"frameP95":19.81}, - "resize-keys-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.31,"pressJump":0,"teleport":false,"teleportPx":60.07,"keys":false,"css":true,"renderKey":0.03,"drop":59.96,"reload":102,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.71}, - "resize-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":60.25,"keys":false,"css":true,"renderKey":0.03,"drop":60.06,"reload":104.01,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":18.41}, - "resize-keys-px-r0-nested-z50-mid": {"smooth":false,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":60.06,"keys":false,"css":true,"renderKey":0.03,"drop":60.01,"reload":101.98,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, - "resize-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":false,"teleportPx":60.25,"keys":false,"css":true,"renderKey":0.03,"drop":60,"reload":104.01,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.71,"frameP95":18.1}, - "resize-keys-px-r0-root-z100-mid": {"smooth":false,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":30.39,"keys":false,"css":true,"renderKey":0.03,"drop":30.46,"reload":87.37,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.91}, - "resize-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":52.12,"keys":false,"css":true,"renderKey":0.03,"drop":52.03,"reload":60.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":19.81}, - "resize-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":false,"teleportPx":71.62,"keys":false,"css":true,"renderKey":0.03,"drop":71.52,"reload":59.97,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.84,"frameP95":19}, - "resize-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":52.13,"keys":false,"css":true,"renderKey":0.03,"drop":52.03,"reload":60.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.61,"frameP95":18.5}, - "resize-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":false,"teleportPx":71.62,"keys":false,"css":true,"renderKey":0.03,"drop":71.57,"reload":59.97,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":18.41}, - "resize-keys-px-r0-root-z50-on": {"smooth":false,"tracking":0.32,"pressJump":0,"teleport":false,"teleportPx":52.13,"keys":false,"css":true,"renderKey":0.03,"drop":51.98,"reload":60.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.42,"frameP95":18.1}, - "resize-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.34,"pressJump":0,"teleport":false,"teleportPx":44.69,"keys":false,"css":true,"renderKey":0.05,"drop":72.08,"reload":98.52,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.39,"frameP95":18.41}, - "resize-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":false,"teleportPx":45.44,"keys":false,"css":true,"renderKey":0.05,"drop":71.9,"reload":100.5,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.74,"frameP95":18.5}, - "resize-keys-px-r30-nested-z200-mid": {"smooth":false,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":44.7,"keys":false,"css":true,"renderKey":0.05,"drop":72.11,"reload":98.54,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.6}, - "resize-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":45.44,"keys":false,"css":true,"renderKey":0.05,"drop":71.89,"reload":100.47,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.5,"frameP95":19.3}, - "resize-keys-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.39,"pressJump":0,"teleport":false,"teleportPx":59.85,"keys":false,"css":true,"renderKey":0.05,"drop":59.93,"reload":59.97,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.81}, - "resize-keys-px-r30-nested-z50-on": {"smooth":false,"tracking":0.4,"pressJump":0,"teleport":false,"teleportPx":45.45,"keys":false,"css":true,"renderKey":0.05,"drop":71.9,"reload":100.46,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.01,"frameP95":18.3}, - "resize-keys-px-r30-root-z100-mid": {"smooth":false,"tracking":0.31,"pressJump":0,"teleport":false,"teleportPx":89.52,"keys":false,"css":true,"renderKey":0.06,"drop":134.74,"reload":149.37,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, - "resize-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":false,"teleportPx":145.59,"keys":false,"css":true,"renderKey":0.05,"drop":145.44,"reload":100.19,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.46,"frameP95":17.91}, - "resize-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":156.44,"keys":false,"css":true,"renderKey":0.06,"drop":156.35,"reload":112.55,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":19.6}, - "resize-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":145.59,"keys":false,"css":true,"renderKey":0.05,"drop":145.37,"reload":100.14,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":7,"frameP95":18.21}, - "resize-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.44,"pressJump":0,"teleport":false,"teleportPx":156.43,"keys":false,"css":true,"renderKey":0.06,"drop":156.26,"reload":112.51,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.71}, - "resize-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.42,"pressJump":0,"teleport":false,"teleportPx":145.62,"keys":false,"css":true,"renderKey":0.05,"drop":145.35,"reload":100.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.71,"frameP95":18.91}, - "resize-none-center-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.75,"frameP95":19.3}, - "resize-none-center-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.77,"frameP95":17.91}, - "resize-none-center-r0-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.19,"frameP95":19.7}, - "resize-none-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.93,"frameP95":20.31}, - "resize-none-center-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.16,"frameP95":18.71}, - "resize-none-center-r0-root-z50": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.03,"frameP95":19.71}, - "resize-none-center-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":19.4}, - "resize-none-center-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.59,"frameP95":19.5}, - "resize-none-center-r30-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.22,"frameP95":18.71}, - "resize-none-center-r30-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":18.91}, - "resize-none-center-r30-root-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.06,"frameP95":20.9}, - "resize-none-center-r30-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":18.4}, - "resize-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.82,"frameP95":18.6}, - "resize-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":20.7}, - "resize-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.12,"frameP95":18.2}, - "resize-none-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":18.21}, - "resize-none-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.9}, - "resize-none-pct-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.37,"frameP95":19}, - "resize-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18}, - "resize-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.18,"frameP95":18.6}, - "resize-none-pct-r30-nested-z50": {"smooth":false,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.14,"frameP95":19.8}, - "resize-none-pct-r30-root-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.34,"frameP95":18.8}, - "resize-none-pct-r30-root-z200": {"smooth":false,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":9.47,"frameP95":19.9}, - "resize-none-pct-r30-root-z50": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":19.9}, - "resize-none-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.78,"frameP95":21.4}, - "resize-none-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.7,"frameP95":19.6}, - "resize-none-px-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.47,"frameP95":18.5}, - "resize-none-px-r0-root-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":2,"controlDropped":0,"workMax":8.49,"frameP95":24.7}, - "resize-none-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.12,"frameP95":19.1}, - "resize-none-px-r0-root-z50": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.2,"frameP95":21.9}, - "resize-none-px-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.08,"frameP95":20.3}, - "resize-none-px-r30-nested-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.8,"frameP95":19.2}, - "resize-none-px-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":17.8}, - "resize-none-px-r30-root-z100": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":17.9}, - "resize-none-px-r30-root-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.7,"frameP95":19.4}, - "resize-none-px-r30-root-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":20.21}, - "resize-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.35,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.19,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.43,"frameP95":18.81}, - "resize-scale-px-r0-nested-z100-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.01,"drop":0.24,"reload":0.24,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.7,"frameP95":19}, - "resize-scale-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.36,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.21,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.71}, - "resize-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.01,"drop":0.24,"reload":0.24,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.98,"frameP95":18.5}, - "resize-scale-px-r0-nested-z50-mid": {"smooth":false,"tracking":0.41,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.23,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.6}, - "resize-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":false,"css":true,"renderKey":0.01,"drop":0.28,"reload":0.28,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":19.11}, - "resize-scale-px-r0-root-z100-mid": {"smooth":false,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.19,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, - "resize-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":false,"css":true,"renderKey":0.02,"drop":0.25,"reload":0.25,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.56,"frameP95":17.91}, - "resize-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.19,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18.11}, - "resize-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.02,"drop":0.26,"reload":0.27,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.7,"frameP95":20.31}, - "resize-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.14,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":17.91}, - "resize-scale-px-r0-root-z50-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.24,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":9.3,"frameP95":19.2}, - "resize-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.36,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.11,"drop":0.2,"reload":0.2,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.08,"frameP95":17.91}, - "resize-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.11,"drop":0.25,"reload":0.25,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":17.91}, - "resize-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.35,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.11,"drop":0.2,"reload":0.21,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":17.91}, - "resize-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":false,"css":true,"renderKey":0.11,"drop":0.24,"reload":0.24,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.33,"frameP95":19.41}, - "resize-scale-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.46,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":false,"css":true,"renderKey":0.11,"drop":0.21,"reload":0.2,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":20.41}, - "resize-scale-px-r30-nested-z50-on": {"smooth":false,"tracking":0.39,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":false,"css":true,"renderKey":0.11,"drop":0.26,"reload":0.28,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.15,"frameP95":18.91}, - "resize-scale-px-r30-root-z100-mid": {"smooth":false,"tracking":0.38,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":false,"css":true,"renderKey":0.08,"drop":138.89,"reload":138.71,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, - "resize-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":false,"css":true,"renderKey":0.08,"drop":148.2,"reload":148.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.71,"frameP95":18.1}, - "resize-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.36,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":false,"css":true,"renderKey":0.08,"drop":138.86,"reload":138.67,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":19.91}, - "resize-scale-px-r30-root-z200-on": {"smooth":false,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":false,"css":true,"renderKey":0.08,"drop":148.17,"reload":148.04,"render":0.02,"undo":false,"dropped":1,"controlDropped":0,"workMax":8.86,"frameP95":20.2}, - "resize-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.39,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":false,"css":true,"renderKey":0.08,"drop":138.8,"reload":138.62,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18}, - "resize-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":false,"css":true,"renderKey":0.08,"drop":148,"reload":147.97,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":20.3}, - "resize-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.94,"frameP95":18.5}, - "resize-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.98,"frameP95":18.2}, - "resize-size-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.5}, - "resize-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.89,"frameP95":18.7}, - "resize-size-px-r0-nested-z50-mid": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, - "resize-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.69,"frameP95":18.1}, - "resize-size-px-r0-root-z100-mid": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, - "resize-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":false,"css":true,"renderKey":0.03,"drop":120.37,"reload":120.37,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":18.11}, - "resize-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":false,"css":true,"renderKey":0.03,"drop":120.38,"reload":120.38,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18.2}, - "resize-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":false,"css":true,"renderKey":0.03,"drop":120.38,"reload":120.37,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.49,"frameP95":18.91}, - "resize-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":false,"css":true,"renderKey":0.03,"drop":120.39,"reload":120.36,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.25,"frameP95":19.3}, - "resize-size-px-r0-root-z50-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":false,"css":true,"renderKey":0.03,"drop":120.34,"reload":120.37,"render":0.02,"undo":false,"dropped":1,"controlDropped":0,"workMax":9.37,"frameP95":19.21}, - "resize-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18}, - "resize-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.87,"frameP95":18.7}, - "resize-size-px-r30-nested-z200-mid": {"smooth":false,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.81}, - "resize-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0.04,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.9,"frameP95":18.21}, - "resize-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.6}, - "resize-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.11,"drop":0,"reload":0.11,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.34,"frameP95":19.71}, - "resize-size-px-r30-root-z100-mid": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.3,"reload":116.3,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.2}, - "resize-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.3,"reload":116.3,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":18.1}, - "resize-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.28,"reload":116.28,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18.8}, - "resize-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.24,"reload":116.25,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.31,"frameP95":18.31}, - "resize-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.26,"reload":116.3,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.7}, - "resize-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":false,"css":true,"renderKey":0.09,"drop":116.33,"reload":116.33,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.66,"frameP95":18.7}, - "resize-spin-px-r0-nested-z100-mid": {"smooth":false,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.03,"frameP95":20.6}, - "resize-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.91,"frameP95":18.4}, - "resize-spin-px-r0-nested-z200-mid": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.7}, - "resize-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18.41}, - "resize-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":17.91}, - "resize-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.34,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":18.4}, - "resize-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":18.31}, - "resize-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":19.5}, - "resize-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.56,"frameP95":18}, - "resize-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.46,"frameP95":18.7}, - "resize-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.53,"frameP95":18.41}, - "resize-spin-px-r0-root-z50-on": {"smooth":false,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":9.43,"frameP95":19.41}, - "resize-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":17.81}, - "resize-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.2,"frameP95":18.3}, - "resize-spin-px-r30-nested-z200-mid": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.1}, - "resize-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":18.6}, - "resize-spin-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.7}, - "resize-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.34,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.19,"frameP95":17.41}, - "resize-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":18.31}, - "resize-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":19}, - "resize-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.03,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":20.3}, - "resize-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.2,"frameP95":18.6}, - "resize-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.17,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.5}, - "resize-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.52,"frameP95":18.3}, - "resize-tween-center-r0-nested-z100": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.88,"frameP95":18.91}, - "resize-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17.6}, - "resize-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":19.8}, - "resize-tween-center-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":17.41}, - "resize-tween-center-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17.8}, - "resize-tween-center-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.67,"frameP95":17.6}, - "resize-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":19.71}, - "resize-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.81,"frameP95":18.71}, - "resize-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.43,"frameP95":17.61}, - "resize-tween-center-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.96,"frameP95":18.1}, - "resize-tween-center-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.45,"frameP95":18.3}, - "resize-tween-center-r30-root-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":17.61}, - "resize-tween-pct-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.64,"frameP95":18.8}, - "resize-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.5}, - "resize-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.33,"frameP95":20.5}, - "resize-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":18.5}, - "resize-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":18}, - "resize-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":17.9}, - "resize-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.52,"frameP95":20.5}, - "resize-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":17.71}, - "resize-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.61}, - "resize-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":19}, - "resize-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.1,"frameP95":18.21}, - "resize-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":19.5}, - "resize-tween-px-r0-nested-z100": {"smooth":false,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.17,"frameP95":18.5}, - "resize-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.02,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.9}, - "resize-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.86,"frameP95":17.71}, - "resize-tween-px-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.31,"frameP95":18.4}, - "resize-tween-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.2,"frameP95":17.81}, - "resize-tween-px-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":18.4}, - "resize-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.03,"frameP95":19.1}, - "resize-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.11,"frameP95":18.41}, - "resize-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.71}, - "resize-tween-px-r30-root-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":8.38,"frameP95":18.11}, - "resize-tween-px-r30-root-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":19}, - "resize-tween-px-r30-root-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":17.6}, - "resize-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.26,"frameP95":18.8}, - "resize-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.5}, - "resize-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":19.21}, - "resize-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.6,"frameP95":20.3}, - "resize-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.87,"frameP95":17.71}, - "resize-tween-xpercent-r0-root-z50": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.69,"frameP95":17.8}, - "resize-tween-xpercent-r30-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.66,"frameP95":18.3}, - "resize-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":18.71}, - "resize-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.05,"frameP95":18.3}, - "resize-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.97,"frameP95":18.21}, - "resize-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.65,"frameP95":17.91}, - "resize-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.82,"frameP95":19.81}, - "rotate-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":18.7}, - "rotate-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":19.61}, - "rotate-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":18.71}, - "rotate-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":17.5}, - "rotate-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.97,"frameP95":17.21}, - "rotate-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.4}, - "rotate-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":18.7}, - "rotate-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.44,"frameP95":17.71}, - "rotate-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.35,"frameP95":17.91}, - "rotate-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":17.5}, - "rotate-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":18.5}, - "rotate-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.81}, - "rotate-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":17.7}, - "rotate-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.41}, - "rotate-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.2}, - "rotate-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.31}, - "rotate-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17.21}, - "rotate-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.67,"frameP95":17.41}, - "rotate-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.86,"frameP95":17.31}, - "rotate-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.5,"frameP95":17.5}, - "rotate-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":19.61}, - "rotate-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.06,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.22,"frameP95":17.61}, - "rotate-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.2,"frameP95":17.7}, - "rotate-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":18.2}, - "rotate-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.74,"frameP95":19.3}, - "rotate-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":17.71}, - "rotate-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":18.5}, - "rotate-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.71}, - "rotate-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.5}, - "rotate-hold-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.41}, - "rotate-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":18.91}, - "rotate-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.21}, - "rotate-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":17.9}, - "rotate-hold-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.76,"frameP95":17.21}, - "rotate-hold-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":17.8}, - "rotate-hold-center-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":17.5}, - "rotate-hold-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":19.91}, - "rotate-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.8}, - "rotate-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.5}, - "rotate-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":17.71}, - "rotate-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.8,"frameP95":17.41}, - "rotate-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":17.5}, - "rotate-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":18}, - "rotate-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.34,"frameP95":17.2}, - "rotate-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":18.3}, - "rotate-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.06,"frameP95":17.3}, - "rotate-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.81}, - "rotate-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":17.41}, - "rotate-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":20}, - "rotate-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":19.21}, - "rotate-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":17.8}, - "rotate-hold-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":17.8}, - "rotate-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.92,"frameP95":18.21}, - "rotate-hold-px-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.98,"frameP95":17.8}, - "rotate-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.31}, - "rotate-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.03,"frameP95":17.21}, - "rotate-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.88,"frameP95":19.41}, - "rotate-hold-px-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.54,"frameP95":17.21}, - "rotate-hold-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.71}, - "rotate-hold-px-r30-root-z50": {"smooth":false,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":1,"controlDropped":0,"workMax":2.65,"frameP95":17.21}, - "rotate-hold-xpercent-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.2,"frameP95":22.81}, - "rotate-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":18.6}, - "rotate-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":19.71}, - "rotate-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18.61}, - "rotate-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.51,"frameP95":17.41}, - "rotate-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.7}, - "rotate-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":18.31}, - "rotate-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.21}, - "rotate-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.57,"frameP95":17.5}, - "rotate-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.4,"frameP95":17.21}, - "rotate-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.44,"frameP95":19}, - "rotate-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.14,"frameP95":17.5}, - "rotate-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.82,"frameP95":19.11}, - "rotate-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":19}, - "rotate-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.74,"frameP95":17.1}, - "rotate-idle-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":17.8}, - "rotate-idle-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.31,"frameP95":17.1}, - "rotate-idle-center-r0-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.22,"frameP95":17.31}, - "rotate-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.55,"frameP95":18.3}, - "rotate-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.95,"frameP95":17.31}, - "rotate-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":18.41}, - "rotate-idle-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.12,"frameP95":17.6}, - "rotate-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":17.5}, - "rotate-idle-center-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.81,"frameP95":17.11}, - "rotate-idle-pct-r0-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.43,"frameP95":18.4}, - "rotate-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":17.31}, - "rotate-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.51,"frameP95":17.1}, - "rotate-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":18.2}, - "rotate-idle-pct-r0-root-z200": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":3.78,"frameP95":18.1}, - "rotate-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.5}, - "rotate-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.03,"frameP95":17.81}, - "rotate-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.78,"frameP95":17.3}, - "rotate-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.4}, - "rotate-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":17.31}, - "rotate-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.26,"frameP95":19.1}, - "rotate-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.18,"frameP95":18}, - "rotate-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":17.5}, - "rotate-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":18.1}, - "rotate-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":18}, - "rotate-idle-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":20}, - "rotate-idle-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":18.21}, - "rotate-idle-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":17.71}, - "rotate-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.71}, - "rotate-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.55,"frameP95":18.5}, - "rotate-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":19.71}, - "rotate-idle-px-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.2}, - "rotate-idle-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":18.71}, - "rotate-idle-px-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.11,"frameP95":17.3}, - "rotate-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.71}, - "rotate-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":17.61}, - "rotate-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.06,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":18}, - "rotate-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.04,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":18.1}, - "rotate-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.13,"drop":0,"reload":0.07,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":17.11}, - "rotate-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.13,"drop":0,"reload":0.1,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.31}, - "rotate-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":18.1}, - "rotate-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.48,"frameP95":17.5}, - "rotate-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":17.61}, - "rotate-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":17.61}, - "rotate-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":19.4}, - "rotate-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.81}, - "rotate-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.5}, - "rotate-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.31}, - "rotate-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.31,"frameP95":17.21}, - "rotate-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.06,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.54,"frameP95":17.41}, - "rotate-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.45,"frameP95":17.31}, - "rotate-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":19.5}, - "rotate-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.75,"frameP95":17.3}, - "rotate-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.45,"frameP95":17.41}, - "rotate-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.81}, - "rotate-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":18}, - "rotate-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.7}, - "rotate-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.12,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":17.6}, - "rotate-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":18.4}, - "rotate-none-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":19.71}, - "rotate-none-center-r0-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":20.7}, - "rotate-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":19.21}, - "rotate-none-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":17.7}, - "rotate-none-center-r0-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":17.4}, - "rotate-none-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.7}, - "rotate-none-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.6}, - "rotate-none-center-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.61,"frameP95":21.4}, - "rotate-none-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.02,"frameP95":18.71}, - "rotate-none-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":18.61}, - "rotate-none-center-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":18.81}, - "rotate-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.3}, - "rotate-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.4}, - "rotate-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":17.2}, - "rotate-none-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":20.2}, - "rotate-none-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.9}, - "rotate-none-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.5}, - "rotate-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.6}, - "rotate-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":18.31}, - "rotate-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.58,"frameP95":18.9}, - "rotate-none-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.93,"frameP95":18.4}, - "rotate-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.28,"frameP95":17.31}, - "rotate-none-pct-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.6}, - "rotate-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.21,"frameP95":19.1}, - "rotate-none-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":21.21}, - "rotate-none-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.21,"frameP95":18.8}, - "rotate-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.3,"frameP95":20.2}, - "rotate-none-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.51,"frameP95":17.5}, - "rotate-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":18.9}, - "rotate-none-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.55,"frameP95":18.31}, - "rotate-none-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":17.4}, - "rotate-none-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":19}, - "rotate-none-px-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":18}, - "rotate-none-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":19.3}, - "rotate-none-px-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.29,"frameP95":18.31}, - "rotate-none-transform-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.41}, - "rotate-none-transform-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":18.31}, - "rotate-none-transform-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":20.4}, - "rotate-none-transform-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":19.5}, - "rotate-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":17.71}, - "rotate-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":17.6}, - "rotate-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.8}, - "rotate-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.08,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":18.7}, - "rotate-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.2,"frameP95":17.21}, - "rotate-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.5}, - "rotate-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.17,"frameP95":18.1}, - "rotate-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":20.31}, - "rotate-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.81}, - "rotate-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.41}, - "rotate-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.71}, - "rotate-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":18.41}, - "rotate-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.7}, - "rotate-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":17.5}, - "rotate-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.21}, - "rotate-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.48,"frameP95":17.41}, - "rotate-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":17.21}, - "rotate-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":20.4}, - "rotate-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.72,"frameP95":17.31}, - "rotate-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.42,"frameP95":17.81}, - "rotate-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.07,"frameP95":19.31}, - "rotate-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":18.5}, - "rotate-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.2,"frameP95":17.81}, - "rotate-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.11,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.83,"frameP95":17.81}, - "rotate-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.5}, - "rotate-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":18.6}, - "rotate-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":18.71}, - "rotate-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.41}, - "rotate-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.07,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.95,"frameP95":17.1}, - "rotate-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.14,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.32,"frameP95":17.3}, - "rotate-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.71,"frameP95":17.31}, - "rotate-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.19,"frameP95":17.31}, - "rotate-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.02,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.5}, - "rotate-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.31}, - "rotate-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.07,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.7}, - "rotate-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":17.7}, - "rotate-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.5}, - "rotate-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.3}, - "rotate-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.21}, - "rotate-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.21}, - "rotate-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.1}, - "rotate-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17.31}, - "rotate-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.83,"frameP95":17.2}, - "rotate-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.5}, - "rotate-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":18.5}, - "rotate-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":21.41}, - "rotate-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.81}, - "rotate-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":17.41}, - "rotate-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17.6}, - "rotate-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.91}, - "rotate-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":18.1}, - "rotate-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4,"frameP95":17.8}, - "rotate-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.98,"frameP95":17.21}, - "rotate-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.52,"frameP95":17.3}, - "rotate-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":false,"css":true,"renderKey":0.05,"drop":50.03,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.91}, - "rotate-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":false,"css":true,"renderKey":0.05,"drop":50.03,"reload":50.03,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":18.6}, - "rotate-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":false,"css":true,"renderKey":0.05,"drop":50.01,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.7}, - "rotate-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":false,"css":true,"renderKey":0.05,"drop":50.01,"reload":50.03,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.41}, - "rotate-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":50,"keys":false,"css":true,"renderKey":0.05,"drop":50.04,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.65,"frameP95":18.41}, - "rotate-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":false,"css":true,"renderKey":0.05,"drop":50.04,"reload":50.02,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":18.91}, - "rotate-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":17.71}, - "rotate-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.41}, - "rotate-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.03,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.2}, - "rotate-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":17.41}, - "rotate-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":17.41}, - "rotate-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":18.11}, - "rotate-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":25.85,"keys":false,"css":true,"renderKey":0.05,"drop":111.45,"reload":111.45,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.21}, - "rotate-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":26.81,"keys":false,"css":true,"renderKey":0.05,"drop":113.69,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":17.41}, - "rotate-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":8.78,"keys":false,"css":true,"renderKey":0.05,"drop":111.42,"reload":111.44,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":20.6}, - "rotate-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":10.76,"keys":false,"css":true,"renderKey":0.05,"drop":113.72,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.1,"frameP95":17.6}, - "rotate-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":60.18,"keys":false,"css":true,"renderKey":0.05,"drop":111.48,"reload":111.49,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":17.7}, - "rotate-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":false,"teleportPx":60.78,"keys":false,"css":true,"renderKey":0.05,"drop":113.69,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.5}, - "rotate-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":17.91}, - "rotate-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":17.5}, - "rotate-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17.11}, - "rotate-tween-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.12,"frameP95":17.61}, - "rotate-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":17.5}, - "rotate-tween-center-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.16,"frameP95":17.4}, - "rotate-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":18.4}, - "rotate-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.01,"frameP95":17.91}, - "rotate-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.46,"frameP95":18}, - "rotate-tween-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.8,"frameP95":17.3}, - "rotate-tween-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18}, - "rotate-tween-center-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":18.31}, - "rotate-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.64,"frameP95":20.4}, - "rotate-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":18.2}, - "rotate-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":17.1}, - "rotate-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":19.1}, - "rotate-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":19.4}, - "rotate-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.41}, - "rotate-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.6}, - "rotate-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.91}, - "rotate-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":18.71}, - "rotate-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.61,"frameP95":17.8}, - "rotate-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":17.81}, - "rotate-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.05,"frameP95":18.1}, - "rotate-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.98,"frameP95":20.21}, - "rotate-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.79,"frameP95":17.6}, - "rotate-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.56,"frameP95":17.3}, - "rotate-tween-px-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.37,"frameP95":18.41}, - "rotate-tween-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.02,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.94,"frameP95":17.5}, - "rotate-tween-px-r0-root-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.71}, - "rotate-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.8}, - "rotate-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.16,"frameP95":18}, - "rotate-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.43,"frameP95":18.71}, - "rotate-tween-px-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.27,"frameP95":17.21}, - "rotate-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":18.21}, - "rotate-tween-px-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.01,"frameP95":17.3}, - "rotate-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":20.1}, - "rotate-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.12,"frameP95":17.71}, - "rotate-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.68,"frameP95":17.4}, - "rotate-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":17.71}, - "rotate-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.97,"frameP95":17.21}, - "rotate-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.46,"frameP95":18.6}, - "rotate-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":17.61}, - "rotate-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.52,"frameP95":17.21}, - "rotate-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.67,"frameP95":17.9}, - "rotate-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.21}, - "rotate-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.97,"frameP95":17.7}, - "rotate-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.15,"frameP95":17.41}, - "seqab-none-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":17.9}, - "seqab-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.67,"frameP95":17.7}, - "seqab-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.4}, - "seqab-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":17.6}, - "seqab-none-px-r0-nested-z100": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.13,"frameP95":17.7}, - "seqab-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.02,"frameP95":18}, - "seqinflight-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.8}, - "seqinflight-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":17.8}, - "seqinflight-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.07,"frameP95":18.1}, - "seqinflight-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.2}, - "seqinflight-none-px-r0-nested-z100": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.19,"frameP95":17.3}, - "seqinflight-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.57,"frameP95":17.6}, - "seqnudge-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.26,"frameP95":17.9}, - "seqnudge-none-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":14.23,"frameP95":18}, - "seqnudge-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.7,"frameP95":17.7}, - "seqnudge-none-pct-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":11.79,"frameP95":17.7}, - "seqnudge-none-px-r0-nested-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":14.95,"frameP95":17.6}, - "seqnudge-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.04,"frameP95":17.3}, + "crop-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":17.2}, + "crop-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.03,"drop":0.09,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":17.5}, + "crop-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":18.8}, + "crop-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":18.91}, + "crop-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.1,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.2}, + "crop-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":18.3}, + "crop-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.06,"reload":0.06,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":18.3}, + "crop-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.02,"drop":0.09,"reload":0.09,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":17.21}, + "crop-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.02,"drop":0.03,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.1}, + "crop-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.02,"drop":0.04,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.4}, + "crop-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.02,"drop":0.13,"reload":0.12,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":17.31}, + "crop-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.02,"drop":0.11,"reload":0.12,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.91}, + "crop-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.29,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":18.1}, + "crop-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.29,"drop":0.08,"reload":0.08,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.5}, + "crop-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.29,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.7}, + "crop-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.29,"drop":0.04,"reload":0.04,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":18.2}, + "crop-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.29,"drop":0.14,"reload":0.11,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":19.41}, + "crop-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.29,"drop":0.08,"reload":0.07,"render":0.28,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.21}, + "crop-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.27,"drop":0.06,"reload":0.06,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.31}, + "crop-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.27,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":17.21}, + "crop-fromto-px-r30-root-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.27,"drop":0.02,"reload":0.04,"render":0.25,"undo":true,"dropped":1,"controlDropped":0,"workMax":4.62,"frameP95":18.6}, + "crop-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.27,"drop":0.02,"reload":0.05,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.03,"frameP95":17.61}, + "crop-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.27,"drop":0.14,"reload":0.11,"render":0.25,"undo":true,"dropped":0,"controlDropped":1,"workMax":5.05,"frameP95":18.3}, + "crop-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.27,"drop":0.14,"reload":0.11,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.2}, + "crop-hold-center-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.85,"frameP95":17.81}, + "crop-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":17.5}, + "crop-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.7,"frameP95":18.81}, + "crop-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":18.7}, + "crop-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":17.11}, + "crop-hold-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.81}, + "crop-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18.81}, + "crop-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.9}, + "crop-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":18.1}, + "crop-hold-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":17.21}, + "crop-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.1}, + "crop-hold-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.3}, + "crop-hold-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":18.41}, + "crop-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.94,"frameP95":17.21}, + "crop-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.04,"frameP95":17.3}, + "crop-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.01,"frameP95":17.6}, + "crop-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":17.21}, + "crop-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.21}, + "crop-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":19.1}, + "crop-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":17}, + "crop-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.14,"reload":0.11,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.7}, + "crop-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.31}, + "crop-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":18.4}, + "crop-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.12,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.5}, + "crop-hold-px-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.53,"frameP95":18.71}, + "crop-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":17.21}, + "crop-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.84,"frameP95":17.6}, + "crop-hold-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.3}, + "crop-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":17.2}, + "crop-hold-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":17.41}, + "crop-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.69,"frameP95":18.91}, + "crop-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.1,"frameP95":17.21}, + "crop-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.14,"reload":0.11,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":18.4}, + "crop-hold-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.02,"frameP95":17.1}, + "crop-hold-px-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":1,"controlDropped":0,"workMax":3.87,"frameP95":18.5}, + "crop-hold-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.12,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.41}, + "crop-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.45,"frameP95":18.31}, + "crop-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":17.71}, + "crop-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":18.4}, + "crop-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":17.81}, + "crop-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17.21}, + "crop-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":17.21}, + "crop-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.43,"frameP95":17.9}, + "crop-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":17.61}, + "crop-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.12,"frameP95":17.21}, + "crop-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":17.6}, + "crop-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":18.61}, + "crop-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":17.41}, + "crop-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":18.3}, + "crop-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":16.91}, + "crop-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.54,"frameP95":17.9}, + "crop-idle-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":17}, + "crop-idle-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.3}, + "crop-idle-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.47,"frameP95":17.1}, + "crop-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":17.5}, + "crop-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":18.11}, + "crop-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":18.2}, + "crop-idle-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":16.91}, + "crop-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":17.4}, + "crop-idle-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.45,"frameP95":17.7}, + "crop-idle-pct-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.67,"frameP95":19.6}, + "crop-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":17.11}, + "crop-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.68,"frameP95":17.2}, + "crop-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":17.1}, + "crop-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":18.1}, + "crop-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.4}, + "crop-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":18.21}, + "crop-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.1}, + "crop-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":17.4}, + "crop-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.5}, + "crop-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":20.9}, + "crop-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.14,"frameP95":17.21}, + "crop-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.8}, + "crop-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":19.1}, + "crop-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.5,"frameP95":20}, + "crop-idle-px-r0-root-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.06,"frameP95":18.7}, + "crop-idle-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":19}, + "crop-idle-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":18}, + "crop-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":18.1}, + "crop-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.21}, + "crop-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.14,"reload":0.11,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.8}, + "crop-idle-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.1}, + "crop-idle-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":17.1}, + "crop-idle-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"drop":0.14,"reload":0.14,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":18.7}, + "crop-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.1}, + "crop-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":17.1}, + "crop-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":18.7}, + "crop-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.03,"drop":0.03,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":18.1}, + "crop-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.03,"drop":0.16,"reload":0.13,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":17.31}, + "crop-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.6}, + "crop-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.09,"keys":true,"css":true,"renderKey":0.03,"drop":0.09,"reload":0.09,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":18.6}, + "crop-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.07,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":19.3}, + "crop-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":17.1}, + "crop-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.03,"drop":0.03,"reload":0.03,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.86,"frameP95":16.91}, + "crop-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.16,"keys":true,"css":true,"renderKey":0.03,"drop":0.18,"reload":0.15,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":18.1}, + "crop-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.03,"drop":0.12,"reload":0.12,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":18.6}, + "crop-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.25,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.77,"frameP95":17.71}, + "crop-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.25,"drop":0.06,"reload":0.06,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17}, + "crop-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.25,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17}, + "crop-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.25,"drop":0.04,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":1,"workMax":5.3,"frameP95":18.71}, + "crop-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.25,"drop":0.14,"reload":0.15,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":17.7}, + "crop-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.25,"drop":0.18,"reload":0.11,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":19.8}, + "crop-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.24,"drop":0.11,"reload":0.11,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17}, + "crop-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.24,"drop":0.06,"reload":0.06,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":17.2}, + "crop-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.24,"drop":0.04,"reload":0.05,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.21}, + "crop-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"keys":true,"css":true,"renderKey":0.24,"drop":0.03,"reload":0.03,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.33,"frameP95":18.1}, + "crop-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.17,"keys":true,"css":true,"renderKey":0.24,"drop":0.19,"reload":0.18,"render":0.25,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":17.1}, + "crop-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.24,"drop":0.16,"reload":0.13,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.2}, + "crop-none-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":18.2}, + "crop-none-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":17.3}, + "crop-none-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":18.7}, + "crop-none-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":18.31}, + "crop-none-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":19.31}, + "crop-none-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.11,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":19.1}, + "crop-none-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":18.5}, + "crop-none-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":18.81}, + "crop-none-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.06,"frameP95":18.1}, + "crop-none-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":18.21}, + "crop-none-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.04,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":18.4}, + "crop-none-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":18.1}, + "crop-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.89,"frameP95":19.21}, + "crop-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.36,"frameP95":18.31}, + "crop-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":18.5}, + "crop-none-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":18.6}, + "crop-none-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":18.3}, + "crop-none-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.39,"frameP95":17.5}, + "crop-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":18.5}, + "crop-none-pct-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.44,"frameP95":18.3}, + "crop-none-pct-r30-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":1,"controlDropped":0,"workMax":5.61,"frameP95":17.8}, + "crop-none-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.26,"frameP95":19.81}, + "crop-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.58,"frameP95":18}, + "crop-none-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.11,"reload":0.1,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":18.5}, + "crop-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.08,"reload":0.08,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":19.1}, + "crop-none-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":19.1}, + "crop-none-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.1,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.17,"frameP95":19.1}, + "crop-none-px-r0-root-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.12,"frameP95":20.5}, + "crop-none-px-r0-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":5.44,"frameP95":21.4}, + "crop-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.5}, + "crop-none-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":18.4}, + "crop-none-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.04,"reload":0.05,"render":0.3,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.69,"frameP95":18.4}, + "crop-none-px-r30-nested-z50": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.14,"reload":0.11,"render":0.3,"undo":true,"dropped":2,"controlDropped":0,"workMax":5.79,"frameP95":22.6}, + "crop-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.08,"reload":0.08,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":18}, + "crop-none-px-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.26,"undo":true,"dropped":2,"controlDropped":0,"workMax":5.49,"frameP95":21.21}, + "crop-none-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"drop":0.14,"reload":0.14,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":17.9}, + "crop-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.09,"reload":0.09,"render":0.99,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":18.31}, + "crop-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.01,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.02,"frameP95":18}, + "crop-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.84,"frameP95":18.91}, + "crop-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.01,"drop":0.04,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":18.1}, + "crop-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.02,"drop":0.12,"reload":0.15,"render":0.99,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":17.5}, + "crop-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.01,"drop":0.11,"reload":0.11,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":17.3}, + "crop-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.02,"drop":0.08,"reload":0.08,"render":0.99,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.85,"frameP95":18.41}, + "crop-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":18.7}, + "crop-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17.1}, + "crop-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.02,"drop":0.05,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.1}, + "crop-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.02,"drop":0.12,"reload":0.13,"render":0.99,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":18.1}, + "crop-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.02,"drop":0.11,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":18}, + "crop-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.25,"drop":0.11,"reload":0.11,"render":0.78,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":18.5}, + "crop-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.23,"drop":0.06,"reload":0.06,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.5}, + "crop-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.24,"drop":0.05,"reload":0.06,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":17.5}, + "crop-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.23,"drop":0.04,"reload":0.03,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":18}, + "crop-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.24,"drop":0.16,"reload":0.16,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":18.4}, + "crop-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.1,"keys":true,"css":true,"renderKey":0.23,"drop":0.06,"reload":0.1,"render":0.34,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":18.3}, + "crop-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.22,"drop":0.08,"reload":0.08,"render":0.78,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.2}, + "crop-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.21,"drop":0.09,"reload":0.09,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":18.7}, + "crop-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.04,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":19.2}, + "crop-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.21}, + "crop-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.22,"drop":0.16,"reload":0.13,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17}, + "crop-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.21,"drop":0.06,"reload":0.09,"render":0.28,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.5}, + "crop-size-px-r0-nested-z100-mid": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":3.94,"frameP95":18.8}, + "crop-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.5}, + "crop-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.07,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.79,"frameP95":19.5}, + "crop-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.68,"frameP95":17.6}, + "crop-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.13,"keys":true,"css":true,"renderKey":0.03,"drop":0.19,"reload":0.15,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.4}, + "crop-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.03,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.96,"frameP95":18.5}, + "crop-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.06,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":19.1}, + "crop-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":19.5}, + "crop-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.03,"drop":0.05,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17}, + "crop-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.1}, + "crop-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.16,"keys":true,"css":true,"renderKey":0.03,"drop":0.24,"reload":0.18,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":17.1}, + "crop-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.03,"drop":0.13,"reload":0.12,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":17}, + "crop-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.2,"drop":0.07,"reload":0.07,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.21,"frameP95":17.1}, + "crop-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.07,"keys":true,"css":true,"renderKey":0.2,"drop":0.06,"reload":0.06,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.41}, + "crop-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.06,"keys":true,"css":true,"renderKey":0.2,"drop":0.06,"reload":0.07,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.41}, + "crop-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.2,"drop":0.05,"reload":0.05,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":18.5}, + "crop-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.2,"drop":0.17,"reload":0.17,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":19.4}, + "crop-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"keys":true,"css":true,"renderKey":0.2,"drop":0.17,"reload":0.1,"render":0.36,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":18.41}, + "crop-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.22,"drop":0.08,"reload":0.08,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":17.2}, + "crop-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.08,"keys":true,"css":true,"renderKey":0.22,"drop":0.09,"reload":0.09,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":17.31}, + "crop-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.06,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":18.81}, + "crop-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.06,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.6}, + "crop-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.18,"keys":true,"css":true,"renderKey":0.22,"drop":0.23,"reload":0.21,"render":0.18,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17.41}, + "crop-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.22,"drop":0.17,"reload":0.15,"render":0.29,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.1}, + "crop-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":17.6}, + "crop-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":18.1}, + "crop-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18.3}, + "crop-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.5}, + "crop-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.1,"render":0.32,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":17.21}, + "crop-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.5}, + "crop-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.06,"reload":0.06,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":18.5}, + "crop-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.04,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":19.41}, + "crop-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.03,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":17.11}, + "crop-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":17.11}, + "crop-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"keys":true,"css":true,"renderKey":0.21,"drop":0.17,"reload":0.12,"render":0.26,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.31}, + "crop-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.21,"drop":0.15,"reload":0.1,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.7}, + "crop-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.06,"reload":0.06,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.5}, + "crop-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.07,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.91}, + "crop-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.04,"reload":0.05,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.67,"frameP95":17.5}, + "crop-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.04,"keys":true,"css":true,"renderKey":0.22,"drop":0.05,"reload":0.05,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.09,"frameP95":17.2}, + "crop-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.1,"reload":0.11,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":17.1}, + "crop-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"keys":true,"css":true,"renderKey":0.22,"drop":0.11,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.2}, + "crop-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.07,"reload":0.07,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.31}, + "crop-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.04,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":17.4}, + "crop-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.05,"reload":0.07,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.31,"frameP95":17.11}, + "crop-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"keys":true,"css":true,"renderKey":0.21,"drop":0.04,"reload":0.06,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":17.81}, + "crop-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.15,"keys":true,"css":true,"renderKey":0.21,"drop":0.14,"reload":0.11,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":17}, + "crop-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"keys":true,"css":true,"renderKey":0.21,"drop":0.15,"reload":0.1,"render":0.27,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":17.21}, + "crop-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":18.8}, + "crop-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":17.41}, + "crop-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.43,"frameP95":17.4}, + "crop-tween-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":17.71}, + "crop-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.41}, + "crop-tween-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.21}, + "crop-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":19.4}, + "crop-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":17.71}, + "crop-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.57,"frameP95":18.5}, + "crop-tween-center-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":17.5}, + "crop-tween-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.6,"frameP95":19.11}, + "crop-tween-center-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":17.1}, + "crop-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.71}, + "crop-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.03,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":17.41}, + "crop-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.11,"drop":0.1,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":17.41}, + "crop-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":17}, + "crop-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17.3}, + "crop-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.1,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.8}, + "crop-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.05,"drop":0.06,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":18.61}, + "crop-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":18}, + "crop-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.12,"drop":0.08,"reload":0.08,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.87,"frameP95":17}, + "crop-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.05,"reload":0.05,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18.3}, + "crop-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":18.11}, + "crop-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.1,"drop":0.07,"reload":0.07,"render":0.27,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18.3}, + "crop-tween-px-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.09,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.79,"frameP95":18.6}, + "crop-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.36,"frameP95":17.11}, + "crop-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.07,"reload":0.09,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.24,"frameP95":17.3}, + "crop-tween-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":17.4}, + "crop-tween-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0,"reload":0.02,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":17.5}, + "crop-tween-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.03,"frameP95":17.3}, + "crop-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.06,"drop":0.08,"reload":0.08,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":19.2}, + "crop-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.05,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.3}, + "crop-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.09,"drop":0.08,"reload":0.07,"render":0.25,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":18.71}, + "crop-tween-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.06,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":19.1}, + "crop-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.02,"drop":0.02,"reload":0.04,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.36,"frameP95":18.71}, + "crop-tween-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.08,"drop":0.07,"reload":0.06,"render":0.24,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.44,"frameP95":17.31}, + "crop-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":18.1}, + "crop-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":17.3}, + "crop-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.28,"frameP95":18.5}, + "crop-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.03,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":17.91}, + "crop-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.04,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":17.8}, + "crop-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.13,"drop":0.13,"reload":0.09,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.99,"frameP95":17.21}, + "crop-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.36,"frameP95":18.91}, + "crop-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":17}, + "crop-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.44,"frameP95":17.91}, + "crop-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.04,"drop":0.07,"reload":0.07,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.21}, + "crop-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.03,"drop":0.02,"reload":0.05,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":18.3}, + "crop-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.14,"drop":0.12,"reload":0.13,"render":0.26,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":18.11}, + "move-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.84,"frameP95":17.81}, + "move-fromto-px-r0-nested-z100-on": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":5.53,"frameP95":19.31}, + "move-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.25,"frameP95":17.6}, + "move-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.42,"frameP95":18.31}, + "move-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":17.31}, + "move-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.42,"frameP95":17}, + "move-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.81,"frameP95":18.91}, + "move-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.7,"frameP95":17.7}, + "move-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.61}, + "move-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.71}, + "move-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":19.2}, + "move-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.2,"frameP95":17.9}, + "move-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.28,"frameP95":17.5}, + "move-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.17,"frameP95":18.61}, + "move-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":18.41}, + "move-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":19}, + "move-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":17.91}, + "move-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.77,"frameP95":19.2}, + "move-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":true,"css":true,"renderKey":0.05,"drop":135.76,"reload":135.76,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.89,"frameP95":18.7}, + "move-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":17.5}, + "move-fromto-px-r30-root-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":true,"css":true,"renderKey":0.05,"drop":135.74,"reload":135.74,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.6,"frameP95":19}, + "move-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.16,"frameP95":18.6}, + "move-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":62.34,"keys":true,"css":true,"renderKey":0.05,"drop":135.84,"reload":135.73,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":17.61}, + "move-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.75,"frameP95":19.1}, + "move-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.78,"frameP95":19.3}, + "move-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":17.41}, + "move-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":17.91}, + "move-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.5}, + "move-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":18.41}, + "move-hold-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":17.9}, + "move-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.27,"frameP95":20.21}, + "move-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":18.91}, + "move-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.2,"frameP95":17.21}, + "move-hold-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":17.7}, + "move-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":17.8}, + "move-hold-center-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.63,"frameP95":19.4}, + "move-hold-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.04,"frameP95":18.61}, + "move-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.6}, + "move-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":18.41}, + "move-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.8}, + "move-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":18.71}, + "move-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":17.11}, + "move-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.19,"frameP95":17.71}, + "move-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.91}, + "move-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":17.6}, + "move-hold-pct-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.3}, + "move-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":18.1}, + "move-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":17.6}, + "move-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":18.21}, + "move-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":18.11}, + "move-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.87,"frameP95":17.8}, + "move-hold-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":19.6}, + "move-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":19.9}, + "move-hold-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.41,"frameP95":17.21}, + "move-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.94,"frameP95":18.3}, + "move-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":17.71}, + "move-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":17.8}, + "move-hold-px-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, + "move-hold-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":19.21}, + "move-hold-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":17.9}, + "move-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":17.41}, + "move-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.66,"frameP95":17.5}, + "move-hold-xpercent-r0-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.91}, + "move-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.43,"frameP95":17.5}, + "move-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":19.5}, + "move-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":17.4}, + "move-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":19.81}, + "move-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.01,"frameP95":18.8}, + "move-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":18.3}, + "move-hold-xpercent-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, + "move-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.91,"frameP95":17.7}, + "move-hold-xpercent-r30-root-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.88,"frameP95":19}, + "move-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.28,"frameP95":18.41}, + "move-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.76,"frameP95":17.1}, + "move-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":16.91}, + "move-idle-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.6,"frameP95":17}, + "move-idle-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":17.9}, + "move-idle-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.21}, + "move-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.57,"frameP95":17.8}, + "move-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.5}, + "move-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":17.1}, + "move-idle-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.69,"frameP95":17.6}, + "move-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.81}, + "move-idle-center-r30-root-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.33,"frameP95":17.3}, + "move-idle-pct-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.74,"frameP95":19.8}, + "move-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":17.71}, + "move-idle-pct-r0-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.61}, + "move-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":17.4}, + "move-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":18.6}, + "move-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.32,"frameP95":17.4}, + "move-idle-pct-r30-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.55,"frameP95":18.8}, + "move-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":18.1}, + "move-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":17.11}, + "move-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.03,"frameP95":17.8}, + "move-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.89,"frameP95":17.4}, + "move-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":19.9}, + "move-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":17.6}, + "move-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.43,"frameP95":17.8}, + "move-idle-px-r0-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.81}, + "move-idle-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.83,"frameP95":18.31}, + "move-idle-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.4,"frameP95":18}, + "move-idle-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.69,"frameP95":17.9}, + "move-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":18.71}, + "move-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":19.21}, + "move-idle-px-r30-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.46,"frameP95":18.3}, + "move-idle-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.56,"frameP95":17.61}, + "move-idle-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":17.6}, + "move-idle-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.13,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":19.2}, + "move-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":18.81}, + "move-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":18.31}, + "move-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.43,"frameP95":17.91}, + "move-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.09,"frameP95":17.3}, + "move-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.78,"frameP95":17.41}, + "move-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.44,"frameP95":17.41}, + "move-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":108.17,"pressJump":0,"teleport":false,"teleportPx":116.62,"keys":false,"css":true,"renderKey":0.03,"drop":42.44,"reload":47.46,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":17.7}, + "move-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":18.2}, + "move-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":17.21}, + "move-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.78,"frameP95":17.5}, + "move-keys-px-r0-root-z50-mid": {"smooth":false,"tracking":108.17,"pressJump":0,"teleport":false,"teleportPx":110.01,"keys":false,"css":true,"renderKey":0.02,"drop":266.83,"reload":266.87,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.68,"frameP95":17.91}, + "move-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":18.1}, + "move-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":17.4}, + "move-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":17.81}, + "move-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":18.5}, + "move-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.59,"frameP95":19.11}, + "move-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0.1,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":18.7}, + "move-keys-px-r30-nested-z50-on": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.25,"frameP95":18.2}, + "move-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":false,"teleportPx":86.17,"keys":true,"css":true,"renderKey":0.03,"drop":159.91,"reload":159.91,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":18.41}, + "move-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":90.56,"keys":true,"css":true,"renderKey":0.03,"drop":168.54,"reload":168.54,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.43,"frameP95":17.81}, + "move-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":86.15,"keys":true,"css":true,"renderKey":0.03,"drop":159.95,"reload":159.96,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":20.2}, + "move-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":90.55,"keys":true,"css":true,"renderKey":0.03,"drop":168.57,"reload":168.56,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18}, + "move-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":false,"teleportPx":86.16,"keys":true,"css":true,"renderKey":0.03,"drop":159.91,"reload":159.91,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.47,"frameP95":18.61}, + "move-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":90.56,"keys":true,"css":true,"renderKey":0.03,"drop":168.65,"reload":168.64,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.44,"frameP95":17.61}, + "move-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.03,"frameP95":18.31}, + "move-none-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":18.7}, + "move-none-center-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":18.5}, + "move-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.25,"frameP95":18.1}, + "move-none-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":19.2}, + "move-none-center-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":19.71}, + "move-none-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":18.2}, + "move-none-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":21.1}, + "move-none-center-r30-nested-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":19}, + "move-none-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.81,"frameP95":19.5}, + "move-none-center-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.52,"frameP95":19.31}, + "move-none-center-r30-root-z50": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.86,"frameP95":18.3}, + "move-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.63,"frameP95":19}, + "move-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":18.4}, + "move-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":19}, + "move-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18}, + "move-none-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.56,"frameP95":20.4}, + "move-none-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.96,"frameP95":18}, + "move-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":19.9}, + "move-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":18.21}, + "move-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":18.2}, + "move-none-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.23,"frameP95":19.9}, + "move-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.01,"frameP95":18.21}, + "move-none-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":17.71}, + "move-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.03,"frameP95":19.1}, + "move-none-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.16,"frameP95":18}, + "move-none-px-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":19.6}, + "move-none-px-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.5,"frameP95":19.31}, + "move-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.5,"frameP95":20.5}, + "move-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":21.3}, + "move-none-px-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.38,"frameP95":18.2}, + "move-none-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.65,"frameP95":19.6}, + "move-none-px-r30-nested-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.03,"frameP95":19.9}, + "move-none-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.24,"frameP95":17.9}, + "move-none-px-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.61,"frameP95":20.5}, + "move-none-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.13,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":22.6}, + "move-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.21,"frameP95":18.1}, + "move-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":18.91}, + "move-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":18}, + "move-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":18.3}, + "move-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":17.61}, + "move-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":17.5}, + "move-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":20.21}, + "move-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":17.7}, + "move-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.47,"frameP95":19}, + "move-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":17.91}, + "move-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.62,"frameP95":18.1}, + "move-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.28,"frameP95":18.31}, + "move-scale-px-r30-nested-z100-mid": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.27,"frameP95":19}, + "move-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":20.41}, + "move-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.94,"frameP95":17.31}, + "move-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":18.1}, + "move-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":18.6}, + "move-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.8,"frameP95":17.6}, + "move-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.25,"frameP95":17.31}, + "move-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.49,"frameP95":17.91}, + "move-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.72,"frameP95":19.21}, + "move-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.06,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":19.21}, + "move-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.23,"frameP95":18.7}, + "move-scale-px-r30-root-z50-on": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.08,"undo":false,"dropped":1,"controlDropped":0,"workMax":8.25,"frameP95":18.8}, + "move-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":18.21}, + "move-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.07,"frameP95":17.1}, + "move-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.97,"frameP95":18.7}, + "move-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":18.41}, + "move-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.64,"frameP95":19.41}, + "move-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":18}, + "move-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":17.91}, + "move-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.08,"frameP95":18}, + "move-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":17.11}, + "move-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.83,"frameP95":17.5}, + "move-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.49,"frameP95":17.91}, + "move-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":17.5}, + "move-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":19.81}, + "move-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.41,"frameP95":19.3}, + "move-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":18.5}, + "move-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":17.81}, + "move-size-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.64,"frameP95":19}, + "move-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.11,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":18}, + "move-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":17.8}, + "move-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.41,"frameP95":18.1}, + "move-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.2,"frameP95":18.41}, + "move-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.55,"frameP95":19.5}, + "move-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18.21}, + "move-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.61}, + "move-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.83,"frameP95":18.91}, + "move-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.69,"frameP95":19.2}, + "move-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.09,"render":0.23,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.83,"frameP95":18.31}, + "move-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":18.9}, + "move-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.86,"frameP95":18.3}, + "move-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.34,"frameP95":17.6}, + "move-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.87,"frameP95":18}, + "move-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":18.6}, + "move-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.73,"frameP95":17.41}, + "move-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":18}, + "move-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.14,"frameP95":19.1}, + "move-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.13,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.95,"frameP95":19.2}, + "move-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.58,"frameP95":18.81}, + "move-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.2,"frameP95":17.81}, + "move-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":18.5}, + "move-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.71}, + "move-spin-px-r30-nested-z50-mid": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.81,"frameP95":17.41}, + "move-spin-px-r30-nested-z50-on": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.21,"frameP95":20}, + "move-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.7}, + "move-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":17.5}, + "move-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.86,"frameP95":17.8}, + "move-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.43,"frameP95":19.41}, + "move-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":18.2}, + "move-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.13,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":18.31}, + "move-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":18}, + "move-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.71}, + "move-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":18.1}, + "move-tween-center-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":18.41}, + "move-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.24,"frameP95":18.3}, + "move-tween-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.57,"frameP95":17.7}, + "move-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.23,"frameP95":20.6}, + "move-tween-center-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.3}, + "move-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":17.6}, + "move-tween-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":17.71}, + "move-tween-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":18}, + "move-tween-center-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.45,"frameP95":18.5}, + "move-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.45,"frameP95":18.4}, + "move-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":17.5}, + "move-tween-pct-r0-nested-z50": {"smooth":false,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.71}, + "move-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":17.41}, + "move-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.02,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":17.3}, + "move-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":17.21}, + "move-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":19.7}, + "move-tween-pct-r30-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.6}, + "move-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.1,"frameP95":17.6}, + "move-tween-pct-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.31}, + "move-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":18.21}, + "move-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.5}, + "move-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":19}, + "move-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":18}, + "move-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":16.91}, + "move-tween-px-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.01,"frameP95":17.5}, + "move-tween-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":18.7}, + "move-tween-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":17.3}, + "move-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.65,"frameP95":18.91}, + "move-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":18.3}, + "move-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.75,"frameP95":17.5}, + "move-tween-px-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, + "move-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":17.5}, + "move-tween-px-r30-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":17.71}, + "move-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.8,"frameP95":18.1}, + "move-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.61}, + "move-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.21}, + "move-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":18.41}, + "move-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.63,"frameP95":17.5}, + "move-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":17.11}, + "move-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.55,"frameP95":19.21}, + "move-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":17.61}, + "move-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":19.4}, + "move-tween-xpercent-r30-root-z100": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.61}, + "move-tween-xpercent-r30-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.37,"frameP95":18}, + "move-tween-xpercent-r30-root-z50": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.6,"frameP95":18}, + "nudge-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":18}, + "nudge-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":17}, + "nudge-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.63,"frameP95":17.31}, + "nudge-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.6,"frameP95":17.5}, + "nudge-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":19.21}, + "nudge-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.51,"frameP95":17.6}, + "nudge-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":17}, + "nudge-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.31,"frameP95":17.3}, + "nudge-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.01,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":17}, + "nudge-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.02,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17}, + "nudge-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.31}, + "nudge-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":18.5}, + "nudge-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":16.81}, + "nudge-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.01,"frameP95":17.4}, + "nudge-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.21,"frameP95":17.81}, + "nudge-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0.02,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.31}, + "nudge-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":17.1}, + "nudge-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.6}, + "nudge-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.05,"drop":87.92,"reload":87.92,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":18.31}, + "nudge-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.75,"frameP95":17.71}, + "nudge-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.05,"drop":87.91,"reload":87.89,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":17.5}, + "nudge-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17.41}, + "nudge-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.05,"drop":88.01,"reload":87.92,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":17.41}, + "nudge-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.31}, + "nudge-hold-center-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.93,"frameP95":17.41}, + "nudge-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.98,"frameP95":17.21}, + "nudge-hold-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":18.7}, + "nudge-hold-center-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17.3}, + "nudge-hold-center-r0-root-z200": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, + "nudge-hold-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":17.21}, + "nudge-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.43,"frameP95":18.8}, + "nudge-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":17.3}, + "nudge-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.35,"frameP95":17.21}, + "nudge-hold-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":17.21}, + "nudge-hold-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17.31}, + "nudge-hold-center-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.14,"frameP95":17.3}, + "nudge-hold-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":17.21}, + "nudge-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.58,"frameP95":18.1}, + "nudge-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.37,"frameP95":21.9}, + "nudge-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.94,"frameP95":17.21}, + "nudge-hold-pct-r0-root-z200": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.41}, + "nudge-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":16.91}, + "nudge-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":18.61}, + "nudge-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.41,"frameP95":18.21}, + "nudge-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":18.41}, + "nudge-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.51,"frameP95":16.91}, + "nudge-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":18.91}, + "nudge-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.43,"frameP95":19}, + "nudge-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.6}, + "nudge-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.43,"frameP95":17.2}, + "nudge-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.1,"frameP95":17.3}, + "nudge-hold-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":16.91}, + "nudge-hold-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17.41}, + "nudge-hold-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17.21}, + "nudge-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.53,"frameP95":19.61}, + "nudge-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.3}, + "nudge-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":18.5}, + "nudge-hold-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17}, + "nudge-hold-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.21}, + "nudge-hold-px-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.3}, + "nudge-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.25,"frameP95":17.21}, + "nudge-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.54,"frameP95":17.2}, + "nudge-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.41}, + "nudge-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.39,"frameP95":17.21}, + "nudge-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.44,"frameP95":17.1}, + "nudge-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.53,"frameP95":17.2}, + "nudge-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.49,"frameP95":19.91}, + "nudge-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":19.11}, + "nudge-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.4}, + "nudge-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.41}, + "nudge-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.16,"frameP95":17.21}, + "nudge-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":17.9}, + "nudge-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.99,"frameP95":17.3}, + "nudge-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.39,"frameP95":17.21}, + "nudge-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.1}, + "nudge-idle-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.6}, + "nudge-idle-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.5}, + "nudge-idle-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":17.1}, + "nudge-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":17.11}, + "nudge-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":17.3}, + "nudge-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.95,"frameP95":17.1}, + "nudge-idle-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.2}, + "nudge-idle-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.1}, + "nudge-idle-center-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":17.5}, + "nudge-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":19.21}, + "nudge-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":17.2}, + "nudge-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":17.8}, + "nudge-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.83,"frameP95":16.9}, + "nudge-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.6}, + "nudge-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":17.11}, + "nudge-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":16.9}, + "nudge-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.55,"frameP95":17.3}, + "nudge-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.81,"frameP95":18.8}, + "nudge-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.27,"frameP95":17.9}, + "nudge-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.19,"frameP95":17.3}, + "nudge-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.94,"frameP95":17.4}, + "nudge-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.73,"frameP95":18.71}, + "nudge-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.59,"frameP95":17.1}, + "nudge-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":18.21}, + "nudge-idle-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17}, + "nudge-idle-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17.1}, + "nudge-idle-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.99,"frameP95":17.1}, + "nudge-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":21.3}, + "nudge-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.31}, + "nudge-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.89,"frameP95":17.5}, + "nudge-idle-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.3}, + "nudge-idle-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.4,"frameP95":17.41}, + "nudge-idle-px-r30-root-z50": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.4}, + "nudge-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.83,"frameP95":19}, + "nudge-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.1}, + "nudge-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.35,"frameP95":17.5}, + "nudge-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17.41}, + "nudge-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.35,"frameP95":18.6}, + "nudge-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.21}, + "nudge-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.5}, + "nudge-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.83,"frameP95":17.3}, + "nudge-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.01,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":17.21}, + "nudge-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.55,"frameP95":17.41}, + "nudge-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":17.3}, + "nudge-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.5}, + "nudge-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.41}, + "nudge-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17}, + "nudge-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.55,"frameP95":17.81}, + "nudge-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.37,"frameP95":17.5}, + "nudge-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.41}, + "nudge-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.5}, + "nudge-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.29,"reload":108.29,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17}, + "nudge-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.19,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.41}, + "nudge-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.28,"reload":108.29,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":20.5}, + "nudge-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.17,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.89,"frameP95":17.41}, + "nudge-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":108.26,"reload":108.28,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.5}, + "nudge-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":118.19,"reload":118.15,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":18.1}, + "nudge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":17.4}, + "nudge-none-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":18}, + "nudge-none-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17.41}, + "nudge-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":18.71}, + "nudge-none-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":18.81}, + "nudge-none-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":17.9}, + "nudge-none-center-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.31}, + "nudge-none-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.75,"frameP95":17.6}, + "nudge-none-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17}, + "nudge-none-center-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":17.1}, + "nudge-none-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":17.6}, + "nudge-none-center-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.5}, + "nudge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.13,"frameP95":18.9}, + "nudge-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.54,"frameP95":17.1}, + "nudge-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.2}, + "nudge-none-pct-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":17.3}, + "nudge-none-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":17.3}, + "nudge-none-pct-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.81,"frameP95":17.4}, + "nudge-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.71}, + "nudge-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.3}, + "nudge-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":18.4}, + "nudge-none-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.14,"frameP95":18.4}, + "nudge-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.41,"frameP95":17.4}, + "nudge-none-pct-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":19.2}, + "nudge-none-px-r0-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":4.91,"frameP95":25.2}, + "nudge-none-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.86,"frameP95":17.5}, + "nudge-none-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.55,"frameP95":17.3}, + "nudge-none-px-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.23,"frameP95":17.4}, + "nudge-none-px-r0-root-z200": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.2}, + "nudge-none-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":18.3}, + "nudge-none-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.85,"frameP95":17.3}, + "nudge-none-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":18.1}, + "nudge-none-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.5}, + "nudge-none-px-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.93,"frameP95":20.1}, + "nudge-none-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":18.6}, + "nudge-none-px-r30-root-z50": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, + "nudge-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":17.2}, + "nudge-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":18.2}, + "nudge-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.11}, + "nudge-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.08,"frameP95":17.1}, + "nudge-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":17.6}, + "nudge-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.81}, + "nudge-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.86,"frameP95":17.31}, + "nudge-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":17.5}, + "nudge-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":17.11}, + "nudge-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.3}, + "nudge-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.62,"frameP95":17.61}, + "nudge-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":17.5}, + "nudge-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.5}, + "nudge-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":17.41}, + "nudge-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":17.41}, + "nudge-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":17.4}, + "nudge-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.41}, + "nudge-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.3}, + "nudge-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.85,"frameP95":18.6}, + "nudge-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.11}, + "nudge-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.3,"frameP95":17.4}, + "nudge-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.06,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":17.1}, + "nudge-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.08,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.14,"frameP95":18.1}, + "nudge-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.31}, + "nudge-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":20.6}, + "nudge-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":17.31}, + "nudge-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.56,"frameP95":17.31}, + "nudge-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":17.31}, + "nudge-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.25,"frameP95":17.31}, + "nudge-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":17.6}, + "nudge-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":17.1}, + "nudge-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.35,"frameP95":17.5}, + "nudge-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.01,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.5}, + "nudge-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":17.61}, + "nudge-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.68,"frameP95":17.11}, + "nudge-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":18}, + "nudge-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17.5}, + "nudge-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17}, + "nudge-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.6}, + "nudge-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.3}, + "nudge-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17}, + "nudge-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.11,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.21}, + "nudge-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":18.5}, + "nudge-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.71,"frameP95":17}, + "nudge-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":17.7}, + "nudge-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":17.5}, + "nudge-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.32,"frameP95":17.41}, + "nudge-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":17.5}, + "nudge-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":17.81}, + "nudge-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":17.2}, + "nudge-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.03,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":17.3}, + "nudge-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.21}, + "nudge-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.07,"render":0.22,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.8,"frameP95":17.3}, + "nudge-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.77,"frameP95":17}, + "nudge-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.5}, + "nudge-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.69,"frameP95":17.31}, + "nudge-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":17.11}, + "nudge-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":18.71}, + "nudge-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.18,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.6}, + "nudge-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.43,"frameP95":22.5}, + "nudge-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.41}, + "nudge-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.09,"frameP95":17.3}, + "nudge-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.96,"frameP95":17.31}, + "nudge-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":17.41}, + "nudge-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.17,"frameP95":17.21}, + "nudge-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":18}, + "nudge-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":19.1}, + "nudge-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":17.5}, + "nudge-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.5}, + "nudge-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17.1}, + "nudge-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":17.21}, + "nudge-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.52,"frameP95":17.6}, + "nudge-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.25,"frameP95":20.71}, + "nudge-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.64,"frameP95":18.4}, + "nudge-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.11}, + "nudge-tween-center-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.11,"frameP95":16.9}, + "nudge-tween-center-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.59,"frameP95":18.31}, + "nudge-tween-center-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.07,"frameP95":17.41}, + "nudge-tween-center-r30-nested-z100": {"smooth":false,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, + "nudge-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.47,"frameP95":19.5}, + "nudge-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.53,"frameP95":17.4}, + "nudge-tween-center-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.11}, + "nudge-tween-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.96,"frameP95":18.1}, + "nudge-tween-center-r30-root-z50": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, + "nudge-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.83,"frameP95":17.21}, + "nudge-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.74,"frameP95":17.21}, + "nudge-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.37,"frameP95":18.8}, + "nudge-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.9,"frameP95":16.81}, + "nudge-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":17.41}, + "nudge-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.04,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.16,"frameP95":17}, + "nudge-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":17.5}, + "nudge-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":17.31}, + "nudge-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.52,"frameP95":18.5}, + "nudge-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.41}, + "nudge-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":18.21}, + "nudge-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.06,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.12,"frameP95":20.9}, + "nudge-tween-px-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":16.9}, + "nudge-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":17.21}, + "nudge-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.42,"frameP95":17.3}, + "nudge-tween-px-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.98,"frameP95":16.8}, + "nudge-tween-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.44,"frameP95":17.31}, + "nudge-tween-px-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.46,"frameP95":17.31}, + "nudge-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":17.71}, + "nudge-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.8}, + "nudge-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.01,"frameP95":18.4}, + "nudge-tween-px-r30-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.88,"frameP95":19.5}, + "nudge-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.05,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.97,"frameP95":17.3}, + "nudge-tween-px-r30-root-z50": {"smooth":false,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, + "nudge-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.3,"frameP95":17}, + "nudge-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.28,"frameP95":17.1}, + "nudge-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.25,"frameP95":17.3}, + "nudge-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.43,"frameP95":17}, + "nudge-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":17.6}, + "nudge-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":17.4}, + "nudge-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.36,"frameP95":17.71}, + "nudge-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":21.5}, + "nudge-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.91,"frameP95":17.41}, + "nudge-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.02,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":16.8}, + "nudge-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.55,"frameP95":17.41}, + "nudge-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.01,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":21}, + "pathcircle-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.11,"frameP95":18.1}, + "pathcircle-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.07,"frameP95":18.2}, + "pathcircle-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.04,"frameP95":18.1}, + "pathcircle-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.55,"frameP95":17.9}, + "pathcircle-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":20.3}, + "pathcircle-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.97,"frameP95":17.7}, + "pathcircle-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":20}, + "pathcircle-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.66,"frameP95":17.3}, + "pathcircle-none-px-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, + "pathedge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.29,"frameP95":18.7}, + "pathedge-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.09,"frameP95":18.3}, + "pathedge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":17.6}, + "pathedge-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.9,"frameP95":18.3}, + "pathedge-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.25,"frameP95":19.2}, + "pathedge-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":17.1}, + "pathedge-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.68,"frameP95":18.4}, + "pathedge-none-px-r0-root-z50": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.02,"frameP95":18.4}, + "pathedge-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.59,"frameP95":17.8}, + "pathflick-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.1}, + "pathflick-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.95,"frameP95":17.1}, + "pathflick-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.92,"frameP95":20.9}, + "pathflick-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":17.6}, + "pathflick-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.47,"frameP95":18.6}, + "pathflick-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":17.4}, + "pathflick-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.47,"frameP95":17.9}, + "pathflick-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17}, + "pathflick-none-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.29,"frameP95":17.2}, + "pathpause-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.72,"frameP95":18}, + "pathpause-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.4,"frameP95":17.3}, + "pathpause-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.32,"frameP95":17.5}, + "pathpause-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.16,"frameP95":17.1}, + "pathpause-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.72,"frameP95":18.1}, + "pathpause-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":16.9}, + "pathpause-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.09,"frameP95":17.7}, + "pathpause-none-px-r0-root-z50": {"smooth":true,"tracking":0,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.71,"frameP95":17.9}, + "pathpause-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.44,"frameP95":18}, + "pathstray-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":17.2}, + "pathstray-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":17.3}, + "pathstray-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.06,"frameP95":18.4}, + "pathstray-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.1}, + "pathstray-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":17.8}, + "pathstray-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":18.6}, + "pathstray-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":18.3}, + "pathstray-none-px-r0-root-z50": {"smooth":true,"tracking":0,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.27,"frameP95":17.3}, + "pathstray-none-px-r30-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":17.7}, + "pathzigzag-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.6}, + "pathzigzag-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.73,"frameP95":17.2}, + "pathzigzag-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.5,"frameP95":18.6}, + "pathzigzag-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.13,"frameP95":18.5}, + "pathzigzag-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.41,"frameP95":17.4}, + "pathzigzag-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":17.3}, + "pathzigzag-none-px-r0-root-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18}, + "pathzigzag-none-px-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.17,"frameP95":17.2}, + "pathzigzag-none-px-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":17.4}, + "resize-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18}, + "resize-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":20.2}, + "resize-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.38,"frameP95":17.91}, + "resize-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.02,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.76,"frameP95":19.41}, + "resize-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":17.91}, + "resize-fromto-px-r0-nested-z50-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.21}, + "resize-fromto-px-r0-root-z100-mid": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.7}, + "resize-fromto-px-r0-root-z100-on": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, + "resize-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.01,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.67,"frameP95":17.9}, + "resize-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.77,"frameP95":17.81}, + "resize-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":18.91}, + "resize-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.01,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.27,"frameP95":18.1}, + "resize-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.23,"frameP95":18.21}, + "resize-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":17.7}, + "resize-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":18.81}, + "resize-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":18.21}, + "resize-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":17.4}, + "resize-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.48,"frameP95":18}, + "resize-fromto-px-r30-root-z100-mid": {"smooth":false,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":94.42,"keys":true,"css":true,"renderKey":0.03,"drop":136.77,"reload":136.77,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.5}, + "resize-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.15,"frameP95":18.71}, + "resize-fromto-px-r30-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":94.42,"keys":true,"css":true,"renderKey":0.03,"drop":136.73,"reload":136.76,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.07,"frameP95":18.7}, + "resize-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":18}, + "resize-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":94.43,"keys":true,"css":true,"renderKey":0.03,"drop":136.74,"reload":136.74,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.58,"frameP95":18}, + "resize-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":false,"css":true,"renderKey":0.03,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.97,"frameP95":17.7}, + "resize-hold-center-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.13,"frameP95":18.71}, + "resize-hold-center-r0-nested-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.62,"frameP95":18.71}, + "resize-hold-center-r0-nested-z50": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":9.58,"frameP95":18.1}, + "resize-hold-center-r0-root-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.17,"frameP95":19.11}, + "resize-hold-center-r0-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":18.5}, + "resize-hold-center-r0-root-z50": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.02,"frameP95":18.21}, + "resize-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.56,"frameP95":21.3}, + "resize-hold-center-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":18}, + "resize-hold-center-r30-nested-z50": {"smooth":false,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.41}, + "resize-hold-center-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.85,"frameP95":17.8}, + "resize-hold-center-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18.3}, + "resize-hold-center-r30-root-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":19}, + "resize-hold-pct-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.12,"frameP95":22}, + "resize-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.64,"frameP95":19.6}, + "resize-hold-pct-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":17.41}, + "resize-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.03,"frameP95":18.31}, + "resize-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.95,"frameP95":18.71}, + "resize-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.01,"frameP95":17.61}, + "resize-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.48,"frameP95":18.71}, + "resize-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.54,"frameP95":18.71}, + "resize-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":18.3}, + "resize-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":17.8}, + "resize-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.26,"frameP95":18.3}, + "resize-hold-pct-r30-root-z50": {"smooth":false,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.43,"frameP95":20.1}, + "resize-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":19.41}, + "resize-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":20.3}, + "resize-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":17.41}, + "resize-hold-px-r0-root-z100": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.71}, + "resize-hold-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.65,"frameP95":18.9}, + "resize-hold-px-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.07,"frameP95":17.7}, + "resize-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.78,"frameP95":20.21}, + "resize-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.79,"frameP95":19}, + "resize-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.08,"frameP95":19.3}, + "resize-hold-px-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.7,"frameP95":18.11}, + "resize-hold-px-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.36,"frameP95":18.3}, + "resize-hold-px-r30-root-z50": {"smooth":false,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.24,"frameP95":18.21}, + "resize-hold-xpercent-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":10.82,"frameP95":19.5}, + "resize-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.81,"frameP95":18.5}, + "resize-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":17.7}, + "resize-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.29,"frameP95":18.21}, + "resize-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.01,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.08,"frameP95":18}, + "resize-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":17.6}, + "resize-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.54,"frameP95":18.31}, + "resize-hold-xpercent-r30-nested-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":3,"controlDropped":0,"workMax":6.98,"frameP95":27.5}, + "resize-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.38,"frameP95":17.91}, + "resize-hold-xpercent-r30-root-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.4,"frameP95":19.2}, + "resize-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.39,"frameP95":18.4}, + "resize-hold-xpercent-r30-root-z50": {"smooth":false,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":9,"frameP95":19.8}, + "resize-idle-center-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.07,"frameP95":18}, + "resize-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":17.5}, + "resize-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":17.2}, + "resize-idle-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.74,"frameP95":19.1}, + "resize-idle-center-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.35,"frameP95":18}, + "resize-idle-center-r0-root-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":17.3}, + "resize-idle-center-r30-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.08,"frameP95":19}, + "resize-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.45,"frameP95":17.4}, + "resize-idle-center-r30-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.82,"frameP95":17.31}, + "resize-idle-center-r30-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":17.5}, + "resize-idle-center-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.9}, + "resize-idle-center-r30-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":18.5}, + "resize-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.83,"frameP95":20.81}, + "resize-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.71,"frameP95":18.1}, + "resize-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":17.4}, + "resize-idle-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":18.4}, + "resize-idle-pct-r0-root-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.25,"frameP95":18.4}, + "resize-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":17.21}, + "resize-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.42,"frameP95":18.71}, + "resize-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":18.3}, + "resize-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":17.31}, + "resize-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":17.8}, + "resize-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":18.3}, + "resize-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.96,"frameP95":18.6}, + "resize-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.16,"frameP95":17.71}, + "resize-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.89,"frameP95":18}, + "resize-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.6,"frameP95":19}, + "resize-idle-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":19}, + "resize-idle-px-r0-root-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.61,"frameP95":18.4}, + "resize-idle-px-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":18.3}, + "resize-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.02,"frameP95":18.41}, + "resize-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.58,"frameP95":17.9}, + "resize-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.43,"frameP95":18.1}, + "resize-idle-px-r30-root-z100": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":18}, + "resize-idle-px-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.69,"frameP95":18.4}, + "resize-idle-px-r30-root-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.92,"frameP95":17.6}, + "resize-keys-px-r0-nested-z100-mid": {"smooth":false,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.42,"frameP95":18.2}, + "resize-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.03,"frameP95":18.21}, + "resize-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":18.11}, + "resize-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.06,"frameP95":20.81}, + "resize-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.5,"frameP95":17.31}, + "resize-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.38,"frameP95":17.91}, + "resize-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":18.81}, + "resize-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.67,"frameP95":20.2}, + "resize-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":20}, + "resize-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":18.3}, + "resize-keys-px-r0-root-z50-mid": {"smooth":false,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.05,"render":0.02,"undo":false,"dropped":1,"controlDropped":0,"workMax":7.85,"frameP95":18.6}, + "resize-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.07,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.66,"frameP95":19}, + "resize-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.34,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":18.11}, + "resize-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.98,"frameP95":18.31}, + "resize-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.44,"frameP95":18.31}, + "resize-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.16,"frameP95":17.71}, + "resize-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.39,"pressJump":0,"teleport":true,"teleportPx":0.31,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":17.91}, + "resize-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.4,"pressJump":0,"teleport":true,"teleportPx":0.3,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.72,"frameP95":18.1}, + "resize-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":false,"teleportPx":109.23,"keys":true,"css":true,"renderKey":0.03,"drop":110.96,"reload":110.96,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.87,"frameP95":17.71}, + "resize-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":false,"teleportPx":116.92,"keys":true,"css":true,"renderKey":0.03,"drop":118.71,"reload":118.71,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.19,"frameP95":17.81}, + "resize-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":109.22,"keys":true,"css":true,"renderKey":0.03,"drop":111,"reload":110.99,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":19.3}, + "resize-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":116.92,"keys":true,"css":true,"renderKey":0.03,"drop":118.71,"reload":118.71,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.04,"frameP95":18.31}, + "resize-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.44,"pressJump":0,"teleport":false,"teleportPx":109.21,"keys":true,"css":true,"renderKey":0.03,"drop":110.96,"reload":110.97,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.23,"frameP95":17.5}, + "resize-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.42,"pressJump":0,"teleport":false,"teleportPx":116.95,"keys":true,"css":true,"renderKey":0.03,"drop":118.68,"reload":118.72,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.34,"frameP95":17.61}, + "resize-none-center-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.22,"frameP95":19.81}, + "resize-none-center-r0-nested-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.04,"frameP95":19}, + "resize-none-center-r0-nested-z50": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":9.7,"frameP95":19.9}, + "resize-none-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":19.6}, + "resize-none-center-r0-root-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":9.65,"frameP95":21.5}, + "resize-none-center-r0-root-z50": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.7,"frameP95":20.8}, + "resize-none-center-r30-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":11.07,"frameP95":18.6}, + "resize-none-center-r30-nested-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.3,"frameP95":20.3}, + "resize-none-center-r30-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.89,"frameP95":17.9}, + "resize-none-center-r30-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":18.7}, + "resize-none-center-r30-root-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.96,"frameP95":21}, + "resize-none-center-r30-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":18.6}, + "resize-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.05,"frameP95":18.6}, + "resize-none-pct-r0-nested-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.39,"frameP95":21.9}, + "resize-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.26,"frameP95":19.1}, + "resize-none-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.48,"frameP95":19.7}, + "resize-none-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":18.7}, + "resize-none-pct-r0-root-z50": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.37,"frameP95":21.6}, + "resize-none-pct-r30-nested-z100": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.76,"frameP95":23.9}, + "resize-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.55,"frameP95":18.1}, + "resize-none-pct-r30-nested-z50": {"smooth":false,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.18,"frameP95":17.91}, + "resize-none-pct-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.67,"frameP95":19.21}, + "resize-none-pct-r30-root-z200": {"smooth":false,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.16,"frameP95":20}, + "resize-none-pct-r30-root-z50": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.98,"frameP95":20.3}, + "resize-none-px-r0-nested-z100": {"smooth":false,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.7,"frameP95":22}, + "resize-none-px-r0-nested-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.72,"frameP95":20.5}, + "resize-none-px-r0-nested-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.76,"frameP95":18.9}, + "resize-none-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.45,"frameP95":17.71}, + "resize-none-px-r0-root-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.48,"frameP95":17.8}, + "resize-none-px-r0-root-z50": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.8,"frameP95":19.9}, + "resize-none-px-r30-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.69,"frameP95":18.8}, + "resize-none-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.46,"frameP95":19}, + "resize-none-px-r30-nested-z50": {"smooth":false,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.39,"frameP95":19}, + "resize-none-px-r30-root-z100": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":19.5}, + "resize-none-px-r30-root-z200": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":1,"controlDropped":0,"workMax":8.11,"frameP95":23.1}, + "resize-none-px-r30-root-z50": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":18.6}, + "resize-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.35,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.19,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.13,"frameP95":19.41}, + "resize-scale-px-r0-nested-z100-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.01,"drop":0.24,"reload":0.24,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.85,"frameP95":19.81}, + "resize-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.36,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.21,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.86,"frameP95":18.61}, + "resize-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.01,"drop":0.24,"reload":0.24,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.11,"frameP95":20}, + "resize-scale-px-r0-nested-z50-mid": {"smooth":false,"tracking":0.41,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.01,"drop":0.19,"reload":0.23,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.17,"frameP95":17.71}, + "resize-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":true,"css":true,"renderKey":0.01,"drop":0.28,"reload":0.28,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.52,"frameP95":17.7}, + "resize-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.19,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.37,"frameP95":17.91}, + "resize-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":true,"css":true,"renderKey":0.02,"drop":0.25,"reload":0.25,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.4,"frameP95":18.11}, + "resize-scale-px-r0-root-z200-mid": {"smooth":true,"tracking":0.33,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.19,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.65,"frameP95":18.2}, + "resize-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.02,"drop":0.26,"reload":0.27,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":18.41}, + "resize-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.37,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.14,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":18.41}, + "resize-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.02,"drop":0.19,"reload":0.24,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.05,"frameP95":18.21}, + "resize-scale-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.36,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.11,"drop":0.2,"reload":0.2,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.14,"frameP95":17.7}, + "resize-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.11,"drop":0.25,"reload":0.25,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.05,"frameP95":18.91}, + "resize-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.35,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.11,"drop":0.2,"reload":0.21,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.26,"frameP95":17.91}, + "resize-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.27,"keys":true,"css":true,"renderKey":0.11,"drop":0.24,"reload":0.24,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":18}, + "resize-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.46,"pressJump":0,"teleport":true,"teleportPx":0.34,"keys":true,"css":true,"renderKey":0.11,"drop":0.21,"reload":0.2,"render":0.13,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.95,"frameP95":18.91}, + "resize-scale-px-r30-nested-z50-on": {"smooth":false,"tracking":0.39,"pressJump":0,"teleport":true,"teleportPx":0.28,"keys":true,"css":true,"renderKey":0.11,"drop":0.26,"reload":0.28,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.03,"frameP95":20.4}, + "resize-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":true,"css":true,"renderKey":0.08,"drop":138.89,"reload":138.71,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.19,"frameP95":18.2}, + "resize-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":true,"css":true,"renderKey":0.08,"drop":148.2,"reload":148.05,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.78,"frameP95":18.31}, + "resize-scale-px-r30-root-z200-mid": {"smooth":false,"tracking":0.36,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":true,"css":true,"renderKey":0.08,"drop":138.86,"reload":138.67,"render":0.12,"undo":false,"dropped":1,"controlDropped":0,"workMax":6.65,"frameP95":20.2}, + "resize-scale-px-r30-root-z200-on": {"smooth":false,"tracking":0.28,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":true,"css":true,"renderKey":0.08,"drop":148.17,"reload":148.04,"render":0.02,"undo":false,"dropped":1,"controlDropped":0,"workMax":5.96,"frameP95":19.5}, + "resize-scale-px-r30-root-z50-mid": {"smooth":true,"tracking":0.39,"pressJump":0,"teleport":false,"teleportPx":138.71,"keys":true,"css":true,"renderKey":0.08,"drop":138.8,"reload":138.62,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.7,"frameP95":18}, + "resize-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":false,"teleportPx":148.01,"keys":true,"css":true,"renderKey":0.08,"drop":148,"reload":147.97,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":18.2}, + "resize-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.36,"frameP95":18}, + "resize-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.63,"frameP95":18.7}, + "resize-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.42,"frameP95":17.91}, + "resize-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.15,"frameP95":18.41}, + "resize-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.9,"frameP95":18.3}, + "resize-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.02,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.4,"frameP95":19}, + "resize-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":true,"css":true,"renderKey":0.03,"drop":120.37,"reload":120.37,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":7.3,"frameP95":18.2}, + "resize-size-px-r0-root-z100-on": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":true,"css":true,"renderKey":0.03,"drop":120.37,"reload":120.37,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.04,"frameP95":19.8}, + "resize-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.03,"drop":0,"reload":0.04,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":17.8}, + "resize-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":true,"css":true,"renderKey":0.03,"drop":120.38,"reload":120.37,"render":0.02,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.51,"frameP95":17.81}, + "resize-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":true,"css":true,"renderKey":0.03,"drop":120.39,"reload":120.36,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.18,"frameP95":20.3}, + "resize-size-px-r0-root-z50-on": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":false,"teleportPx":120.38,"keys":true,"css":true,"renderKey":0.03,"drop":120.34,"reload":120.37,"render":0.02,"undo":false,"dropped":1,"controlDropped":0,"workMax":7.71,"frameP95":17.91}, + "resize-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":18}, + "resize-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":19.6}, + "resize-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0.05,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.98,"frameP95":19.41}, + "resize-size-px-r30-nested-z200-on": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0.04,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.35,"frameP95":18.41}, + "resize-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.32,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.47,"frameP95":18.91}, + "resize-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.11,"drop":0,"reload":0.11,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.71,"frameP95":18.81}, + "resize-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.3,"reload":116.3,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.01,"frameP95":17.91}, + "resize-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.3,"reload":116.3,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.51,"frameP95":20.6}, + "resize-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.28,"reload":116.28,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.33,"frameP95":18.91}, + "resize-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.24,"reload":116.25,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.13,"frameP95":20}, + "resize-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.26,"reload":116.3,"render":0.01,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18}, + "resize-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":false,"teleportPx":116.27,"keys":true,"css":true,"renderKey":0.09,"drop":116.33,"reload":116.33,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.63,"frameP95":19}, + "resize-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.72,"frameP95":20.3}, + "resize-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.42,"frameP95":19.3}, + "resize-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.21,"frameP95":19.6}, + "resize-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.66,"frameP95":19.6}, + "resize-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.29,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.29,"frameP95":17.5}, + "resize-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.34,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.83,"frameP95":18.71}, + "resize-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":19.91}, + "resize-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.39,"frameP95":19.41}, + "resize-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.32,"frameP95":18.1}, + "resize-spin-px-r0-root-z200-on": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":8.26,"frameP95":17.71}, + "resize-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.07,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.28,"frameP95":20.71}, + "resize-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.6,"frameP95":20.31}, + "resize-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.23,"frameP95":18.5}, + "resize-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.08,"frameP95":18}, + "resize-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.93,"frameP95":18.1}, + "resize-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.77,"frameP95":17.7}, + "resize-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":17.91}, + "resize-spin-px-r30-nested-z50-on": {"smooth":false,"tracking":0.34,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.36,"frameP95":20.1}, + "resize-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.71,"frameP95":18.5}, + "resize-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":17.7}, + "resize-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.03,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":6.1,"frameP95":18.6}, + "resize-spin-px-r30-root-z200-on": {"smooth":false,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":1,"controlDropped":0,"workMax":7.14,"frameP95":22.6}, + "resize-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.17,"render":0.09,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":18.2}, + "resize-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.24,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.1,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.36,"frameP95":17.7}, + "resize-tween-center-r0-nested-z100": {"smooth":false,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.56,"frameP95":18.71}, + "resize-tween-center-r0-nested-z200": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.41}, + "resize-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.4}, + "resize-tween-center-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.87,"frameP95":17.7}, + "resize-tween-center-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":18.71}, + "resize-tween-center-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.99,"frameP95":18.21}, + "resize-tween-center-r30-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.21,"frameP95":19.8}, + "resize-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":18.91}, + "resize-tween-center-r30-nested-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.59,"frameP95":18.21}, + "resize-tween-center-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.48,"frameP95":17.8}, + "resize-tween-center-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":17.8}, + "resize-tween-center-r30-root-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.1,"frameP95":18.21}, + "resize-tween-pct-r0-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":8.19,"frameP95":18.9}, + "resize-tween-pct-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.18,"frameP95":18.3}, + "resize-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":19.8}, + "resize-tween-pct-r0-root-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.61}, + "resize-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.52,"frameP95":18.1}, + "resize-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.65,"frameP95":19.6}, + "resize-tween-pct-r30-nested-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.13,"frameP95":18.71}, + "resize-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.25,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":17.91}, + "resize-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.35,"frameP95":18}, + "resize-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":17.81}, + "resize-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.87,"frameP95":18.7}, + "resize-tween-pct-r30-root-z50": {"smooth":false,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.41,"frameP95":20}, + "resize-tween-px-r0-nested-z100": {"smooth":false,"tracking":0.22,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":1,"controlDropped":0,"workMax":7.55,"frameP95":18.3}, + "resize-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.02,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.44,"frameP95":20.91}, + "resize-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.31,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.07,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.58,"frameP95":17.71}, + "resize-tween-px-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.93,"frameP95":18.1}, + "resize-tween-px-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.78,"frameP95":19.5}, + "resize-tween-px-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":18.71}, + "resize-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.6,"frameP95":20.3}, + "resize-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.45,"frameP95":18.5}, + "resize-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.28,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.02,"frameP95":19.6}, + "resize-tween-px-r30-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.72,"frameP95":18.21}, + "resize-tween-px-r30-root-z200": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.04,"frameP95":18.31}, + "resize-tween-px-r30-root-z50": {"smooth":true,"tracking":0.3,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.06,"frameP95":18.5}, + "resize-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.02,"frameP95":18.4}, + "resize-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.97,"frameP95":19.1}, + "resize-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18.3}, + "resize-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.27,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.53,"frameP95":17.71}, + "resize-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.03,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.35,"frameP95":18.3}, + "resize-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.23,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.91,"frameP95":17.9}, + "resize-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.4,"frameP95":20.8}, + "resize-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.21,"frameP95":17.5}, + "resize-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.32,"frameP95":17.61}, + "resize-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":18.8}, + "resize-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.89,"frameP95":19}, + "resize-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.38,"pressJump":0,"teleport":true,"teleportPx":0.25,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7,"frameP95":18.3}, + "rotate-fromto-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":19.6}, + "rotate-fromto-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":17.6}, + "rotate-fromto-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":19.9}, + "rotate-fromto-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.5,"frameP95":17.81}, + "rotate-fromto-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.5}, + "rotate-fromto-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.05,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.34,"frameP95":17.21}, + "rotate-fromto-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.85,"frameP95":19.71}, + "rotate-fromto-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.69,"frameP95":17.41}, + "rotate-fromto-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.06,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.53,"frameP95":17.2}, + "rotate-fromto-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.85,"frameP95":17.7}, + "rotate-fromto-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":18.31}, + "rotate-fromto-px-r0-root-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.12,"frameP95":18.41}, + "rotate-fromto-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.37,"frameP95":17.1}, + "rotate-fromto-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":17.5}, + "rotate-fromto-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":17.5}, + "rotate-fromto-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":17.31}, + "rotate-fromto-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":20.81}, + "rotate-fromto-px-r30-nested-z50-on": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.11,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":18}, + "rotate-fromto-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.66,"frameP95":17.5}, + "rotate-fromto-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":17.41}, + "rotate-fromto-px-r30-root-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":13.16,"frameP95":18.61}, + "rotate-fromto-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.06,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.77,"frameP95":17.6}, + "rotate-fromto-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.33,"frameP95":17.81}, + "rotate-fromto-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.1,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":18}, + "rotate-hold-center-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.47,"frameP95":19.71}, + "rotate-hold-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.5}, + "rotate-hold-center-r0-nested-z50": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.08,"frameP95":20.4}, + "rotate-hold-center-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.97,"frameP95":17.71}, + "rotate-hold-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.62,"frameP95":18.3}, + "rotate-hold-center-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.72,"frameP95":17.5}, + "rotate-hold-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.61,"frameP95":19.5}, + "rotate-hold-center-r30-nested-z200": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.2}, + "rotate-hold-center-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.66,"frameP95":17.41}, + "rotate-hold-center-r30-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":19.5}, + "rotate-hold-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.12,"frameP95":17.7}, + "rotate-hold-center-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.14,"frameP95":18}, + "rotate-hold-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.51,"frameP95":19.91}, + "rotate-hold-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":17.21}, + "rotate-hold-pct-r0-nested-z50": {"smooth":false,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.6}, + "rotate-hold-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.52,"frameP95":17.41}, + "rotate-hold-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.41}, + "rotate-hold-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.45,"frameP95":17.6}, + "rotate-hold-pct-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.1,"frameP95":18.3}, + "rotate-hold-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":19.71}, + "rotate-hold-pct-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":17.21}, + "rotate-hold-pct-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":18.71}, + "rotate-hold-pct-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.58,"frameP95":18.41}, + "rotate-hold-pct-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.92,"frameP95":19.11}, + "rotate-hold-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.99,"frameP95":18.1}, + "rotate-hold-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.63,"frameP95":17.61}, + "rotate-hold-px-r0-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":18.5}, + "rotate-hold-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.33,"frameP95":17.61}, + "rotate-hold-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.71}, + "rotate-hold-px-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":17.61}, + "rotate-hold-px-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":20.21}, + "rotate-hold-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.69,"frameP95":18}, + "rotate-hold-px-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.5,"frameP95":17.5}, + "rotate-hold-px-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.85,"frameP95":19.41}, + "rotate-hold-px-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":18.21}, + "rotate-hold-px-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.07,"frameP95":17.4}, + "rotate-hold-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":18.9}, + "rotate-hold-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.06,"frameP95":17}, + "rotate-hold-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.05,"frameP95":17.61}, + "rotate-hold-xpercent-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.3,"frameP95":17.5}, + "rotate-hold-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.67,"frameP95":18.5}, + "rotate-hold-xpercent-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.21,"frameP95":17.4}, + "rotate-hold-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.51,"frameP95":18.21}, + "rotate-hold-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":18.5}, + "rotate-hold-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.41,"frameP95":18}, + "rotate-hold-xpercent-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":19.91}, + "rotate-hold-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.41}, + "rotate-hold-xpercent-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":17.81}, + "rotate-idle-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.4,"frameP95":19.61}, + "rotate-idle-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":1.92,"frameP95":17}, + "rotate-idle-center-r0-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.65,"frameP95":17.41}, + "rotate-idle-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.22,"frameP95":17.41}, + "rotate-idle-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":18}, + "rotate-idle-center-r0-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":17.4}, + "rotate-idle-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.5}, + "rotate-idle-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":19.3}, + "rotate-idle-center-r30-nested-z50": {"smooth":false,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":16.9}, + "rotate-idle-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.88,"frameP95":18}, + "rotate-idle-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":17.6}, + "rotate-idle-center-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":18.11}, + "rotate-idle-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18}, + "rotate-idle-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.66,"frameP95":17.1}, + "rotate-idle-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.89,"frameP95":19.7}, + "rotate-idle-pct-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.2}, + "rotate-idle-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.65,"frameP95":19}, + "rotate-idle-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.56,"frameP95":19.5}, + "rotate-idle-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.49,"frameP95":18.5}, + "rotate-idle-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.03,"frameP95":18.21}, + "rotate-idle-pct-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.26,"frameP95":17.4}, + "rotate-idle-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":17.9}, + "rotate-idle-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":20.5}, + "rotate-idle-pct-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.22,"frameP95":19.2}, + "rotate-idle-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":21}, + "rotate-idle-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.18,"frameP95":17}, + "rotate-idle-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":17.91}, + "rotate-idle-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.15,"frameP95":18.5}, + "rotate-idle-px-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.05,"frameP95":18.5}, + "rotate-idle-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.5}, + "rotate-idle-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.64,"frameP95":17.9}, + "rotate-idle-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":19.31}, + "rotate-idle-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.03,"frameP95":17.31}, + "rotate-idle-px-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":18.3}, + "rotate-idle-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.73,"frameP95":17.31}, + "rotate-idle-px-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.09,"frameP95":17.71}, + "rotate-keys-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.88,"frameP95":18.11}, + "rotate-keys-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.5}, + "rotate-keys-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.76,"frameP95":19.6}, + "rotate-keys-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.41}, + "rotate-keys-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.13,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":17.6}, + "rotate-keys-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.13,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3,"frameP95":17.3}, + "rotate-keys-px-r0-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":17.81}, + "rotate-keys-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.79,"frameP95":17.8}, + "rotate-keys-px-r0-root-z200-mid": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":17.2}, + "rotate-keys-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.6}, + "rotate-keys-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.54,"frameP95":18.91}, + "rotate-keys-px-r0-root-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.11,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.71}, + "rotate-keys-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.42,"frameP95":17.2}, + "rotate-keys-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":17.5}, + "rotate-keys-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.21,"frameP95":17.71}, + "rotate-keys-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.14,"frameP95":17.31}, + "rotate-keys-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.11,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.51,"frameP95":17.71}, + "rotate-keys-px-r30-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.63,"frameP95":18.7}, + "rotate-keys-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.71}, + "rotate-keys-px-r30-root-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":17.21}, + "rotate-keys-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":18}, + "rotate-keys-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":17.61}, + "rotate-keys-px-r30-root-z50-mid": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.38,"frameP95":17.21}, + "rotate-keys-px-r30-root-z50-on": {"smooth":true,"tracking":0.12,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.14,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.07,"frameP95":19.11}, + "rotate-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.42,"frameP95":17.5}, + "rotate-none-center-r0-nested-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.7}, + "rotate-none-center-r0-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.08,"frameP95":17.41}, + "rotate-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.47,"frameP95":17.1}, + "rotate-none-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":17.4}, + "rotate-none-center-r0-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":18.21}, + "rotate-none-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.71}, + "rotate-none-center-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.34,"frameP95":17.6}, + "rotate-none-center-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.26,"frameP95":17.1}, + "rotate-none-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":17.3}, + "rotate-none-center-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.94,"frameP95":20.6}, + "rotate-none-center-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.5,"frameP95":18.41}, + "rotate-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.23,"frameP95":17.5}, + "rotate-none-pct-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.49,"frameP95":17.1}, + "rotate-none-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":20.1}, + "rotate-none-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.54,"frameP95":18.2}, + "rotate-none-pct-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.82,"frameP95":18.5}, + "rotate-none-pct-r0-root-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":18.3}, + "rotate-none-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.84,"frameP95":18.4}, + "rotate-none-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.46,"frameP95":18.5}, + "rotate-none-pct-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.33,"frameP95":17.3}, + "rotate-none-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.28,"frameP95":21.5}, + "rotate-none-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":18.91}, + "rotate-none-pct-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.08,"frameP95":18.4}, + "rotate-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.8,"frameP95":19.7}, + "rotate-none-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.16,"frameP95":17.9}, + "rotate-none-px-r0-nested-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.52,"frameP95":19}, + "rotate-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.64,"frameP95":17.6}, + "rotate-none-px-r0-root-z200": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.08,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":6.08,"frameP95":21.4}, + "rotate-none-px-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.33,"frameP95":18.3}, + "rotate-none-px-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.56,"frameP95":18}, + "rotate-none-px-r30-nested-z200": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.01,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.73,"frameP95":19.6}, + "rotate-none-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.72,"frameP95":18.1}, + "rotate-none-px-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.6,"frameP95":18.6}, + "rotate-none-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.82,"frameP95":18.9}, + "rotate-none-px-r30-root-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.46,"frameP95":18.6}, + "rotate-none-transform-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.3}, + "rotate-none-transform-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.97,"frameP95":19.71}, + "rotate-none-transform-r30-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":17.5}, + "rotate-none-transform-r30-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.19,"frameP95":21.1}, + "rotate-scale-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.88,"frameP95":17.8}, + "rotate-scale-px-r0-nested-z100-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.74,"frameP95":20}, + "rotate-scale-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.05,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.85,"frameP95":17.91}, + "rotate-scale-px-r0-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.08,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.94,"frameP95":18.1}, + "rotate-scale-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.16,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.38,"frameP95":17.5}, + "rotate-scale-px-r0-nested-z50-on": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.11,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.8,"frameP95":17.41}, + "rotate-scale-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.96,"frameP95":17.81}, + "rotate-scale-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.14,"frameP95":18}, + "rotate-scale-px-r0-root-z200-mid": {"smooth":false,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.1}, + "rotate-scale-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.04,"render":0.07,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.25,"frameP95":17.61}, + "rotate-scale-px-r0-root-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.05,"render":0.17,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.3,"frameP95":17.91}, + "rotate-scale-px-r0-root-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.05,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.51,"frameP95":19.91}, + "rotate-scale-px-r30-nested-z100-mid": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, + "rotate-scale-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.52,"frameP95":17.6}, + "rotate-scale-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.18,"frameP95":17.6}, + "rotate-scale-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":17.6}, + "rotate-scale-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.24,"frameP95":17.6}, + "rotate-scale-px-r30-nested-z50-on": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":17.41}, + "rotate-scale-px-r30-root-z100-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":17.91}, + "rotate-scale-px-r30-root-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.28,"frameP95":17.5}, + "rotate-scale-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.03,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.53,"frameP95":17.3}, + "rotate-scale-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":20}, + "rotate-scale-px-r30-root-z50-mid": {"smooth":false,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.06,"drop":0,"reload":0.1,"render":0.04,"undo":false,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.11}, + "rotate-scale-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.11,"render":0.03,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.54,"frameP95":17.6}, + "rotate-size-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.52,"frameP95":19.3}, + "rotate-size-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.11,"frameP95":20.11}, + "rotate-size-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.81,"frameP95":17.41}, + "rotate-size-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.04,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.02,"frameP95":18.7}, + "rotate-size-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.07,"render":0.14,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.29,"frameP95":17.5}, + "rotate-size-px-r0-nested-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.1,"drop":0,"reload":0.14,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.42,"frameP95":17.11}, + "rotate-size-px-r0-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":17.5}, + "rotate-size-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.98,"frameP95":18}, + "rotate-size-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.02,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":17}, + "rotate-size-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.04,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.22,"frameP95":17.5}, + "rotate-size-px-r0-root-z50-mid": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.07,"render":0.12,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.63,"frameP95":17.21}, + "rotate-size-px-r0-root-z50-on": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.12,"drop":0,"reload":0.05,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.74,"frameP95":17.41}, + "rotate-size-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.22,"frameP95":16.91}, + "rotate-size-px-r30-nested-z100-on": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.57,"frameP95":17.5}, + "rotate-size-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.67,"frameP95":17.31}, + "rotate-size-px-r30-nested-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.17,"frameP95":17.11}, + "rotate-size-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.04,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":17.6}, + "rotate-size-px-r30-nested-z50-on": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.05,"drop":0,"reload":0.1,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.19,"frameP95":17.31}, + "rotate-size-px-r30-root-z100-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.41}, + "rotate-size-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.59,"frameP95":17.3}, + "rotate-size-px-r30-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.06,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.77,"frameP95":17}, + "rotate-size-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":19}, + "rotate-size-px-r30-root-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.07,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.28,"frameP95":17}, + "rotate-size-px-r30-root-z50-on": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.08,"drop":0,"reload":0.05,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.84,"frameP95":17.7}, + "rotate-spin-px-r0-nested-z100-mid": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.23,"frameP95":17.2}, + "rotate-spin-px-r0-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.22,"frameP95":18.6}, + "rotate-spin-px-r0-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.1,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.15,"frameP95":18.2}, + "rotate-spin-px-r0-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.97,"frameP95":17.41}, + "rotate-spin-px-r0-nested-z50-mid": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.07,"render":0.11,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.92,"frameP95":17.6}, + "rotate-spin-px-r0-nested-z50-on": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.35,"frameP95":17.31}, + "rotate-spin-px-r0-root-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":true,"css":true,"renderKey":0.05,"drop":50.03,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.78,"frameP95":18.61}, + "rotate-spin-px-r0-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":true,"css":true,"renderKey":0.05,"drop":50.03,"reload":50.03,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.82,"frameP95":17.3}, + "rotate-spin-px-r0-root-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":true,"css":true,"renderKey":0.05,"drop":50.01,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.12,"frameP95":17.41}, + "rotate-spin-px-r0-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":true,"css":true,"renderKey":0.05,"drop":50.01,"reload":50.03,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.06,"frameP95":18.31}, + "rotate-spin-px-r0-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":50,"keys":true,"css":true,"renderKey":0.05,"drop":50.04,"reload":50.03,"render":0.12,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.2,"frameP95":19}, + "rotate-spin-px-r0-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":false,"teleportPx":50.01,"keys":true,"css":true,"renderKey":0.05,"drop":50.04,"reload":50.02,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.39,"frameP95":18.3}, + "rotate-spin-px-r30-nested-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.3,"frameP95":17.1}, + "rotate-spin-px-r30-nested-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":17.6}, + "rotate-spin-px-r30-nested-z200-mid": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.31,"frameP95":17.5}, + "rotate-spin-px-r30-nested-z200-on": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.11,"frameP95":17.31}, + "rotate-spin-px-r30-nested-z50-mid": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.9,"frameP95":17.8}, + "rotate-spin-px-r30-nested-z50-on": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"keys":true,"css":true,"renderKey":0.09,"drop":0,"reload":0.1,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.9,"frameP95":17.61}, + "rotate-spin-px-r30-root-z100-mid": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":false,"teleportPx":25.85,"keys":true,"css":true,"renderKey":0.05,"drop":111.45,"reload":111.45,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.5}, + "rotate-spin-px-r30-root-z100-on": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":26.81,"keys":true,"css":true,"renderKey":0.05,"drop":113.69,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":2.95,"frameP95":17.41}, + "rotate-spin-px-r30-root-z200-mid": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":false,"teleportPx":8.78,"keys":true,"css":true,"renderKey":0.05,"drop":111.42,"reload":111.44,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.72,"frameP95":17.5}, + "rotate-spin-px-r30-root-z200-on": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":false,"teleportPx":10.76,"keys":true,"css":true,"renderKey":0.05,"drop":113.72,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":18.81}, + "rotate-spin-px-r30-root-z50-mid": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":false,"teleportPx":60.18,"keys":true,"css":true,"renderKey":0.05,"drop":111.48,"reload":111.49,"render":0.05,"undo":false,"dropped":0,"controlDropped":0,"workMax":3.2,"frameP95":17.21}, + "rotate-spin-px-r30-root-z50-on": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":false,"teleportPx":60.78,"keys":true,"css":true,"renderKey":0.05,"drop":113.69,"reload":113.69,"render":0.06,"undo":false,"dropped":0,"controlDropped":0,"workMax":5.33,"frameP95":17.61}, + "rotate-tween-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":19.8}, + "rotate-tween-center-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.01,"frameP95":17.8}, + "rotate-tween-center-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.5,"frameP95":20.6}, + "rotate-tween-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.92,"frameP95":17.2}, + "rotate-tween-center-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.41,"frameP95":17.6}, + "rotate-tween-center-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.02,"frameP95":17.9}, + "rotate-tween-center-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":6,"frameP95":19.61}, + "rotate-tween-center-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.85,"frameP95":17.91}, + "rotate-tween-center-r30-nested-z50": {"smooth":false,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.8}, + "rotate-tween-center-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.6}, + "rotate-tween-center-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":17.81}, + "rotate-tween-center-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.33,"frameP95":17.5}, + "rotate-tween-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.79,"frameP95":19}, + "rotate-tween-pct-r0-nested-z200": {"smooth":false,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17}, + "rotate-tween-pct-r0-nested-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.78,"frameP95":19}, + "rotate-tween-pct-r0-root-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.52,"frameP95":17.4}, + "rotate-tween-pct-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.48,"frameP95":17.6}, + "rotate-tween-pct-r0-root-z50": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.87,"frameP95":19.11}, + "rotate-tween-pct-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.9,"frameP95":19.11}, + "rotate-tween-pct-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.45,"frameP95":17.5}, + "rotate-tween-pct-r30-nested-z50": {"smooth":true,"tracking":0.09,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":1.91,"frameP95":17}, + "rotate-tween-pct-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.76,"frameP95":19.31}, + "rotate-tween-pct-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.09,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.86,"frameP95":17.8}, + "rotate-tween-pct-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.41,"frameP95":18.4}, + "rotate-tween-px-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.38,"frameP95":20}, + "rotate-tween-px-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.06,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.78,"frameP95":18.3}, + "rotate-tween-px-r0-nested-z50": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.1,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.13,"frameP95":18.8}, + "rotate-tween-px-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.49,"frameP95":17.71}, + "rotate-tween-px-r0-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.02,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.38,"frameP95":18.2}, + "rotate-tween-px-r0-root-z50": {"smooth":true,"tracking":0.08,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.05,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.53,"frameP95":18.31}, + "rotate-tween-px-r30-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.06,"frameP95":18.9}, + "rotate-tween-px-r30-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.07,"frameP95":20.1}, + "rotate-tween-px-r30-nested-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.07,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.64,"frameP95":18}, + "rotate-tween-px-r30-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.29,"frameP95":17.61}, + "rotate-tween-px-r30-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.04,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.1,"frameP95":17.8}, + "rotate-tween-px-r30-root-z50": {"smooth":true,"tracking":0.1,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.11,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.21,"frameP95":17.41}, + "rotate-tween-xpercent-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.62,"frameP95":18.8}, + "rotate-tween-xpercent-r0-nested-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2,"frameP95":17.21}, + "rotate-tween-xpercent-r0-nested-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.61,"frameP95":17.5}, + "rotate-tween-xpercent-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.02,"frameP95":17.1}, + "rotate-tween-xpercent-r0-root-z200": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.88,"frameP95":18}, + "rotate-tween-xpercent-r0-root-z50": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.78,"frameP95":17.5}, + "rotate-tween-xpercent-r30-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.11,"frameP95":18.41}, + "rotate-tween-xpercent-r30-nested-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.74,"frameP95":17.6}, + "rotate-tween-xpercent-r30-nested-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":2.48,"frameP95":17}, + "rotate-tween-xpercent-r30-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.15,"frameP95":17.71}, + "rotate-tween-xpercent-r30-root-z200": {"smooth":true,"tracking":0.01,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.03,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.91,"frameP95":18}, + "rotate-tween-xpercent-r30-root-z50": {"smooth":true,"tracking":0.11,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0.07,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.34,"frameP95":18.21}, + "seqab-none-center-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.52,"frameP95":18.6}, + "seqab-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.98,"frameP95":17.2}, + "seqab-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.98,"frameP95":17.1}, + "seqab-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.64,"frameP95":19}, + "seqab-none-px-r0-nested-z100": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.31,"frameP95":17.9}, + "seqab-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.59,"frameP95":17.7}, + "seqinflight-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5,"frameP95":17.8}, + "seqinflight-none-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.5}, + "seqinflight-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.81,"frameP95":17.7}, + "seqinflight-none-pct-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.58,"frameP95":17.3}, + "seqinflight-none-px-r0-nested-z100": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.58,"frameP95":17.4}, + "seqinflight-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":14.64,"frameP95":17.3}, + "seqnudge-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.74,"frameP95":18.1}, + "seqnudge-none-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":9.92,"frameP95":17.7}, + "seqnudge-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.77,"frameP95":17.6}, + "seqnudge-none-pct-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.2,"frameP95":18}, + "seqnudge-none-px-r0-nested-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.5}, + "seqnudge-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.6}, "seqnudgeundo-none-center-r0-nested-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, "seqnudgeundo-none-center-r0-root-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, "seqnudgeundo-none-pct-r0-nested-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, "seqnudgeundo-none-pct-r0-root-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, - "seqnudgeundo-none-px-r0-nested-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":1.95,"frameP95":15.9}, + "seqnudgeundo-none-px-r0-nested-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, "seqnudgeundo-none-px-r0-root-z100": {"smooth":true,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":0,"frameP95":null}, - "seqrepeat-none-center-r0-nested-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.85,"frameP95":17.6}, - "seqrepeat-none-center-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.2}, - "seqrepeat-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.29,"frameP95":17.5}, - "seqrepeat-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.49,"frameP95":17.8}, - "seqrepeat-none-px-r0-nested-z100": {"smooth":false,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":17.3}, - "seqrepeat-none-px-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.58,"frameP95":17.4}, - "seqresize-none-center-r0-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.44,"frameP95":17.9}, - "seqresize-none-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.14,"frameP95":19.7}, - "seqresize-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":13.71,"frameP95":18.9}, - "seqresize-none-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.24,"frameP95":17.4}, - "seqresize-none-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.61,"frameP95":18.2}, - "seqresize-none-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.19,"frameP95":18.3}, - "seqresizeundo-none-center-r0-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.86,"frameP95":18.6}, - "seqresizeundo-none-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.94,"frameP95":20.4}, - "seqresizeundo-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.92,"frameP95":18.9}, - "seqresizeundo-none-pct-r0-root-z100": {"smooth":false,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.3}, - "seqresizeundo-none-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.98,"frameP95":18.3}, - "seqresizeundo-none-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.66,"frameP95":18.2}, - "seqrotatenudge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.7,"frameP95":17.2}, - "seqrotatenudge-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.57,"frameP95":18.7}, - "seqrotatenudge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":17.2}, - "seqrotatenudge-none-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.04,"frameP95":18.4}, - "seqrotatenudge-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.36,"frameP95":17.2}, - "seqrotatenudge-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.64,"frameP95":17.4}, - "seqseek-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.79,"frameP95":17.9}, - "seqseek-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.25,"frameP95":17.7}, - "seqseek-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.75,"frameP95":18.6}, - "seqseek-none-pct-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.01,"frameP95":17.5}, - "seqseek-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.9,"frameP95":18.2}, - "seqseek-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.59,"frameP95":19}, - "sequndo-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":12.36,"frameP95":17.7}, - "sequndo-none-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":11.44,"frameP95":18.6}, - "sequndo-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18}, - "sequndo-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":15.34,"frameP95":18.8}, - "sequndo-none-px-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":14.18,"frameP95":18.7}, - "sequndo-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.51,"frameP95":18.5}, - "textedit-none-px-r0-nested-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":23.6}, - "textedit-none-px-r0-root-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":13.72,"frameP95":20.2}, - "textselect-none-px-r0-nested-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":23.6}, - "textselect-none-px-r0-root-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":1,"controlDropped":0,"workMax":14.14,"frameP95":25.3} + "seqrepeat-none-center-r0-nested-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.99,"frameP95":17.6}, + "seqrepeat-none-center-r0-root-z100": {"smooth":true,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.73,"frameP95":17.7}, + "seqrepeat-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":18.5}, + "seqrepeat-none-pct-r0-root-z100": {"smooth":true,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.27,"frameP95":17.3}, + "seqrepeat-none-px-r0-nested-z100": {"smooth":true,"tracking":0.07,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":1,"workMax":6.18,"frameP95":17.4}, + "seqrepeat-none-px-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":11.72,"frameP95":17.8}, + "seqresize-none-center-r0-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.73,"frameP95":19.1}, + "seqresize-none-center-r0-root-z100": {"smooth":false,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":10.06,"frameP95":18.6}, + "seqresize-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.31,"frameP95":17.5}, + "seqresize-none-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.8,"frameP95":18.4}, + "seqresize-none-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.28,"frameP95":17.9}, + "seqresize-none-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.22,"frameP95":17.8}, + "seqresizeundo-none-center-r0-nested-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":18.9}, + "seqresizeundo-none-center-r0-root-z100": {"smooth":true,"tracking":0.24,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.59,"frameP95":19.5}, + "seqresizeundo-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.94,"frameP95":18.7}, + "seqresizeundo-none-pct-r0-root-z100": {"smooth":true,"tracking":0.26,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.24,"frameP95":18.5}, + "seqresizeundo-none-px-r0-nested-z100": {"smooth":true,"tracking":0.21,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.69,"frameP95":19}, + "seqresizeundo-none-px-r0-root-z100": {"smooth":true,"tracking":0.23,"pressJump":0,"teleport":true,"teleportPx":0.24,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":5.17,"frameP95":17.8}, + "seqrotatenudge-none-center-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.54,"frameP95":17.2}, + "seqrotatenudge-none-center-r0-root-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.05,"undo":true,"dropped":0,"controlDropped":0,"workMax":3.3,"frameP95":17.6}, + "seqrotatenudge-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.02,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.22,"frameP95":17.3}, + "seqrotatenudge-none-pct-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.17,"frameP95":18.6}, + "seqrotatenudge-none-px-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.06,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.28,"frameP95":17.3}, + "seqrotatenudge-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.08,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.26,"frameP95":17.6}, + "seqseek-none-center-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.8,"frameP95":18.8}, + "seqseek-none-center-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.11,"frameP95":17.3}, + "seqseek-none-pct-r0-nested-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.02,"undo":true,"dropped":0,"controlDropped":0,"workMax":4.7,"frameP95":17.9}, + "seqseek-none-pct-r0-root-z100": {"smooth":false,"tracking":0.05,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":8.04,"frameP95":17.6}, + "seqseek-none-px-r0-nested-z100": {"smooth":true,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":6.05,"frameP95":17.7}, + "seqseek-none-px-r0-root-z100": {"smooth":true,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":7.32,"frameP95":18.5}, + "sequndo-none-center-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":15.65,"frameP95":18.2}, + "sequndo-none-center-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":14.37,"frameP95":17.9}, + "sequndo-none-pct-r0-nested-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.01,"undo":true,"dropped":3,"controlDropped":0,"workMax":13.65,"frameP95":20.2}, + "sequndo-none-pct-r0-root-z100": {"smooth":false,"tracking":0.06,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":12.88,"frameP95":18.4}, + "sequndo-none-px-r0-nested-z100": {"smooth":false,"tracking":0.04,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":0,"controlDropped":0,"workMax":15.34,"frameP95":18.2}, + "sequndo-none-px-r0-root-z100": {"smooth":false,"tracking":0.03,"pressJump":0,"teleport":true,"teleportPx":0.01,"drop":0,"reload":0,"render":0.04,"undo":true,"dropped":1,"controlDropped":0,"workMax":14.42,"frameP95":18.7}, + "textedit-none-px-r0-nested-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":18.1}, + "textedit-none-px-r0-root-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":2,"controlDropped":0,"workMax":13.85,"frameP95":31.4}, + "textselect-none-px-r0-nested-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":21.1}, + "textselect-none-px-r0-root-z100": {"smooth":false,"tracking":0,"pressJump":null,"teleport":true,"teleportPx":null,"text":true,"drop":0,"reload":0,"render":0.03,"undo":true,"dropped":0,"controlDropped":0,"workMax":null,"frameP95":23.5} } } diff --git a/packages/studio/tests/e2e/edit-accuracy/case.mjs b/packages/studio/tests/e2e/edit-accuracy/case.mjs index 5fb2dc36d3a..c706b978a64 100644 --- a/packages/studio/tests/e2e/edit-accuracy/case.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/case.mjs @@ -20,6 +20,7 @@ import { } from "./geometry.mjs"; import { frameSamplerScript, scoreTeleport, startFrames, stopFrames } from "./teleport.mjs"; import { terminateWindowsProcessTree } from "../../../../cli/src/utils/processTree.ts"; +import { installWebMcpHost } from "../webmcp-host.mjs"; export const VIEWPORT = { width: 1600, height: 900 }; const STEPS = 20; @@ -101,18 +102,11 @@ export async function stopServer(child) { await exited; } -/** Runs in the top frame before Studio: the WebMCP host plus a frame-interval and long-task recorder. */ +/** Runs in the top frame after installWebMcpHost("__editBench"): 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 }; + window.__editBench.rec = 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()); @@ -641,6 +635,7 @@ export async function controlDrag(browser, gesture) { try { const page = await context.newPage(); await page.setViewport(VIEWPORT); + await page.evaluateOnNewDocument(installWebMcpHost, "__editBench"); await page.evaluateOnNewDocument(instrumentPage); // The real drags run the frame sampler, so the control pays its cost too. await page.evaluateOnNewDocument(frameSamplerScript); @@ -794,6 +789,7 @@ export async function inStudio({ browser, spec, dir, files, url, evidence }, dri (evidence.shots[name] = await page.screenshot({ type: "jpeg", quality: 70 })); try { await page.setViewport(VIEWPORT); + await page.evaluateOnNewDocument(installWebMcpHost, "__editBench"); await page.evaluateOnNewDocument(instrumentPage); await page.evaluateOnNewDocument(frameSamplerScript); await page.goto(url); diff --git a/packages/studio/tests/e2e/edit-accuracy/ratchet.mjs b/packages/studio/tests/e2e/edit-accuracy/ratchet.mjs index 0e831cacc7f..da880d82e72 100644 --- a/packages/studio/tests/e2e/edit-accuracy/ratchet.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/ratchet.mjs @@ -55,10 +55,7 @@ export function bankable(runs) { * Cases a real Studio race flips run to run, with the PR fixing it: measured and listed every run, never gated. * The fixing PR deletes its own ids here and re-banks them in the same PR. */ -export const QUARANTINED = { - // A redo or undo write waits behind preview videos holding all of Chrome's connections to the host. - "seqnudge-none-pct-r0-nested-z100": "#4889", -}; +export const QUARANTINED = {}; /** Every run of every case: each shard's run plus the re-runs of the cases it flipped. */ // fallow-ignore-next-line complexity diff --git a/packages/studio/tests/e2e/fixtures/undo-socket-pool/hyperframes.json b/packages/studio/tests/e2e/fixtures/undo-socket-pool/hyperframes.json new file mode 100644 index 00000000000..5fb1d6d872f --- /dev/null +++ b/packages/studio/tests/e2e/fixtures/undo-socket-pool/hyperframes.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/hyperframes.json", + "registry": "https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry", + "paths": { + "blocks": "compositions", + "components": "compositions/components", + "assets": "assets" + } +} diff --git a/packages/studio/tests/e2e/fixtures/undo-socket-pool/index.html b/packages/studio/tests/e2e/fixtures/undo-socket-pool/index.html new file mode 100644 index 00000000000..0c9cf42fde8 --- /dev/null +++ b/packages/studio/tests/e2e/fixtures/undo-socket-pool/index.html @@ -0,0 +1,123 @@ + + + + + + + + +
+
+ + + + + + + + +
+ + diff --git a/packages/studio/tests/e2e/undo-socket-pool.mjs b/packages/studio/tests/e2e/undo-socket-pool.mjs new file mode 100644 index 00000000000..fda8c841a70 --- /dev/null +++ b/packages/studio/tests/e2e/undo-socket-pool.mjs @@ -0,0 +1,176 @@ +#!/usr/bin/env node +// An undo must not wait for a socket while the preview's paused videos hold Chrome's six per host. +// STUDIO_URL=http://localhost:5317/#project/undo-socket-pool STUDIO_PROJECT_DIR= node +// Generates any missing fixture video with ffmpeg and deletes what it generated. Prints evidence JSON. +import { execFileSync } from "node:child_process"; +import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { launchStudioChrome } from "./chrome-executable.mjs"; +import { installWebMcpHost } from "./webmcp-host.mjs"; + +const STUDIO_URL = process.env.STUDIO_URL; +const PROJECT_DIR = process.env.STUDIO_PROJECT_DIR; +const ROUNDS = Number(process.env.UNDO_ROUNDS || 3); +// Unpinned, the undo is sent in under 20 ms; behind pinned media it waited 780-961 ms. +const STALL_LIMIT_MS = Number(process.env.UNDO_STALL_LIMIT_MS || 250); +const VIDEOS = 8; + +if (!STUDIO_URL || !PROJECT_DIR) { + console.error("STUDIO_URL and STUDIO_PROJECT_DIR are required"); + process.exit(2); +} +mkdirSync(join(PROJECT_DIR, "assets"), { recursive: true }); +// 480 MB in all: whatever this run generated, it deletes when it ends. A caller may supply the videos instead. +const generated = []; +process.on("exit", () => generated.forEach((file) => rmSync(file, { force: true }))); +for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => process.exit(1)); +for (let i = 1; i <= VIDEOS; i++) { + const file = join(PROJECT_DIR, `assets/v${i}.mp4`); + if (existsSync(file)) continue; + generated.push(file); + // 60 MB each (constant 8 Mb/s for 60 s): more than Chrome buffers for a paused element, so its request stays open. + execFileSync("ffmpeg", [ + ...["-v", "error", "-y", "-f", "lavfi", "-i", "testsrc2=size=640x360:rate=10:duration=60"], + ...["-vf", `hue=h=${i * 40}`, "-pix_fmt", "yuv420p", "-c:v", "libx264", "-preset", "ultrafast"], + ...[ + "-b:v", + "8M", + "-minrate", + "8M", + "-maxrate", + "8M", + "-bufsize", + "2M", + "-x264-params", + "nal-hrd=cbr", + ], + ...["-g", "10", file], + ]); +} + +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); +const indexFile = join(PROJECT_DIR, "index.html"); +const readIndex = () => readFileSync(indexFile, "utf8"); +async function until(check, timeoutMs) { + for (const deadline = Date.now() + timeoutMs; Date.now() < deadline; await sleep(50)) { + if (await check()) return true; + } + return false; +} + +const { browser } = await launchStudioChrome(); +const failures = []; +const rounds = []; +try { + const page = await browser.newPage(); + await page.setViewport({ width: 1600, height: 900 }); + await page.evaluateOnNewDocument(installWebMcpHost, "__undoPool"); + const call = (name, input) => + Promise.race([ + page.evaluate((n, i) => window.__undoPool.call(n, i), name, input), + sleep(20_000).then(() => { + const waiting = [...requests.values()].filter( + (r) => !r.headers && !r.done && r.type !== "Media", + ); + throw new Error( + `${name} did not answer in 20 s; ${pinnedMedia()} media responses open, Studio requests with no ` + + `answer: ${waiting.map((r) => `${r.method} ${new URL(r.url).pathname}`).join(", ")}`, + ); + }), + ]); + + const origin = new URL(STUDIO_URL).origin; + const requests = new Map(); + const cdp = await page.createCDPSession(); + await cdp.send("Network.enable"); + await cdp.send("Page.enable"); + cdp.on("Network.requestWillBeSent", ({ requestId, request, type, frameId }) => { + if (request.url.startsWith(origin)) + requests.set(requestId, { url: request.url, method: request.method, type, frameId }); + }); + // Chrome cancels a replaced preview frame's media without a loadingFailed event; those sockets are free again. + const dropFrame = (frameId) => { + for (const r of requests.values()) + if (r.frameId === frameId && r.type === "Media") r.done = true; + }; + cdp.on("Page.frameDetached", ({ frameId }) => dropFrame(frameId)); + cdp.on("Page.frameNavigated", ({ frame }) => dropFrame(frame.id)); + cdp.on("Network.responseReceived", ({ requestId, response }) => { + const entry = requests.get(requestId); + if (entry) Object.assign(entry, { headers: true, timing: response.timing }); + }); + const finish = ({ requestId }) => { + const entry = requests.get(requestId); + if (entry) entry.done = true; + }; + cdp.on("Network.loadingFinished", finish); + cdp.on("Network.loadingFailed", finish); + // A socket is held by a response whose body is still being read. + // Chrome gives a host six sockets. Under the CLI the /api/events stream holds one, so five videos fill the rest; + // Vite's dev server sends live updates over its HMR WebSocket instead of SSE, so there all six must be videos. + const pinnedNeeded = () => + [...requests.values()].some((r) => r.type === "EventSource" && !r.done) ? 5 : 6; + const pinnedMedia = () => + [...requests.values()].filter((r) => r.type === "Media" && r.headers && !r.done).length; + + await page.goto(STUDIO_URL, { waitUntil: "domcontentloaded" }); + await page.waitForFunction(() => window.__undoPool?.has("studio_seek"), { timeout: 90_000 }); + await until(async () => (await call("studio_seek", { time: 1 }).catch(() => null))?.ok, 30_000); + const look = await call("studio_look", { limit: 50 }); + const target = (look.elements ?? []).find((element) => element.label === "Target"); + if (!target) + throw new Error(`studio_look found no #target: ${JSON.stringify(look).slice(0, 400)}`); + + const colors = ["#ff0000", "#00ff00", "#0000ff", "#ff00ff", "#00ffff"]; + for (let round = 0; round < ROUNDS; round++) { + const before = readIndex(); + await call("studio_set_style", { + handle: target.handle, + styles: { backgroundColor: colors[round % colors.length] }, + }); + if (!(await until(() => readIndex() !== before, 10_000))) + throw new Error(`round ${round}: the edit never reached disk`); + // Without pinned media the gate would pass on any build, so it refuses to measure. + if (!(await until(() => pinnedMedia() >= pinnedNeeded(), 30_000))) { + failures.push( + `round ${round}: only ${pinnedMedia()} media responses held open; the fixture must pin ${pinnedNeeded()}`, + ); + break; + } + const pinned = pinnedMedia(); + const seen = requests.size; + await page.evaluate(() => { + if (document.activeElement?.tagName === "IFRAME") document.activeElement.blur(); + }); + await page.keyboard.down("Control"); + await page.keyboard.press("z"); + await page.keyboard.up("Control"); + const step = () => + [...requests.values()] + .slice(seen) + .find((r) => r.method === "POST" && r.url.includes("/history/step")); + await until(() => step()?.done, 15_000); + const undo = step(); + const reverted = await until(() => readIndex() === before, 5_000); + const stallMs = undo?.timing ? Math.round(undo.timing.sendStart) : null; + rounds.push({ round, pinned, stallMs, reverted }); + // Round 0 is exempt until the fix for the first undo of a GSAP-free film, which takes back only part, lands. + if (!reverted && round > 0) failures.push(`round ${round}: the undo did not restore the file`); + if (stallMs == null) + failures.push(`round ${round}: the undo's POST history/step never answered`); + else if (stallMs > STALL_LIMIT_MS) + failures.push( + `round ${round}: the undo waited ${stallMs} ms for a socket (limit ${STALL_LIMIT_MS} ms) with ${pinned} media responses open`, + ); + await sleep(500); + } +} catch (error) { + failures.push(error instanceof Error ? error.message : String(error)); +} finally { + await browser.close(); +} +console.log(JSON.stringify({ stallLimitMs: STALL_LIMIT_MS, rounds, failures }, null, 2)); +if (failures.length > 0) { + for (const failure of failures) console.error(`FAIL: ${failure}`); + process.exit(1); +} diff --git a/packages/studio/tests/e2e/webmcp-host.mjs b/packages/studio/tests/e2e/webmcp-host.mjs new file mode 100644 index 00000000000..57c8059f954 --- /dev/null +++ b/packages/studio/tests/e2e/webmcp-host.mjs @@ -0,0 +1,13 @@ +/** Runs in the top frame before Studio: a WebMCP host whose registered tools `window[name]` can check and call. */ +export function installWebMcpHost(name) { + 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) }, + }); + window[name] = { + has: (tool) => tools.has(tool), + call: (tool, input) => tools.get(tool).execute(input, { signal: new AbortController().signal }), + }; +}