Skip to content

FE-1587: Add an experimental Pixi renderer for the canvas - #9509

Draft
kube wants to merge 2 commits into
mainfrom
claude/canvas-pixi-renderer
Draft

FE-1587: Add an experimental Pixi renderer for the canvas#9509
kube wants to merge 2 commits into
mainfrom
claude/canvas-pixi-renderer

Conversation

@kube

@kube kube commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Important

Experimental
Opt-in through the Renderer viewport setting.

Summary

Before this PR, the canvas had one renderer, React Flow. Every node is a DOM element and every hover, selection or playback frame re-renders the React tree, so nets of a thousand nodes stutter during playback.

Adds a Pixi.js renderer behind the canvas contract, chosen from Viewport settings > Renderer. It draws the same nets, tools, settings and playback animation as React Flow on a GPU canvas. Playback animation runs on the Pixi ticker as buffer writes instead of React re-renders.

9509.mp4

Links

Changes

Settings

  • canvasRenderer user setting with a Renderer row in the viewport settings dialog

    Values are react-flow and pixi, default React Flow.
    Row carries an Experimental chip.

Renderer shell

  • PixiCanvas mounts a Pixi Application inside a DOM host

    Host owns gestures, cursor, place-state tooltip, minimap and viewport controls.
    Declared as arch-docs layer ui.views.canvas.pixi.

  • Viewport store with React Flow's zoom limits and wheel factor

    Implements CanvasController, so the shared viewport controls and recenter hook work unchanged.

  • Opens on the net's saved viewport and saves each move once it settles

    Store reports every frame, so the renderer waits for the viewport to hold still and saves what is waiting when it unmounts.

  • SVG minimap and DOM tooltip

    Minimap drag pans the view.
    Tooltip shows the token state of the hovered place when frames exist.

  • Colours come from the Panda tokens on .petrinaut-root, labels from a bitmap font installed from Inter Variable once it has loaded
  • pixi.js and @pixi/react added as dependencies and Vite externals

Drawing

  • Nodes drawn with Graphics and BitmapText

    Compact and classic places and transitions, component instances, selection and hover outlines, dimming, token badges and firing bolts follow the React Flow visuals.

  • Arcs as one merged ribbon mesh with per-vertex width and colour

    Straight, square, bezier and adaptive bezier paths match the React Flow styles.
    Read arcs are dashed, inhibitor arcs get their disc, weights get labels, selected arcs get halos.

  • Firing animation writes buffers on the ticker

    A frame store mirrors the execution frame source.
    PixiAnimator drives pulse, flash and bolt timelines with useTick and updates token badges.

Interaction

  • Gestures handled on the DOM host with hit testing against scene geometry

    Pan by drag, middle button or Space, wheel zoom, node drag with snapping, partial or full box selection per setting, connect from handles with validation, click to place.

  • Same semantics as React Flow

    Every gesture ends in a useCanvasInteractions call, so selection, snapping and connection rules stay shared.

Known issues

  • Needs WebGL

    Pixi 8 has no canvas fallback, so a browser without WebGL gets no drawing. React Flow stays the default.

  • Bitmap font labels differ slightly from DOM text

    Weight and anti-aliasing are not identical to the React Flow nodes.

Next steps

  • Compare both renderers on large nets before deciding on a default

Test coverage

  • Existing canvas-scene.test.ts and canvas-viewport.test.ts:

    Scene and viewport math the renderer consumes. No renderer-specific automated tests.

  • Headless Playwright script against the production build:

    Drag, connect, box select, click to place, wheel zoom and pan, playback animation, minimap and tooltip.

How to test

  • Open Petrinaut preview on Vercel
  • Viewport controls > Settings > Renderer > Pixi
  • Load example > SIR
  • Add places, transitions and a component instance, connect ports, select and box select, drag with snap to grid
  • Viewport controls > Settings > switch arc style and compact nodes, toggle minimap
  • Simulate > Run, play back
  • Expect arcs to pulse and transitions to flash as with React Flow
  • Viewport controls > Settings > Renderer > React Flow
  • Expect same net and selection

@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 4, 2026 3:59pm UTC
petrinaut Ready Ready Preview Sep 4, 2026 3:59pm UTC
petrinaut-docs Ready Ready Preview Sep 4, 2026 3:59pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 4, 2026 3:59pm UTC

Request Review

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team labels Sep 2, 2026
@kube
kube force-pushed the claude/canvas-pixi-renderer branch from 91a9ed7 to 878fd81 Compare September 3, 2026 23:16
@kube
kube force-pushed the claude/canvas-pixi-renderer branch from 878fd81 to 0f0e186 Compare September 3, 2026 23:32
@kube
kube deployed to pull-request September 3, 2026 23:33 — with GitHub Actions Active
@kube
kube changed the base branch from claude/canvas-renderer-interface to main September 4, 2026 01:36
@kube
kube force-pushed the claude/canvas-pixi-renderer branch from 0f0e186 to e3b9741 Compare September 4, 2026 01:37
@kube
kube changed the base branch from main to claude/canvas-viewport-persistence September 4, 2026 01:37
@kube kube changed the title Add an experimental Pixi renderer for the canvas FE-1587: Add an experimental Pixi renderer for the canvas Sep 4, 2026
@kube
kube deployed to pull-request September 4, 2026 01:37 — with GitHub Actions Active
@kube
kube force-pushed the claude/canvas-pixi-renderer branch from e3b9741 to d6494e1 Compare September 4, 2026 02:07
kube added 2 commits September 4, 2026 15:40
The viewport store reports every frame of a gesture, and the shared provider
no longer coalesces, so the renderer waits for the viewport to hold still
and saves what is still waiting when it unmounts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

1 participant