Speed up compositing and gesture start without behavior changes

- Memoize each operation's choreography effect set in a computed, so
  nodes sharing an edge stop re-evaluating it (linear, not quadratic,
  in chain depth).
- Cache the scene viewport and refresh it from a ResizeObserver and at
  each begin(), instead of measuring the container per node per frame.
- Index operations by origin key so outgoing lookups no longer scan
  every operation; all map changes go through attach()/detach().
- Resolve px and % gesture edge distances arithmetically; only other
  CSS lengths use the off-screen probe. Verified in Chromium to match
  the probe within its 1/64px layout rounding.

The differential suites against main still match exactly. Benchmarks
vs main: styleForNode 2.0x (3 live ops) and 2.4x (10 live ops),
rendered frames 1.14x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Faarh2Ts6StJPcz2mRiHiR
This commit is contained in:
Claude
2026-10-16 03:26:51 +00:00
parent 8448e910ed
commit 46f030630b
3 changed files with 112 additions and 39 deletions
+15 -4
View File
@@ -103,12 +103,16 @@ export const pointOf = (
const nonNegative = (value: number) =>
Number.isFinite(value) ? Math.max(0, value) : 0;
const PIXELS = /^\s*(-?(?:\d+\.?\d*|\.\d+))px\s*$/;
const PERCENT = /^\s*(-?(?:\d+\.?\d*|\.\d+))%\s*$/;
/**
* Resolve an arbitrary CSS length against a box with the gesture host's size.
* Resolve a CSS length against a box with the gesture host's size.
*
* A short-lived off-screen box lets the browser handle `rem`, viewport units,
* percentages, `calc()`, and `clamp()` consistently. This runs only during
* pointer-down for edge-constrained definitions.
* Numbers, pixel lengths, and percentages are computed directly. Anything
* else (`rem`, viewport units, `calc()`, `clamp()`) is measured with a
* short-lived off-screen box so the browser resolves it exactly. This runs
* only during pointer-down for edge-constrained definitions.
*/
export const resolveCssDistance = (
distance: OriginGestureDistance,
@@ -117,6 +121,13 @@ export const resolveCssDistance = (
bounds: OriginRect,
): number => {
if (typeof distance === "number") return nonNegative(distance);
const pixels = PIXELS.exec(distance);
if (pixels) return nonNegative(Number(pixels[1]));
const percent = PERCENT.exec(distance);
if (percent) {
const size = axis === "horizontal" ? bounds.width : bounds.height;
return nonNegative((Number(percent[1]) / 100) * size);
}
const document = host.ownerDocument;
if (!document.body) return Math.max(0, Number.parseFloat(distance) || 0);