Skip to content

feat(graph): scene interpreter prototype and scene bench - #454

Draft
draedful wants to merge 1 commit into
claude/webgl-connections-detachedfrom
claude/webgl-unified-scene
Draft

draedful wants to merge 1 commit into
claude/webgl-connections-detachedfrom
claude/webgl-unified-scene

Conversation

@draedful

@draedful draedful commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A research prototype for a unified scene renderer. It is a declarative scene of primitives drawn by a Canvas2D interpreter, plus a bench that compares it with today's component walk on Nirvana-sized graphs. It answers whether the data model alone, without WebGL, gives most of the frame-time win.

Nothing is exported from the package, and library behaviour is unchanged. The PR is stacked on #451.

Prototype (packages/graph/src/lib/scene, internal)

  • types.ts: primitives (rect, circle, text, icon, path, polygon) with scale visibility, and scene elements.
  • drawPrimitives.ts: drawElements() draws elements with Canvas2D.
    • Consecutive paths and polygons of one style share one fill and one stroke.
    • The run is capped by maxRun, because Chromium's Path2D.closePath() costs time in proportion to the path built so far.
  • SceneStore.ts: elements on a TileIndex, returned in (zIndex, sequence) order.
  • ScenePathBatch.ts: the paths and polygons of one z-level, cached per grid cell on the core BatchScene (cell 8192, chunk 200, chunk paths built with addPath), as BatchPath2DRenderer caches connections.
  • SceneCanvasLayer.ts: a layer that draws a store and its batches in z-order.

Bench (scripts/bench/culling/scene-run.mjs, scripts/bench/culling/scene/)

  • Scenes:
    • median: 130 blocks;
    • guarantee: 10k blocks, ~40k anchors, ~10k connections, 1k groups;
    • stress: 100k blocks.
  • Columns:
    • walk: core components with Nirvana-like canvas blocks;
    • interpreter: a SceneCanvasLayer over a SceneStore;
    • cached: the same with connections in a ScenePathBatch.
  • Measurements:
    • pan, zoom and drag on the scheduler tick, plus the synchronous action call;
    • frame intervals;
    • a pixel diff against walk;
    • optional CPU profiles.
  • Flags:
    • --renderers;
    • --run-cap;
    • --gpu: ANGLE Metal, as run.mjs uses. Without it, Playwright's Chromium rasterizes in software (SwiftShader).
    • --query-timing.

Results

GPU, Apple M3 Pro, guarantee scene, 1600×1000 view, pan. Main-thread tick in ms, mean of 40 actions, 3 repeats:

Scale walk interpreter (run cap 25) cached
0.038 (whole graph in view) 36.9 20.9 13.5
0.05 (59% of blocks) 22.6 14.1 8.2
  • Gap to 4 ms. cached removes 71–78% of the gap between walk and a 4 ms target. For any target from 0 ms up, the share stays at 63.5% or more.
  • Never slower. cached is not slower than walk in any of the 32 measured cells: guarantee, median and stress; pan, zoom and drag.
  • Frame intervals lag the tick. The p50 frame interval at 0.038 goes from 41.7 to 25.0 ms. About 5 ms per action falls outside the tick (raster, canvas flush); it is not attributed yet.
  • What remains. In the cached tick, about 84% is the per-element drawing of blocks and anchors (an estimate from one profile).
  • Bench limitation. The drag target is off-screen at scales 0.15–0.6, so those drag rows time a redraw with no visible change.

Test plan

  • pnpm --dir packages/graph exec jest: 1012 passed, 6 todo
  • pnpm --dir packages/graph exec tsc --noEmit -p tsconfig.json
  • pnpm --dir packages/graph exec eslint src/lib/scene
  • Bench files type-checked with a throw-away tsconfig that maps the bench's GRAPH / GRAPH_SRC aliases. The package tsconfig does not cover them.
  • node scripts/bench/culling/scene-run.mjs --gpu --scenes guarantee --scales 0.038,0.05 --renderers walk,interpreter,cached --run-cap 25 --repeats 3

🤖 Generated with Claude Code

Summary by Sourcery

Prototype an internal scene interpreter and benchmark its Canvas2D and cached-path rendering performance against the existing component walk.

New Features:

  • Add an internal declarative scene model and Canvas2D interpreter for rendering primitive-based graph scenes.
  • Add cached path and polygon batching for efficient rendering across grid cells and z-levels.
  • Add a benchmark harness comparing component walking, scene interpretation, and cached scene rendering across representative graph sizes and interactions.

Enhancements:

  • Support scale-aware primitive visibility, text sizing, draw-order management, viewport culling, and batched path rendering.
  • Provide scene stores with spatial indexing and mutation support for elements, including raising, updating, and deleting items.
  • Add pixel-diff validation, query timing, profiling, GPU selection, and configurable benchmark run caps.

Documentation:

  • Document the scene benchmark setup, renderer modes, measurement methodology, performance caveats, and command-line options.

Tests:

  • Add comprehensive unit tests covering primitive drawing, batching, scene storage, viewport handling, z-ordering, updates, and cache invalidation.

Adds an internal research prototype of a declarative scene (nothing is
exported from the package):

- packages/graph/src/lib/scene: primitive and element types, drawElements
  (Canvas2D drawing with run-batching of same-style paths, capped by
  maxRun), SceneStore (elements on a TileIndex in zIndex/sequence order),
  ScenePathBatch (paths and polygons of one z-level cached per cell on the
  core BatchScene, as BatchPath2DRenderer caches connections) and
  SceneCanvasLayer (draws a store and its batches in z-order).

Adds a scene bench next to the culling bench:

- scripts/bench/culling/scene-run.mjs and scene/: deterministic median,
  guarantee and stress scenes with a Nirvana-like look, drawn by three
  columns: walk (today's component tree), interpreter (SceneCanvasLayer
  over a SceneStore) and cached (connections in a ScenePathBatch). It times
  pan, zoom and drag on the scheduler tick plus the synchronous action,
  diffs the pictures against walk, and can record CPU profiles. Flags:
  --renderers, --run-cap, --gpu, --query-timing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 9, 2026

Copy link
Copy Markdown

Reviewer's Guide

Data structures

Define the scene primitives, visibility rules, element fields, and coordinate conventions that the store and renderer rely on.

  • packages/graph/src/lib/scene/types.ts L1-69

Store scene elements in a tile index and return visible elements in z-index and sequence order.

  • packages/graph/src/lib/scene/SceneStore.ts L1-84

Represent cached path and polygon elements as chunked, per-cell batch data with add, update, delete, and render operations.

  • packages/graph/src/lib/scene/ScenePathBatch.ts L1-178

Define the deterministic benchmark scenes, their block and connection data, and the shared visual primitives used to construct them.

  • scripts/bench/culling/scene/look.ts L1-222
  • scripts/bench/culling/scene/scenes.ts L1-170

Implementation

Draw scene primitives with Canvas2D, preserving ordering around shapes while batching compatible paths and polygons into capped runs.

  • packages/graph/src/lib/scene/drawPrimitives.ts L1-230

Implement the canvas layer that queries visible store elements and interleaves them with batches by z-index.

  • packages/graph/src/lib/scene/SceneCanvasLayer.ts L1-71

Build and run the browser benchmark, including renderer selection, timing, screenshots, pixel comparisons, and profiling options.

  • scripts/bench/culling/scene-run.mjs L1-312

Provide the benchmark’s browser harness and walk/interpreter adapters, including measured actions, scene setup, and query timing.

  • scripts/bench/culling/scene/entry.ts L1-210
  • scripts/bench/culling/scene/interpreter.ts L1-195
  • scripts/bench/culling/scene/sizes.check.ts L1-13
  • scripts/bench/culling/scene/walk.ts L1-155

Documentation

Explain the scene benchmark’s renderers, measurement methodology, limitations, and command-line options.

  • scripts/bench/culling/README.md L73-160

Tests

Check scene-layer visibility, batching, z-order, run limits, and camera-to-world viewport conversion.

  • packages/graph/src/lib/scene/SceneCanvasLayer.test.ts L1-249

Check cached path-batch construction, viewport culling, updates, validation, chunking, and rendering behavior.

  • packages/graph/src/lib/scene/ScenePathBatch.test.ts L1-215

Check scene-store ordering, visibility, movement, deletion, and duplicate-id handling.

  • packages/graph/src/lib/scene/SceneStore.test.ts L1-49

Check primitive visibility, text sizing, shape borders, path-run batching, and draw ordering.

  • packages/graph/src/lib/scene/drawPrimitives.test.ts L1-143

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gravity-ui-bot

Copy link
Copy Markdown
Contributor

Preview is ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants