diff --git a/.changeset/pixi-canvas-renderer.md b/.changeset/pixi-canvas-renderer.md new file mode 100644 index 00000000000..5f53d285d1c --- /dev/null +++ b/.changeset/pixi-canvas-renderer.md @@ -0,0 +1,5 @@ +--- +"@hashintel/petrinaut": patch +--- + +Add an experimental Pixi renderer for the canvas, selectable in the viewport settings dialog. diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md index 2c09ca8b344..e30dd76be40 100644 --- a/libs/@hashintel/petrinaut/docs/visual-settings.md +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -73,3 +73,14 @@ Choose how arcs are drawn between nodes: | **Square** | Right-angle paths (smoothstep routing). | | **Bezier** | Smooth curved paths. | | **Adaptive Bezier** | Curved paths that adjust based on node positions. (Default) | + +### Renderer (experimental) + +Choose which engine draws the canvas: + +| Renderer | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| **React Flow** | The default. Nodes and arcs are regular page elements. | +| **Pixi (GPU)** | Draws the net on a GPU-accelerated canvas. Stays smooth on large nets and during playback; some visual details differ slightly from React Flow. | + +Both renderers share the same nets, selection, tools and settings, so switching is safe at any time. The choice is saved with your other settings. diff --git a/libs/@hashintel/petrinaut/package.json b/libs/@hashintel/petrinaut/package.json index 6bcb0ebe27d..7a96f796839 100644 --- a/libs/@hashintel/petrinaut/package.json +++ b/libs/@hashintel/petrinaut/package.json @@ -70,12 +70,14 @@ "@hashintel/petrinaut-core": "workspace:^", "@hashintel/refractive": "workspace:^", "@monaco-editor/react": "4.8.0-rc.3", + "@pixi/react": "8.0.5", "@tanstack/react-form": "1.29.0", "@xyflow/react": "12.10.1", "ai": "6.0.182", "fuzzysort": "3.1.0", "lodash-es": "4.18.1", "monaco-editor": "0.55.1", + "pixi.js": "8.20.0", "react-markdown": "10.1.0", "react-resizable-panels": "4.6.5", "uplot": "1.6.32", diff --git a/libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts b/libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts index a8cdf2d7cf6..842df121446 100644 --- a/libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts +++ b/libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts @@ -18,6 +18,11 @@ import type { export type ArcRendering = "smoothstep" | "bezier" | "custom"; +/** Which engine draws the canvas. */ +export const canvasRendererNames = ["react-flow", "pixi"] as const; + +export type CanvasRendererName = (typeof canvasRendererNames)[number]; + export type SubViewSectionSettings = { collapsed: boolean; /** Last known panel height in pixels */ @@ -35,6 +40,7 @@ export type UserSettings = { keepPanelsMounted: boolean; compactNodes: boolean; arcRendering: ArcRendering; + canvasRenderer: CanvasRendererName; cursorMode: CursorMode; isLeftSidebarOpen: boolean; leftSidebarWidth: number; @@ -104,6 +110,7 @@ export type UserSettingsActions = { setKeepPanelsMounted: (value: boolean) => void; setCompactNodes: (value: boolean) => void; setArcRendering: (value: ArcRendering) => void; + setCanvasRenderer: (value: CanvasRendererName) => void; setIsLeftSidebarOpen: (value: boolean) => void; setLeftSidebarWidth: (value: number) => void; setPropertiesPanelWidth: (value: number) => void; @@ -139,6 +146,7 @@ export const defaultUserSettings: UserSettings = { keepPanelsMounted: true, compactNodes: false, arcRendering: "custom", + canvasRenderer: "react-flow", cursorMode: "pan", isLeftSidebarOpen: true, leftSidebarWidth: DEFAULT_LEFT_SIDEBAR_WIDTH, @@ -169,6 +177,7 @@ const DEFAULT_CONTEXT_VALUE: UserSettingsContextValue = { setKeepPanelsMounted: () => {}, setCompactNodes: () => {}, setArcRendering: () => {}, + setCanvasRenderer: () => {}, setIsLeftSidebarOpen: () => {}, setLeftSidebarWidth: () => {}, setPropertiesPanelWidth: () => {}, diff --git a/libs/@hashintel/petrinaut/src/react/state/user-settings-provider.tsx b/libs/@hashintel/petrinaut/src/react/state/user-settings-provider.tsx index 711b3ff67a9..e8f4253af98 100644 --- a/libs/@hashintel/petrinaut/src/react/state/user-settings-provider.tsx +++ b/libs/@hashintel/petrinaut/src/react/state/user-settings-provider.tsx @@ -14,6 +14,7 @@ import type { } from "./editor-context"; import type { ArcRendering, + CanvasRendererName, SubViewSectionSettings, UserSettings, } from "./user-settings-context"; @@ -74,6 +75,8 @@ export const UserSettingsProvider: React.FC = ({ setState((prev) => ({ ...prev, compactNodes: value })), setArcRendering: (value: ArcRendering) => setState((prev) => ({ ...prev, arcRendering: value })), + setCanvasRenderer: (value: CanvasRendererName) => + setState((prev) => ({ ...prev, canvasRenderer: value })), setCursorMode: (value: CursorMode) => setState((prev) => ({ ...prev, cursorMode: value })), setIsLeftSidebarOpen: (value: boolean) => diff --git a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/create-experiment-drawer.test.tsx b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/create-experiment-drawer.test.tsx index 6bd9572f759..e7dd6ed96ae 100644 --- a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/create-experiment-drawer.test.tsx +++ b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/create-experiment-drawer.test.tsx @@ -146,6 +146,7 @@ const TestProviders = ({ setShowCompilationOutput: () => {}, setEnableParameterSweeps: () => {}, setEnableOptimizationSurface: () => {}, + setCanvasRenderer: () => {}, setCanvasViewport: () => {}, updateSubViewSection: () => {}, }; diff --git a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderer.ts b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderer.ts index 40905368c1a..3918d126b1b 100644 --- a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderer.ts +++ b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderer.ts @@ -55,6 +55,5 @@ export type CanvasRendererProps = { export type CanvasRenderer = React.FC; -export const canvasRendererNames = ["react-flow"] as const; - -export type CanvasRendererName = (typeof canvasRendererNames)[number]; +/** The user setting that picks the renderer names the same engines. */ +export type { CanvasRendererName } from "../../../react/state/user-settings-context"; diff --git a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderers.ts b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderers.ts index 331aed8258f..52e790636e3 100644 --- a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderers.ts +++ b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderers.ts @@ -1,10 +1,10 @@ +import { PixiCanvas } from "./renderers/pixi/pixi-canvas"; import { ReactFlowCanvas } from "./renderers/react-flow/react-flow-canvas"; import type { CanvasRenderer, CanvasRendererName } from "./canvas-renderer"; -/** Every renderer the canvas view can mount, by name. */ +/** Every renderer the canvas view can mount, by the name the user setting stores. */ export const canvasRenderers: Record = { "react-flow": ReactFlowCanvas, + pixi: PixiCanvas, }; - -export const defaultCanvasRenderer: CanvasRendererName = "react-flow"; diff --git a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-settings-dialog.tsx b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-settings-dialog.tsx index 6bafe7fc747..0ee0daf8a3c 100644 --- a/libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-settings-dialog.tsx +++ b/libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-settings-dialog.tsx @@ -7,7 +7,10 @@ import { isWebGpuAvailable } from "@hashintel/petrinaut-core"; import { SDCPNContext } from "../../../../react/state/sdcpn-context"; import { UserSettingsContext } from "../../../../react/state/user-settings-context"; -import type { ArcRendering } from "../../../../react/state/user-settings-context"; +import type { + ArcRendering, + CanvasRendererName, +} from "../../../../react/state/user-settings-context"; const rowStyle = css({ display: "grid", @@ -94,6 +97,8 @@ export const ViewportSettingsDialog: React.FC = ({ setCompactNodes, arcRendering, setArcRendering, + canvasRenderer, + setCanvasRenderer, showMinimap, setShowMinimap, snapToGrid, @@ -174,6 +179,31 @@ export const ViewportSettingsDialog: React.FC = ({ ]} /> + + Renderer{" "} + + Experimental + + + } + description="Draw the canvas with React Flow or on a GPU-accelerated Pixi canvas" + > +