From 7a01974404e60f03c70602ed453a9da21271d9df Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 13 Apr 2026 19:41:30 +0100 Subject: [PATCH 01/16] initial petrinaut docs --- libs/@hashintel/petrinaut/docs/README.md | 20 ++ .../petrinaut/docs/drawing-a-net.md | 122 ++++++++++++ libs/@hashintel/petrinaut/docs/examples.md | 118 ++++++++++++ .../petrinaut/docs/petri-net-extensions.md | 182 ++++++++++++++++++ libs/@hashintel/petrinaut/docs/simulation.md | 133 +++++++++++++ .../petrinaut/docs/useful-patterns.md | 140 ++++++++++++++ .../petrinaut/docs/visual-settings.md | 51 +++++ 7 files changed, 766 insertions(+) create mode 100644 libs/@hashintel/petrinaut/docs/README.md create mode 100644 libs/@hashintel/petrinaut/docs/drawing-a-net.md create mode 100644 libs/@hashintel/petrinaut/docs/examples.md create mode 100644 libs/@hashintel/petrinaut/docs/petri-net-extensions.md create mode 100644 libs/@hashintel/petrinaut/docs/simulation.md create mode 100644 libs/@hashintel/petrinaut/docs/useful-patterns.md create mode 100644 libs/@hashintel/petrinaut/docs/visual-settings.md diff --git a/libs/@hashintel/petrinaut/docs/README.md b/libs/@hashintel/petrinaut/docs/README.md new file mode 100644 index 00000000000..30423f5f555 --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/README.md @@ -0,0 +1,20 @@ +# Petrinaut User Guide + +Petrinaut is a visual editor for [Petri nets](https://en.wikipedia.org/wiki/Petri_net). + +It lets you build, configure, and simulate Petri nets. It has support for various extensions including types tokens (colours), continuous dynamics, and stochastic transitions. + +## Live site + +Petrinaut is available at [demo.petrinaut.org](https://demo.petrinaut.org). + +Net data will be stored in local browser storage. You can also export and import nets as JSON files for transfer between devices and browsers. + +## Contents + +- [Drawing a Net](drawing-a-net.md) -- Add nodes (places and transitions), connect them with arcs, and navigate the editor. +- [Petri Net Extensions](petri-net-extensions.md) -- Add types, dynamics, transition kernels, firing rules, and inhibitor arcs, as well as parameters and state visualizers. +- [Useful Patterns](useful-patterns.md) -- Common modelling techniques, including duration and resource pools. +- [Simulation](simulation.md) -- Set initial state, run the simulation, use the timeline, and control playback. +- [Visual Settings](visual-settings.md) -- Configure the editor appearance and behavior. +- [Examples](examples.md) -- Walkthrough of the built-in example nets. diff --git a/libs/@hashintel/petrinaut/docs/drawing-a-net.md b/libs/@hashintel/petrinaut/docs/drawing-a-net.md new file mode 100644 index 00000000000..e023f62af74 --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/drawing-a-net.md @@ -0,0 +1,122 @@ +# Drawing a Net + +## Editor layout + +The editor is organized around a central canvas where you build your net: + +- **Canvas** (center) -- the main workspace where places and transitions are displayed and connected. +- **Left sidebar** -- lists of entities organized into tabs: Nodes, Types, Differential Equations, Parameters. +- **Properties panel** (right) -- opens when you select an entity, showing its configurable properties. +- **Bottom panel** -- tabs for Diagnostics (code errors), Simulation Settings, and Timeline (during simulation). +- **Bottom toolbar** -- editing mode buttons and simulation controls. + + + +## Adding places and transitions + +Use the bottom toolbar to add nodes: + +- **Add Place** (shortcut: **N**) -- click the canvas to drop a place, or drag the button onto the canvas. +- **Add Transition** (shortcut: **T**) -- click the canvas to drop a transition, or drag the button onto the canvas. + +New nodes are named automatically (Place1, Place2, Transition1, etc.). Rename them by selecting the node and editing the name in the properties panel. + + + +## Connecting with arcs + +Drag from a node's handle to connect it: + +- **Place to Transition** creates an **input arc** (the transition consumes tokens from the place). +- **Transition to Place** creates an **output arc** (the transition produces tokens in the place). + +Petri nets are bipartite: you cannot connect a place to another place or a transition to another transition. New arcs default to weight 1. + + + +## Arc weight + +Select an arc to open its properties. Set the **weight** to control how many tokens are consumed (input) or produced (output) per firing. + +When weight is greater than 1, a label is displayed on the arc (e.g. "x2"). + +You can also edit an arc's weight via the properties panel for the transition it is connected to. + +See also: [arc weight for multi-token operations](useful-patterns.md#arc-weight-for-multi-token-operations). + +## Pan and Select modes + +The editor has two cursor modes, toggled from the bottom toolbar dropdown: + +| Mode | Shortcut | Behavior | +|------|----------|----------| +| **Pan** | H | Click and drag to pan the canvas. This is the default. | +| **Select** | V | Click and drag to draw a selection box around nodes. | + +With a selection, you can: + +- **Move** -- drag selected nodes to reposition them. +- **Delete** -- press **Backspace** or **Delete**. +- **Copy** -- **Cmd+C** (Mac) / **Ctrl+C** (Windows/Linux). +- **Paste** -- **Cmd+V** / **Ctrl+V**. + +Whether a node must be fully inside or only partially inside the selection box is configurable in [visual settings](visual-settings.md). + + + +## Left sidebar + +The left sidebar has four tabs for creating and managing entities: + +| Tab | Contents | +|-----|----------| +| **Nodes** | All places and transitions. Click to select and open properties. | +| **Types** | Token types (colours). Click **+** to create a new type. | +| **Differential Equations** | ODE definitions for continuous dynamics. Click **+** to create. | +| **Parameters** | Global parameters available in all user code. Click **+** to create. | + +Toggle the sidebar with the button in the top-left corner. + +## Search + +Press **Cmd+F** / **Ctrl+F** to open a search bar. Type to filter entities by name. Press **Escape** to close. + +## Undo / Redo + +Use the **Cmd+Z** / **Ctrl+Z** shortcut to undo the last action. Use the **Cmd+Shift+Z** / **Ctrl+Shift+Z** shortcut to redo the last action. + +The recent history is displayed in the top-right corner. Click on a history entry to go back to that state. + +## Keyboard shortcuts + +| Shortcut | Action | +|----------|--------| +| N | Add Place mode | +| T | Add Transition mode | +| H | Pan mode | +| V | Select mode | +| Escape | Clear selection, return to cursor mode | +| Cmd+A | Select all places and transitions | +| Cmd+C | Copy selection | +| Cmd+V | Paste | +| Cmd+Z | Undo | +| Cmd+Shift+Z | Redo | +| Cmd+F | Search | +| Delete / Backspace | Delete selection | + +## Snap to grid + +When enabled, node positions snap to a grid when placing or dragging. Toggle this in [visual settings](visual-settings.md). + +## Import and export + +From the hamburger menu (top-left): + +- **Export as JSON** -- saves the full net definition including positions and visual styling. +- **Export as JSON without visual info** -- strips node positions and type display colours. Useful for sharing the logical structure only. +- **Export as TikZ** -- generates a `.tex` file with a structural diagram. This is a simplified view: no colours, inhibitor arcs, dynamics, or token types are encoded. Intended for papers and presentations. +- **Import from JSON** -- loads a net from a `.json` file. If node positions are missing, an automatic layout is applied. + +## Auto-layout + +From the hamburger menu, select **Layout** to apply an automatic graph layout (ELK) that rearranges all nodes. Useful after importing a net without positions or when a net has become cluttered. This will not always be an improvement! diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md new file mode 100644 index 00000000000..e4d268a6203 --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -0,0 +1,118 @@ +# Examples + +Petrinaut includes several built-in example nets accessible from the **hamburger menu** (top-left) under **Load example**. They are listed below from simplest to most complex. + +## SIR Epidemic Model + +The classic Susceptible-Infected-Recovered compartmental model from epidemiology, implemented as a stochastic Petri net. + +**Demonstrates:** + +- **Stochastic firing rates** controlled by [global parameters](petri-net-extensions.md#global-parameters) (`infection_rate`, `recovery_rate`). +- **Arc weight > 1** -- the Infection transition consumes 1 Susceptible + 1 Infected and produces 2 Infected tokens, modelling the S+I -> 2I mass-action dynamics. +- Simple parameter-driven lambdas: `parameters.infection_rate` and `parameters.recovery_rate`. + +**Suggested initial state:** set Susceptible to **100** tokens, Infected to **1**, Recovered to **0**. All places are untyped, so you just set token counts. Press Play and watch the epidemic curve in the timeline. + +**Key concepts:** [stochastic firing](petri-net-extensions.md#stochastic-rate), [parameters](petri-net-extensions.md#global-parameters), [arc weight](useful-patterns.md#arc-weight-for-multi-token-operations). + + + +## Drug Production (Stochastic) + +A manufacturing pipeline from raw material suppliers through manufacturing, quality assurance, and shipping to a hospital. Products have a random `quality` attribute that determines whether they pass QA. + +**Demonstrates:** + +- **Typed place** -- QAQueue has a "Product" type with a `quality` dimension. +- **`Distribution.Uniform`** in a transition kernel to sample random quality at manufacturing time. +- **Competing predicate transitions** -- "Dispatch" fires when `quality >= threshold`, "Dispose" fires when `quality < threshold`, routing tokens to different output places. +- **Parameter-driven guard** -- the `quality_threshold` parameter controls the pass/fail boundary. + +**Suggested initial state:** set PlantASupply and PlantBSupply to **10** tokens each. Everything else starts empty. The stochastic "Deliver to Plant" transition will begin consuming from both suppliers once the simulation starts. + +**Key concepts:** [types](petri-net-extensions.md#types-colours), [distributions](petri-net-extensions.md#distributions), [competing transitions](useful-patterns.md#competing-transitions--routing). + + + +## Deployment Pipeline + +A software deployment process with incident handling. Deployments are created at a stochastic rate and proceed through a pipeline, but are blocked by incidents. + +**Demonstrates:** + +- **Inhibitor arcs** -- "Start Deployment" has inhibitor arcs from "IncidentBeingInvestigated" and "DeploymentInProgress", preventing new deployments while an incident is open or another deployment is running. +- **Source transitions** -- "Create Deployment" and "Incident Raised" have no input arcs, modelling Poisson arrivals at configurable rates. +- **Stochastic rates from parameters** -- `deployment_creation_rate`, `incident_rate`, `incident_resolution_rate`. + +**Suggested initial state:** no initial tokens needed -- all places can start empty. The source transitions "Create Deployment" and "Incident Raised" generate tokens at their stochastic rates. Just press Play. + +**Key concepts:** [inhibitor arcs](petri-net-extensions.md#inhibitor-arcs), [source transitions](useful-patterns.md#source-transitions-exogenous-arrivals), [mutual exclusion](useful-patterns.md#mutual-exclusion-with-inhibitor-arcs). + + + +## Production Machines + +A manufacturing system where machines produce goods, accumulate damage, break down, and are repaired by travelling technicians. + +**Demonstrates:** + +- **Multiple typed places** with three different types: Machine (`machine_damage_ratio`), MachineProducingProduct (`machine_damage_ratio`, `transformation_progress`), and Technician (`distance_to_site`). +- **Differential equations** on three places: production progress advancing, damage being repaired, and technicians travelling to the repair site. +- **Predicate guards** based on continuous state -- production completes when `transformation_progress >= 1`, repair finishes when `machine_damage_ratio <= 0`, technician arrives when `distance_to_site <= 0`. +- **Competing outcomes** -- "Production Success" (predicate) vs "Machine Fail" (stochastic with rate `machine_damage_ratio ** 100`, increasing sharply with accumulated damage). + +**Suggested initial state:** + +| Place | Tokens | Values | +|-------|--------|--------| +| RawMaterial | 100 | (untyped) | +| AvailableMachines | 3 | `machine_damage_ratio: 0` each | + +All other places start empty. "Start Production" will immediately consume a raw material and an available machine to begin. + +**Key concepts:** [dynamics](petri-net-extensions.md#differential-equations-dynamics), [resource pools](useful-patterns.md#resource-pools), predicate vs stochastic on competing transitions. + + + +## Satellites in Orbit + +An orbital mechanics simulation with satellites orbiting Earth, subject to collision and crash events. + +**Demonstrates:** + +- **Continuous dynamics** -- gravitational ODE computes acceleration, updating satellite position (`x`, `y`) and motion (`direction`, `velocity`) each step. +- **Custom place visualization** -- an SVG visualizer renders Earth, satellite positions, and velocity vectors in the properties panel. +- **Predicate transitions based on geometry** -- "Collision" checks distance between two satellites, "Crash" checks distance from Earth's surface. +- **Arc weight 2** on the "Collision" transition -- requires two satellites from the same place to evaluate pairwise proximity. +- **Parameters** for physical constants: `earth_radius`, `satellite_radius`, `gravitational_constant`, `crash_threshold`. + +**Suggested initial state:** add 3--5 satellite tokens to the Space place. Position them in a rough orbit around the origin (Earth is at 0,0). For example: + +| x | y | direction | velocity | +|---|---|-----------|----------| +| 80 | 0 | 1.57 | 70 | +| 0 | 100 | 3.14 | 55 | +| -60 | -60 | 0.78 | 80 | + +The velocity needed for a roughly circular orbit at radius `r` is approximately `sqrt(gravitational_constant / r)`. With the default `gravitational_constant` of 400000, that's about 71 at radius 80. Select the Space place and open the visualizer preview to watch the orbits. + +**Key concepts:** [dynamics](petri-net-extensions.md#differential-equations-dynamics), [visualizers](petri-net-extensions.md#visualizer), [arc weight](useful-patterns.md#arc-weight-for-multi-token-operations). + + + +## Probabilistic Satellites Launcher + +Extends the Satellites example with ongoing satellite launches at a stochastic rate. + +**Demonstrates:** + +- **Source transition** with stochastic rate -- "LaunchSatellite" has no inputs and fires at a constant rate, injecting new satellites into orbit. +- **`Distribution.Uniform` and `Distribution.Gaussian`** in the launch kernel for randomized initial conditions. +- **`Distribution.map()`** for coordinate conversion -- a uniform angle is sampled once, then `.map()` derives both `x` (cosine) and `y` (sine) from the same underlying sample for coherent polar-to-cartesian conversion. + +**Suggested initial state:** no initial tokens needed -- start with all places empty. The "LaunchSatellite" source transition fires at a rate of 1 per second, creating satellites with randomized orbital positions and velocities. Just press Play and watch the Space visualizer fill up. + +**Key concepts:** [source transitions](useful-patterns.md#source-transitions-exogenous-arrivals), [distributions and `.map()`](petri-net-extensions.md#distributions). + + diff --git a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md new file mode 100644 index 00000000000..0c6da7336ce --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md @@ -0,0 +1,182 @@ +# Petri Net Extensions + +Petrinaut extends basic Petri nets with typed tokens, continuous dynamics, stochastic firing, and more. This page covers each extension. + +## Typed vs untyped places + +By default, places hold **untyped tokens** -- they only track a count. Tokens are indistinguishable from each other. This is sufficient for simple flow models. + +To give tokens structure, assign a **type** to a place. Each token then carries named dimensions (e.g. `x`, `y`, `velocity`), enabling dynamics, visualization, and data-dependent transition logic. + +## Global parameters + +Parameters are named values available in all user-authored code: dynamics, lambdas, kernels, and visualizers. They are accessed via the `parameters` argument. + +**To create a parameter:** + +1. Open the **Parameters** tab in the left sidebar. +2. Click **+** to add a new parameter. +3. Set a **name** (display label), **variable name** (used in code), and **default value**. + + + +Override parameter values before running a simulation in the **Simulation Settings** panel (see [Simulation](simulation.md#simulation-settings)). This lets you experiment with different values without editing code. + +**Example:** the [SIR Epidemic Model](examples.md#sir-epidemic-model) defines `infection_rate` and `recovery_rate` as parameters, used in its transition lambdas. + +## Types (colours) + +A type defines the structure of tokens in a place: what dimensions they have and what data type each dimension holds. + +**To create a type:** + +1. Open the **Types** tab in the left sidebar. +2. Click **+** to add a new type. +3. Give it a **name** and **display colour**. +4. Add **dimensions** -- each has a name and a type (`real`, `integer`, or `boolean`). // TODO BEFORE ADDING DOCS: does this actually do anything? + + + +**To assign a type to a place:** select the place, then choose the type from the **Accepted token type** dropdown in the properties panel. + +Once a place has a type, its tokens are accessible in code as structured objects. For example, a type with dimensions `x` (real) and `y` (real) means each token is `{ x: number, y: number }`. + +## Differential equations (dynamics) + +Differential equations define how token data evolves continuously over time. They are integrated at each simulation step using the Euler method. + +**Setup:** + +1. Create a differential equation in the **Differential Equations** tab (left sidebar). +2. Associate it with a **type** (the equation applies to tokens of that type). +3. Select a place, enable **Dynamics**, and choose an equation that matches the type assigned to the place. + +**Function signature:** + +```ts +export default Dynamics((tokens, parameters) => { + return tokens.map(({ x, y }) => { + return { x: /* dx/dt */, y: /* dy/dt */ }; + }); +}); +``` + +The function receives the current token values and global parameters. It must return an array of derivative objects -- one per token, with the same dimension names. + + + +**Example:** in [Satellites in Orbit](examples.md#satellites-in-orbit), the orbital dynamics equation computes gravitational acceleration to update satellite position and velocity each step. + +## Visualizer + +A visualizer renders a custom view of a place's tokens during simulation. It is a React component that returns JSX (SVG is recommended). + +**To enable:** select a place, then toggle **Visualizer** in its properties. A code editor opens. + +```tsx +export default Visualization(({ tokens, parameters }) => { + return + {tokens.map(({ x, y }, i) => ( + + ))} + +}); +``` + +The component receives `tokens` (array of token objects) and `parameters` (global parameter values). It renders in the properties panel. During simulation, it updates live as token state changes. + + + +Use the menu in the code editor header to **Load default template** for a starting point. + +**Example:** the [Satellites in Orbit](examples.md#satellites-in-orbit) example includes a visualizer that renders Earth and orbiting satellites with velocity vectors. + +## Transition kernel + +The transition kernel defines how input tokens are transformed into output tokens when a transition fires. + +```ts +export default TransitionKernel((tokensByPlace, parameters) => { + return { + OutputPlace: [{ x: tokensByPlace.InputPlace[0].x + 1 }], + }; +}); +``` + +`tokensByPlace` is keyed by **place name**. Each value is an array of token objects from that input place. The return value is keyed by **output place name**, each containing an array of token objects to produce. + +### Distributions + +Kernel output values can be numbers or `Distribution` objects for stochastic output: + +- `Distribution.Gaussian(mean, standardDeviation)` +- `Distribution.Uniform(min, max)` +- `Distribution.Lognormal(mu, sigma)` + +Use `.map(fn)` to transform a sampled value: + +```ts +const angle = Distribution.Uniform(0, 2 * Math.PI); +return { + Space: [{ + x: angle.map(a => Math.cos(a) * 80), + y: angle.map(a => Math.sin(a) * 80), + }], +}; +``` + +The underlying random sample is drawn once and shared across chained `.map()` calls, so `x` and `y` above are derived from the same angle. + +### Empty kernels + +For transitions where all output places are **untyped**, the kernel code can be left empty. The engine produces the correct number of black tokens automatically. + +## Firing rate / predicate + +Each transition has a **firing rule** that controls when it fires, once structurally enabled (sufficient tokens in input places). Choose between two modes in the transition properties: + +### Predicate + +The function returns a **boolean**. The transition fires immediately when it returns `true`. + +```ts +export default Lambda((tokensByPlace, parameters) => { + return tokensByPlace.MyPlace[0].progress >= 1.0; +}); +``` + +Use predicates for deterministic guards based on token state. + +### Stochastic rate + +The function returns a **number** representing the average firing rate per second: + +- `0` -- disabled (will not fire). +- Any positive number -- average rate (e.g. `2.0` means roughly twice per second). +- `Infinity` -- fires immediately when enabled. + +```ts +export default Lambda((tokensByPlace, parameters) => { + return parameters.rate; +}); +``` + +## Inhibitor arcs + +An inhibitor arc is a special input arc that **prevents** a transition from firing when the source place has tokens equal to or greater than the arc weight -- the opposite of a normal arc. + +**To set:** select an input arc (place to transition) and switch its **Type** to **Inhibitor** in the properties panel. Only input arcs can be inhibitor. + +**Semantics:** the transition is enabled (on this arc) when the source place has **fewer tokens than the arc weight**. With the default weight of 1, this means the place must be empty. + +Inhibitor arcs **do not consume tokens** when the transition fires. + + + +**Example:** in [Deployment Pipeline](examples.md#deployment-pipeline), inhibitor arcs from "IncidentBeingInvestigated" and "DeploymentInProgress" block new deployments while an incident is open or a deployment is already running. + +## Diagnostics + +The **Diagnostics** tab in the bottom panel shows TypeScript errors in your code (dynamics, lambdas, kernels, visualizers), grouped by entity. Click a diagnostic to select the relevant entity and see the error in context. + +Diagnostics must be resolved before running a simulation -- pressing Play with unresolved errors opens the Diagnostics tab instead of starting the simulation. diff --git a/libs/@hashintel/petrinaut/docs/simulation.md b/libs/@hashintel/petrinaut/docs/simulation.md new file mode 100644 index 00000000000..a5056c5060f --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/simulation.md @@ -0,0 +1,133 @@ +# Simulation + +## Initial state + +Before running a simulation, set the **initial marking** -- the starting tokens in each place. + +Select a place and open the **State** sub-view in its properties: + +- **Untyped places** -- set a token count (integer). +- **Typed places** -- define individual tokens with values for each dimension in a spreadsheet editor. + + + +If no initial marking is set, a place starts empty (zero tokens). + +## Simulation settings + +Open the **Simulation Settings** tab in the bottom panel to configure: + +### Parameters + +Override [global parameter](petri-net-extensions.md#global-parameters) values for this run. Each parameter shows its name, variable name, and a value input (pre-filled with the default). Changes here do not modify the parameter definition -- they only apply to the simulation. + +Parameter values are locked while a simulation is running. Reset the simulation to change them. + +### Time step (dt) + +The time step in seconds per frame. Controls the resolution of ODE integration and how frequently transitions are evaluated. + +- **Smaller dt** -- finer approximation, but slower computation. +- **Larger dt** -- faster, but less accurate for continuous dynamics. + +Default: `0.1` seconds. + +### ODE solver + +The numerical method for integrating differential equations. Currently only **Euler** is available. + +## Running a simulation + +Press **Play** in the bottom toolbar. The simulation: + +1. Initializes with a random seed, the current dt, and parameter values. +2. Computes frames in a background Web Worker. +3. Streams frames to the UI for playback. + +If there are unresolved [diagnostics](petri-net-extensions.md#diagnostics) (code errors), pressing Play opens the Diagnostics tab instead of starting the simulation. Fix all errors first. + + + +## How a frame is computed + +Each simulation step proceeds in two phases: + +1. **Continuous dynamics** -- for every place with dynamics enabled, the differential equation is integrated one step (Euler method, step size = dt). This updates all token dimension values. + +2. **Discrete transitions** -- transitions are evaluated in definition order (deterministic, not random). For each transition: + - Check structural enablement (enough tokens in input places, inhibitor conditions met). + - Evaluate the lambda (predicate or stochastic rate). + - If the transition fires, remove input tokens **immediately** (subsequent transitions see the updated state). + + All produced output tokens are added at the end of the step. + +Simulation time advances by `dt` each frame. + +## Deadlock + +If no transition fires in a step **and** no transition is structurally enabled (regardless of lambda values), the simulation reports **deadlock** and stops (a "Simulation Complete" message is shown). + +This only stops computation: the simulation will continue to playback computed frames until no more are available. + +If transitions are structurally enabled but their lambdas prevent firing, the simulation continues stepping. + +## Playback controls + +The bottom toolbar provides playback controls: + +| Control | Description | +|---------|-------------| +| **Play** | Start or resume playback. | +| **Pause** | Pause at the current frame. | +| **Stop / Reset** | Stop playback and reset to frame 0. | + +The frame counter shows the current frame number, total frames, and elapsed simulation time. + + + +### Speed + +Choose a playback speed multiplier: **1x**, **2x**, **5x**, **10x**, **30x**, **60x**, **120x**, or **Max** (as fast as possible). + +### Play mode + +Controls how computation and playback interact: + +| Mode | Behavior | +|------|----------| +| **Play computed steps only** | Replay already-computed frames without further computation. | +| **Play + compute buffer** | Compute only a small buffer ahead of the playhead. | +| **Play + compute max** | Compute frames as fast as possible while playing. | + +### Stopping condition + +- **Run indefinitely** -- simulation continues until manually paused or deadlock. +- **End at fixed time** -- simulation stops after a set number of seconds (simulation time). + +Stopping conditions are **locked after the simulation starts**. Reset the simulation to change them. + +## Timeline + +The **Timeline** tab appears in the bottom panel during and after simulation. It shows token counts per place over time as a chart. + + + +- **Chart type** -- toggle between **Run** (line chart) and **Stacked** (area chart) using the control in the tab header. +- **Scrub** -- click or drag on the chart to jump to any frame. A playhead indicator shows the current position. +- **Legend** -- click place names to show/hide individual traces. Hover to dim other traces. + +## Viewing state during simulation + +Select a place during simulation to see its current token values in the properties panel. For typed places, individual token dimension values are displayed. + +If the place has a [visualizer](petri-net-extensions.md#visualizer) defined, it renders live in the properties panel, updating as the simulation progresses. + + + +## Locked editing + +The editor is **read-only** during simulation and after a simulation completes. You cannot add, remove, or modify nodes, arcs, types, or code while a simulation exists. + +Press **Stop / Reset** to return to editing mode. + +At the last frame of a completed simulation, Play is disabled -- reset to replay from the beginning. diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md new file mode 100644 index 00000000000..c1401867af4 --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -0,0 +1,140 @@ +# Useful Patterns + +Useful modelling techniques for Petri nets in Petrinaut. + +## Modelling duration (exponential) + +For processes with **exponentially distributed** duration, set the transition's stochastic firing rate to `1 / mean_duration`. The exponential distribution is built into the stochastic firing mechanism -- no extra setup needed. + +```ts +export default Lambda((tokensByPlace, parameters) => { + return 1 / parameters.mean_repair_time; +}); +``` + +This is the simplest way to model duration and works well for many processes (service times, failure intervals, etc.). + +## Modelling duration (non-exponential) + +For other distributions (e.g. log-normal, deterministic), place dynamics and durations sampled in the preceding transition kernel can be used. The general approach: + +1. **Add a time dimension** to the token type (e.g. `remaining_time`). +2. **Sample the duration** in a transition kernel using a `Distribution`: + +```ts +export default TransitionKernel((tokensByPlace, parameters) => { + return { + InProgress: [{ + remaining_time: Distribution.Lognormal(2.0, 0.5), + // ... other dimensions + }], + }; +}); +``` + +1. **Count down** with a differential equation: + +```ts +export default Dynamics((tokens, parameters) => { + return tokens.map(() => ({ remaining_time: -1 })); +}); +``` + +1. **Guard the completion transition** with a predicate: + +```ts +export default Lambda((tokensByPlace, parameters) => { + return tokensByPlace.InProgress[0].remaining_time <= 0; +}); +``` + +**Alternative approach:** use two dimensions -- a fixed `sampled_duration` that doesn't change and a `counter` that increments via dynamics. Guard on `counter >= sampled_duration`. This preserves the original sampled value for inspection. + +## Resource pools + +Use a place as a **pool** of tokens representing limited resources (machines, workers, servers). Transitions consume from the pool when starting work and return tokens when done. + +**Structure:** + +``` +[Available] ---> (StartWork) ---> [InUse] ---> (FinishWork) ---> [Available] +``` + +The number of initial tokens in "Available" determines the resource capacity. If no tokens are available, "StartWork" cannot fire -- work is naturally queued. + +**Example:** the [Production Machines](examples.md#production-machines) example models machines cycling between available, producing, broken, and being repaired states. + +## Mutual exclusion with inhibitor arcs + +Use an [inhibitor arc](petri-net-extensions.md#inhibitor-arcs) from a "busy" or "blocked" place to prevent a transition from firing while a condition holds. + +**Structure:** + +``` +[Busy] ---o (StartNew) (inhibitor arc, weight 1) +``` + +"StartNew" can only fire when "Busy" has zero tokens. Once something enters the busy state, no new work can start until the token is removed. + +**Example:** the [Deployment Pipeline](examples.md#deployment-pipeline) uses inhibitor arcs to block new deployments while an incident is being investigated or another deployment is already in progress. + +## Source transitions (exogenous arrivals) + +A transition with **no input arcs** is always structurally enabled. Set a stochastic rate to model arrivals following a Poisson process. + +```ts +export default Lambda((tokensByPlace, parameters) => { + return parameters.arrival_rate; +}); +``` + +Use the transition kernel to define the properties of newly created tokens (if the output place is typed). + +**Examples:** + +- [Deployment Pipeline](examples.md#deployment-pipeline) -- "Create Deployment" and "Incident Raised" generate events at configurable rates. +- [Probabilistic Satellites Launcher](examples.md#probabilistic-satellites-launcher) -- "LaunchSatellite" creates satellites with randomized initial positions and velocities using `Distribution.Uniform` and `Distribution.Gaussian`. + +## Sink transitions (removal / absorption) + +A transition with **no output arcs** consumes tokens without producing any. Useful for modelling: + +- **Expiry** -- tokens that age out or are consumed. +- **Departure** -- entities leaving the system. +- **Disposal** -- rejected or failed items. + +No special configuration needed -- just create a transition with input arcs only. + +## Competing transitions / routing + +Multiple transitions consuming from the **same place** with **complementary predicates** can model routing or branching decisions. + +**Structure:** + +``` + /--> (Pass) ---> [Dispatched] +[QAQueue] --< + \--> (Fail) ---> [Disposed] +``` + +```ts +// Pass transition +export default Lambda((tokensByPlace, parameters) => { + return tokensByPlace.QAQueue[0].quality >= parameters.quality_threshold; +}); + +// Fail transition +export default Lambda((tokensByPlace, parameters) => { + return tokensByPlace.QAQueue[0].quality < parameters.quality_threshold; +}); +``` + +**Example:** the [Drug Production (Stochastic)](examples.md#drug-production-stochastic) example routes products to dispatch or disposal based on a quality threshold. + +## Arc weight for multi-token operations + +An input arc with **weight > 1** requires multiple tokens from the same place for the transition to be enabled. This is useful for interactions between entities. + +**Example:** the [Satellites in Orbit](examples.md#satellites-in-orbit) example has a "Collision" transition with input weight 2 from the "Space" place -- it requires two satellites to be present and checks their distance in the lambda to detect collisions. + +The transition kernel receives the consumed tokens and can compute outputs based on all of them. diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md new file mode 100644 index 00000000000..e192aab7b60 --- /dev/null +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -0,0 +1,51 @@ +# Visual Settings + +Access the settings dialog via the **gear icon** in the viewport controls (bottom-right corner of the canvas). + + + +## Available settings + +### Animations + +Toggle panel transition and UI interaction animations. Disable for a snappier feel or if animations cause performance issues. + +### Keep panels mounted + +When enabled, hidden panels remain loaded in the background. Switching between panels is faster, but uses more memory. When disabled, panels are unmounted when hidden and re-created when opened. + +### Minimap + +Show or hide the **overview minimap** in the top-right corner of the canvas. The minimap provides a zoomed-out view of the entire net for orientation in large models. + +### Snap to grid + +When enabled, node positions snap to a grid when placing new nodes or dragging existing ones. Helps keep nets tidy and aligned. + +### Compact nodes + +Switch between two node rendering styles: + +- **Compact** (enabled) -- smaller card-style nodes. +- **Classic** (disabled) -- larger nodes with more detail. + +### Partial selection + +Controls selection box behavior in [Select mode](drawing-a-net.md#pan-and-select-modes): + +- **Enabled** -- nodes that are only partially inside the selection box are selected. +- **Disabled** -- nodes must be fully enclosed to be selected. + +### Entities tree view (experimental) + +Replaces the tabbed left sidebar with a unified **tree view** showing all entities (nodes, types, equations, parameters) in a single hierarchy. + +### Arcs rendering + +Choose how arcs are drawn between nodes: + +| Style | Description | +|-------|-------------| +| **Square** | Right-angle paths (smoothstep routing). | +| **Bezier** | Smooth curved paths. | +| **Adaptive Bezier** | Curved paths that adjust based on node positions. | From 15c47550b063689470a404caf1bd04e67b05048e Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 13 Apr 2026 19:51:01 +0100 Subject: [PATCH 02/16] fix:markdownlint --- .../petrinaut/docs/drawing-a-net.md | 48 +++++++++---------- libs/@hashintel/petrinaut/docs/examples.md | 18 +++---- libs/@hashintel/petrinaut/docs/simulation.md | 16 +++---- .../petrinaut/docs/useful-patterns.md | 6 +-- .../petrinaut/docs/visual-settings.md | 10 ++-- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/drawing-a-net.md b/libs/@hashintel/petrinaut/docs/drawing-a-net.md index e023f62af74..af252066a55 100644 --- a/libs/@hashintel/petrinaut/docs/drawing-a-net.md +++ b/libs/@hashintel/petrinaut/docs/drawing-a-net.md @@ -48,10 +48,10 @@ See also: [arc weight for multi-token operations](useful-patterns.md#arc-weight- The editor has two cursor modes, toggled from the bottom toolbar dropdown: -| Mode | Shortcut | Behavior | -|------|----------|----------| -| **Pan** | H | Click and drag to pan the canvas. This is the default. | -| **Select** | V | Click and drag to draw a selection box around nodes. | +| Mode | Shortcut | Behavior | +| ---------- | -------- | ------------------------------------------------------ | +| **Pan** | H | Click and drag to pan the canvas. This is the default. | +| **Select** | V | Click and drag to draw a selection box around nodes. | With a selection, you can: @@ -68,12 +68,12 @@ Whether a node must be fully inside or only partially inside the selection box i The left sidebar has four tabs for creating and managing entities: -| Tab | Contents | -|-----|----------| -| **Nodes** | All places and transitions. Click to select and open properties. | -| **Types** | Token types (colours). Click **+** to create a new type. | -| **Differential Equations** | ODE definitions for continuous dynamics. Click **+** to create. | -| **Parameters** | Global parameters available in all user code. Click **+** to create. | +| Tab | Contents | +| -------------------------- | --------------------------------------------------------------------- | +| **Nodes** | All places and transitions. Click to select and open properties. | +| **Types** | Token types (colours). Click **+** to create a new type. | +| **Differential Equations** | ODE definitions for continuous dynamics. Click **+** to create. | +| **Parameters** | Global parameters available in all user code. Click **+** to create. | Toggle the sidebar with the button in the top-left corner. @@ -89,20 +89,20 @@ The recent history is displayed in the top-right corner. Click on a history entr ## Keyboard shortcuts -| Shortcut | Action | -|----------|--------| -| N | Add Place mode | -| T | Add Transition mode | -| H | Pan mode | -| V | Select mode | -| Escape | Clear selection, return to cursor mode | -| Cmd+A | Select all places and transitions | -| Cmd+C | Copy selection | -| Cmd+V | Paste | -| Cmd+Z | Undo | -| Cmd+Shift+Z | Redo | -| Cmd+F | Search | -| Delete / Backspace | Delete selection | +| Shortcut | Action | +| -------------------- | --------------------------------------- | +| N | Add Place mode | +| T | Add Transition mode | +| H | Pan mode | +| V | Select mode | +| Escape | Clear selection, return to cursor mode | +| Cmd+A | Select all places and transitions | +| Cmd+C | Copy selection | +| Cmd+V | Paste | +| Cmd+Z | Undo | +| Cmd+Shift+Z | Redo | +| Cmd+F | Search | +| Delete / Backspace | Delete selection | ## Snap to grid diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md index e4d268a6203..68a06eb3bd0 100644 --- a/libs/@hashintel/petrinaut/docs/examples.md +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -64,10 +64,10 @@ A manufacturing system where machines produce goods, accumulate damage, break do **Suggested initial state:** -| Place | Tokens | Values | -|-------|--------|--------| -| RawMaterial | 100 | (untyped) | -| AvailableMachines | 3 | `machine_damage_ratio: 0` each | +| Place | Tokens | Values | +| ----------------- | ------ | ------------------------------ | +| RawMaterial | 100 | (untyped) | +| AvailableMachines | 3 | `machine_damage_ratio: 0` each | All other places start empty. "Start Production" will immediately consume a raw material and an available machine to begin. @@ -89,11 +89,11 @@ An orbital mechanics simulation with satellites orbiting Earth, subject to colli **Suggested initial state:** add 3--5 satellite tokens to the Space place. Position them in a rough orbit around the origin (Earth is at 0,0). For example: -| x | y | direction | velocity | -|---|---|-----------|----------| -| 80 | 0 | 1.57 | 70 | -| 0 | 100 | 3.14 | 55 | -| -60 | -60 | 0.78 | 80 | +| x | y | direction | velocity | +| --- | ---- | --------- | -------- | +| 80 | 0 | 1.57 | 70 | +| 0 | 100 | 3.14 | 55 | +| -60 | -60 | 0.78 | 80 | The velocity needed for a roughly circular orbit at radius `r` is approximately `sqrt(gravitational_constant / r)`. With the default `gravitational_constant` of 400000, that's about 71 at radius 80. Select the Space place and open the visualizer preview to watch the orbits. diff --git a/libs/@hashintel/petrinaut/docs/simulation.md b/libs/@hashintel/petrinaut/docs/simulation.md index a5056c5060f..8ac84baccd1 100644 --- a/libs/@hashintel/petrinaut/docs/simulation.md +++ b/libs/@hashintel/petrinaut/docs/simulation.md @@ -75,10 +75,10 @@ If transitions are structurally enabled but their lambdas prevent firing, the si The bottom toolbar provides playback controls: -| Control | Description | -|---------|-------------| -| **Play** | Start or resume playback. | -| **Pause** | Pause at the current frame. | +| Control | Description | +| ---------------- | ----------------------------------- | +| **Play** | Start or resume playback. | +| **Pause** | Pause at the current frame. | | **Stop / Reset** | Stop playback and reset to frame 0. | The frame counter shows the current frame number, total frames, and elapsed simulation time. @@ -93,11 +93,11 @@ Choose a playback speed multiplier: **1x**, **2x**, **5x**, **10x**, **30x**, ** Controls how computation and playback interact: -| Mode | Behavior | -|------|----------| +| Mode | Behavior | +| ---------------------------- | ----------------------------------------------------------- | | **Play computed steps only** | Replay already-computed frames without further computation. | -| **Play + compute buffer** | Compute only a small buffer ahead of the playhead. | -| **Play + compute max** | Compute frames as fast as possible while playing. | +| **Play + compute buffer** | Compute only a small buffer ahead of the playhead. | +| **Play + compute max** | Compute frames as fast as possible while playing. | ### Stopping condition diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md index c1401867af4..611393066af 100644 --- a/libs/@hashintel/petrinaut/docs/useful-patterns.md +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -56,7 +56,7 @@ Use a place as a **pool** of tokens representing limited resources (machines, wo **Structure:** -``` +```text [Available] ---> (StartWork) ---> [InUse] ---> (FinishWork) ---> [Available] ``` @@ -70,7 +70,7 @@ Use an [inhibitor arc](petri-net-extensions.md#inhibitor-arcs) from a "busy" or **Structure:** -``` +```text [Busy] ---o (StartNew) (inhibitor arc, weight 1) ``` @@ -111,7 +111,7 @@ Multiple transitions consuming from the **same place** with **complementary pred **Structure:** -``` +```text /--> (Pass) ---> [Dispatched] [QAQueue] --< \--> (Fail) ---> [Disposed] diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md index e192aab7b60..e5cbbade85e 100644 --- a/libs/@hashintel/petrinaut/docs/visual-settings.md +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -44,8 +44,8 @@ Replaces the tabbed left sidebar with a unified **tree view** showing all entiti Choose how arcs are drawn between nodes: -| Style | Description | -|-------|-------------| -| **Square** | Right-angle paths (smoothstep routing). | -| **Bezier** | Smooth curved paths. | -| **Adaptive Bezier** | Curved paths that adjust based on node positions. | +| Style | Description | +| ------------------- | -------------------------------------------------- | +| **Square** | Right-angle paths (smoothstep routing). | +| **Bezier** | Smooth curved paths. | +| **Adaptive Bezier** | Curved paths that adjust based on node positions. | From 06cd00b3e2fc19c03f53b058a64a25814cd7bc28 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 13 Apr 2026 19:55:29 +0100 Subject: [PATCH 03/16] add docs link to menu --- .../petrinaut/src/views/Editor/editor-view.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx index c4860a2d6d4..8505804fa30 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx @@ -331,6 +331,17 @@ export const EditorView = ({ }, ] : []), + { + id: "docs", + label: "Docs", + onClick: () => { + window.open( + "https://github.com/hashintel/hash/tree/main/libs/%40hashintel/petrinaut/docs", + "_blank", + "noopener,noreferrer", + ); + }, + }, ]; const portalContainerRef = useRef(null); From 6ab2af2b0a0ddbc5c5fb534d1efb7fea33663d8f Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 13 Apr 2026 19:56:54 +0100 Subject: [PATCH 04/16] remove reference to token value type --- libs/@hashintel/petrinaut/docs/petri-net-extensions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md index 0c6da7336ce..cf5f4a462f8 100644 --- a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md +++ b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md @@ -33,13 +33,12 @@ A type defines the structure of tokens in a place: what dimensions they have and 1. Open the **Types** tab in the left sidebar. 2. Click **+** to add a new type. 3. Give it a **name** and **display colour**. -4. Add **dimensions** -- each has a name and a type (`real`, `integer`, or `boolean`). // TODO BEFORE ADDING DOCS: does this actually do anything? **To assign a type to a place:** select the place, then choose the type from the **Accepted token type** dropdown in the properties panel. -Once a place has a type, its tokens are accessible in code as structured objects. For example, a type with dimensions `x` (real) and `y` (real) means each token is `{ x: number, y: number }`. +Once a place has a type, its tokens are accessible in code as structured objects. For example, a type with dimensions `x` and `y` means each token is `{ x: number, y: number }`. ## Differential equations (dynamics) From 11e8ea5b6b5663aba6260ddae57dd5e03086b0d6 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:35:39 +0100 Subject: [PATCH 05/16] attached screenshots to useful patterns.md Updated the useful patterns documentation with images and examples for better clarity. --- libs/@hashintel/petrinaut/docs/useful-patterns.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md index 611393066af..05cdadbf2f6 100644 --- a/libs/@hashintel/petrinaut/docs/useful-patterns.md +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -56,9 +56,7 @@ Use a place as a **pool** of tokens representing limited resources (machines, wo **Structure:** -```text -[Available] ---> (StartWork) ---> [InUse] ---> (FinishWork) ---> [Available] -``` +competing-transition-screenshot The number of initial tokens in "Available" determines the resource capacity. If no tokens are available, "StartWork" cannot fire -- work is naturally queued. @@ -70,9 +68,7 @@ Use an [inhibitor arc](petri-net-extensions.md#inhibitor-arcs) from a "busy" or **Structure:** -```text -[Busy] ---o (StartNew) (inhibitor arc, weight 1) -``` +inhibitor-arc-screenshot "StartNew" can only fire when "Busy" has zero tokens. Once something enters the busy state, no new work can start until the token is removed. @@ -111,11 +107,7 @@ Multiple transitions consuming from the **same place** with **complementary pred **Structure:** -```text - /--> (Pass) ---> [Dispatched] -[QAQueue] --< - \--> (Fail) ---> [Disposed] -``` +competing-transition-screenshot ```ts // Pass transition From 01a2e09b5c4b68c671efdd4964eae92072f094de Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:59:18 +0100 Subject: [PATCH 06/16] add screenshots to drawing-a-net.md Updated images in the documentation to use Markdown syntax for better rendering. --- libs/@hashintel/petrinaut/docs/drawing-a-net.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/drawing-a-net.md b/libs/@hashintel/petrinaut/docs/drawing-a-net.md index af252066a55..231766f4706 100644 --- a/libs/@hashintel/petrinaut/docs/drawing-a-net.md +++ b/libs/@hashintel/petrinaut/docs/drawing-a-net.md @@ -10,7 +10,7 @@ The editor is organized around a central canvas where you build your net: - **Bottom panel** -- tabs for Diagnostics (code errors), Simulation Settings, and Timeline (during simulation). - **Bottom toolbar** -- editing mode buttons and simulation controls. - +full-editor ## Adding places and transitions @@ -21,7 +21,7 @@ Use the bottom toolbar to add nodes: New nodes are named automatically (Place1, Place2, Transition1, etc.). Rename them by selecting the node and editing the name in the properties panel. - +add-place-transition-toolbar ## Connecting with arcs @@ -32,7 +32,7 @@ Drag from a node's handle to connect it: Petri nets are bipartite: you cannot connect a place to another place or a transition to another transition. New arcs default to weight 1. - +![drawing-arc](https://github.com/user-attachments/assets/ac688560-bba8-44fe-a6f8-c7ff320474a4) ## Arc weight @@ -62,7 +62,7 @@ With a selection, you can: Whether a node must be fully inside or only partially inside the selection box is configurable in [visual settings](visual-settings.md). - +selection ## Left sidebar From d71e76d065da356f3fd745623f7014305b06f8c6 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:44:31 +0100 Subject: [PATCH 07/16] Add screenshots to examples.md --- libs/@hashintel/petrinaut/docs/examples.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md index 68a06eb3bd0..27c38e8a2a0 100644 --- a/libs/@hashintel/petrinaut/docs/examples.md +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -16,7 +16,7 @@ The classic Susceptible-Infected-Recovered compartmental model from epidemiology **Key concepts:** [stochastic firing](petri-net-extensions.md#stochastic-rate), [parameters](petri-net-extensions.md#global-parameters), [arc weight](useful-patterns.md#arc-weight-for-multi-token-operations). - +SIR ## Drug Production (Stochastic) @@ -33,7 +33,7 @@ A manufacturing pipeline from raw material suppliers through manufacturing, qual **Key concepts:** [types](petri-net-extensions.md#types-colours), [distributions](petri-net-extensions.md#distributions), [competing transitions](useful-patterns.md#competing-transitions--routing). - +probabilitic-supply-chain ## Deployment Pipeline @@ -49,7 +49,7 @@ A software deployment process with incident handling. Deployments are created at **Key concepts:** [inhibitor arcs](petri-net-extensions.md#inhibitor-arcs), [source transitions](useful-patterns.md#source-transitions-exogenous-arrivals), [mutual exclusion](useful-patterns.md#mutual-exclusion-with-inhibitor-arcs). - +deployment-pipeline ## Production Machines @@ -73,7 +73,7 @@ All other places start empty. "Start Production" will immediately consume a raw **Key concepts:** [dynamics](petri-net-extensions.md#differential-equations-dynamics), [resource pools](useful-patterns.md#resource-pools), predicate vs stochastic on competing transitions. - +production-machines ## Satellites in Orbit @@ -99,7 +99,7 @@ The velocity needed for a roughly circular orbit at radius `r` is approximately **Key concepts:** [dynamics](petri-net-extensions.md#differential-equations-dynamics), [visualizers](petri-net-extensions.md#visualizer), [arc weight](useful-patterns.md#arc-weight-for-multi-token-operations). - +![visualiser](https://github.com/user-attachments/assets/46dd34df-6206-4966-9dbd-513afb339ae7) ## Probabilistic Satellites Launcher @@ -115,4 +115,4 @@ Extends the Satellites example with ongoing satellite launches at a stochastic r **Key concepts:** [source transitions](useful-patterns.md#source-transitions-exogenous-arrivals), [distributions and `.map()`](petri-net-extensions.md#distributions). - +probabilistic-satellites From 15f67442792983cf50cb49fbad9192aed884aeb8 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:46:25 +0100 Subject: [PATCH 08/16] Update images and examples in petri-net-extensions.md --- libs/@hashintel/petrinaut/docs/petri-net-extensions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md index cf5f4a462f8..630be3e460c 100644 --- a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md +++ b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md @@ -18,7 +18,7 @@ Parameters are named values available in all user-authored code: dynamics, lambd 2. Click **+** to add a new parameter. 3. Set a **name** (display label), **variable name** (used in code), and **default value**. - +parameters Override parameter values before running a simulation in the **Simulation Settings** panel (see [Simulation](simulation.md#simulation-settings)). This lets you experiment with different values without editing code. @@ -34,7 +34,7 @@ A type defines the structure of tokens in a place: what dimensions they have and 2. Click **+** to add a new type. 3. Give it a **name** and **display colour**. - +token-type **To assign a type to a place:** select the place, then choose the type from the **Accepted token type** dropdown in the properties panel. @@ -62,7 +62,7 @@ export default Dynamics((tokens, parameters) => { The function receives the current token values and global parameters. It must return an array of derivative objects -- one per token, with the same dimension names. - +diff-equations **Example:** in [Satellites in Orbit](examples.md#satellites-in-orbit), the orbital dynamics equation computes gravitational acceleration to update satellite position and velocity each step. @@ -84,7 +84,7 @@ export default Visualization(({ tokens, parameters }) => { The component receives `tokens` (array of token objects) and `parameters` (global parameter values). It renders in the properties panel. During simulation, it updates live as token state changes. - +visauliser-preview Use the menu in the code editor header to **Load default template** for a starting point. @@ -170,7 +170,7 @@ An inhibitor arc is a special input arc that **prevents** a transition from firi Inhibitor arcs **do not consume tokens** when the transition fires. - +inhibitor-arc **Example:** in [Deployment Pipeline](examples.md#deployment-pipeline), inhibitor arcs from "IncidentBeingInvestigated" and "DeploymentInProgress" block new deployments while an incident is open or a deployment is already running. From 4ce52872ff9913ff185c351c9ebc638edb03fea1 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:48:30 +0100 Subject: [PATCH 09/16] Enhance simulation.md with images Updated simulation documentation with images for better clarity. --- libs/@hashintel/petrinaut/docs/simulation.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/simulation.md b/libs/@hashintel/petrinaut/docs/simulation.md index 8ac84baccd1..91e8af0144b 100644 --- a/libs/@hashintel/petrinaut/docs/simulation.md +++ b/libs/@hashintel/petrinaut/docs/simulation.md @@ -9,7 +9,7 @@ Select a place and open the **State** sub-view in its properties: - **Untyped places** -- set a token count (integer). - **Typed places** -- define individual tokens with values for each dimension in a spreadsheet editor. - +initial-states If no initial marking is set, a place starts empty (zero tokens). @@ -46,7 +46,7 @@ Press **Play** in the bottom toolbar. The simulation: If there are unresolved [diagnostics](petri-net-extensions.md#diagnostics) (code errors), pressing Play opens the Diagnostics tab instead of starting the simulation. Fix all errors first. - +simulation-settings ## How a frame is computed @@ -83,7 +83,7 @@ The bottom toolbar provides playback controls: The frame counter shows the current frame number, total frames, and elapsed simulation time. - +simulation-toolbar ### Speed @@ -110,7 +110,7 @@ Stopping conditions are **locked after the simulation starts**. Reset the simula The **Timeline** tab appears in the bottom panel during and after simulation. It shows token counts per place over time as a chart. - +timeline - **Chart type** -- toggle between **Run** (line chart) and **Stacked** (area chart) using the control in the tab header. - **Scrub** -- click or drag on the chart to jump to any frame. A playhead indicator shows the current position. @@ -122,7 +122,7 @@ Select a place during simulation to see its current token values in the properti If the place has a [visualizer](petri-net-extensions.md#visualizer) defined, it renders live in the properties panel, updating as the simulation progresses. - +![visualiser](https://github.com/user-attachments/assets/9324bb5b-4912-499e-8a5d-f2bc6a7754c2) ## Locked editing From d7a06b2e95b143c95b44a70a38a51483ef43bc91 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:50:33 +0100 Subject: [PATCH 10/16] Update satallite net image in examples.md --- libs/@hashintel/petrinaut/docs/examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md index 27c38e8a2a0..377f0388364 100644 --- a/libs/@hashintel/petrinaut/docs/examples.md +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -99,7 +99,7 @@ The velocity needed for a roughly circular orbit at radius `r` is approximately **Key concepts:** [dynamics](petri-net-extensions.md#differential-equations-dynamics), [visualizers](petri-net-extensions.md#visualizer), [arc weight](useful-patterns.md#arc-weight-for-multi-token-operations). -![visualiser](https://github.com/user-attachments/assets/46dd34df-6206-4966-9dbd-513afb339ae7) +satellites ## Probabilistic Satellites Launcher From 8ea6416b76730817aba00e1dfa7142ae33840a28 Mon Sep 17 00:00:00 2001 From: Dora <45151367+drdma@users.noreply.github.com> Date: Tue, 14 Apr 2026 19:22:58 +0100 Subject: [PATCH 11/16] Update images in petri-net-extensions.md to match examples --- libs/@hashintel/petrinaut/docs/petri-net-extensions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md index 630be3e460c..b36ec45be77 100644 --- a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md +++ b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md @@ -18,7 +18,7 @@ Parameters are named values available in all user-authored code: dynamics, lambd 2. Click **+** to add a new parameter. 3. Set a **name** (display label), **variable name** (used in code), and **default value**. -parameters +parameters-SIR Override parameter values before running a simulation in the **Simulation Settings** panel (see [Simulation](simulation.md#simulation-settings)). This lets you experiment with different values without editing code. @@ -170,7 +170,7 @@ An inhibitor arc is a special input arc that **prevents** a transition from firi Inhibitor arcs **do not consume tokens** when the transition fires. -inhibitor-arc +inhibitor-arc-deployment **Example:** in [Deployment Pipeline](examples.md#deployment-pipeline), inhibitor arcs from "IncidentBeingInvestigated" and "DeploymentInProgress" block new deployments while an incident is open or a deployment is already running. From 198640ff21a732e9980e29159476798eccfafbbb Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Wed, 15 Apr 2026 20:10:10 +0100 Subject: [PATCH 12/16] respond to PR feedback. remove non-stochastic supply chain example --- .../petrinaut/docs/drawing-a-net.md | 6 +- libs/@hashintel/petrinaut/docs/examples.md | 2 +- .../petrinaut/docs/petri-net-extensions.md | 42 +++--- libs/@hashintel/petrinaut/docs/simulation.md | 14 +- .../petrinaut/docs/visual-settings.md | 2 +- .../petrinaut/src/examples/supply-chain.ts | 128 ------------------ .../src/views/Editor/editor-view.tsx | 9 -- 7 files changed, 32 insertions(+), 171 deletions(-) delete mode 100644 libs/@hashintel/petrinaut/src/examples/supply-chain.ts diff --git a/libs/@hashintel/petrinaut/docs/drawing-a-net.md b/libs/@hashintel/petrinaut/docs/drawing-a-net.md index 231766f4706..edf50bbfbd9 100644 --- a/libs/@hashintel/petrinaut/docs/drawing-a-net.md +++ b/libs/@hashintel/petrinaut/docs/drawing-a-net.md @@ -8,7 +8,7 @@ The editor is organized around a central canvas where you build your net: - **Left sidebar** -- lists of entities organized into tabs: Nodes, Types, Differential Equations, Parameters. - **Properties panel** (right) -- opens when you select an entity, showing its configurable properties. - **Bottom panel** -- tabs for Diagnostics (code errors), Simulation Settings, and Timeline (during simulation). -- **Bottom toolbar** -- editing mode buttons and simulation controls. +- **Bottom toolbar** -- editing mode buttons and simulation controls (+ show/hide toggle for bottom panel). full-editor @@ -16,7 +16,7 @@ The editor is organized around a central canvas where you build your net: Use the bottom toolbar to add nodes: -- **Add Place** (shortcut: **N**) -- click the canvas to drop a place, or drag the button onto the canvas. +- **Add Place** (shortcut: **N**) -- click the canvas to drop a place, or click and drag the button onto the canvas. - **Add Transition** (shortcut: **T**) -- click the canvas to drop a transition, or drag the button onto the canvas. New nodes are named automatically (Place1, Place2, Transition1, etc.). Rename them by selecting the node and editing the name in the properties panel. @@ -38,8 +38,6 @@ Petri nets are bipartite: you cannot connect a place to another place or a trans Select an arc to open its properties. Set the **weight** to control how many tokens are consumed (input) or produced (output) per firing. -When weight is greater than 1, a label is displayed on the arc (e.g. "x2"). - You can also edit an arc's weight via the properties panel for the transition it is connected to. See also: [arc weight for multi-token operations](useful-patterns.md#arc-weight-for-multi-token-operations). diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md index 377f0388364..84577c8c947 100644 --- a/libs/@hashintel/petrinaut/docs/examples.md +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -18,7 +18,7 @@ The classic Susceptible-Infected-Recovered compartmental model from epidemiology SIR -## Drug Production (Stochastic) +## Supply Chain (Stochastic) A manufacturing pipeline from raw material suppliers through manufacturing, quality assurance, and shipping to a hospital. Products have a random `quality` attribute that determines whether they pass QA. diff --git a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md index b36ec45be77..2c5c3591ec6 100644 --- a/libs/@hashintel/petrinaut/docs/petri-net-extensions.md +++ b/libs/@hashintel/petrinaut/docs/petri-net-extensions.md @@ -8,15 +8,27 @@ By default, places hold **untyped tokens** -- they only track a count. Tokens ar To give tokens structure, assign a **type** to a place. Each token then carries named dimensions (e.g. `x`, `y`, `velocity`), enabling dynamics, visualization, and data-dependent transition logic. +**To create a type:** + +1. Open the **Token Types** tab in the left sidebar. +2. Click **+** to add a new type. +3. Give it a **name** and **display colour**. + +token-type + +**To assign a type to a place:** select the place, then choose the type from the **Accepted token type** dropdown in the properties panel. + +Once a place has a type, its tokens are accessible in code as structured objects. For example, a type with dimensions `x` and `y` means each token is `{ x: number, y: number }`. + ## Global parameters -Parameters are named values available in all user-authored code: dynamics, lambdas, kernels, and visualizers. They are accessed via the `parameters` argument. +Parameters are named values available in all user-authored code: dynamics, firing rate, kernels, and visualizers. They are accessed via the `parameters` argument. **To create a parameter:** 1. Open the **Parameters** tab in the left sidebar. 2. Click **+** to add a new parameter. -3. Set a **name** (display label), **variable name** (used in code), and **default value**. +3. Set a **name** (display label), **variable name** (used in code), and **default value** (can be overridden in the simulation settings). parameters-SIR @@ -24,22 +36,6 @@ Override parameter values before running a simulation in the **Simulation Settin **Example:** the [SIR Epidemic Model](examples.md#sir-epidemic-model) defines `infection_rate` and `recovery_rate` as parameters, used in its transition lambdas. -## Types (colours) - -A type defines the structure of tokens in a place: what dimensions they have and what data type each dimension holds. - -**To create a type:** - -1. Open the **Types** tab in the left sidebar. -2. Click **+** to add a new type. -3. Give it a **name** and **display colour**. - -token-type - -**To assign a type to a place:** select the place, then choose the type from the **Accepted token type** dropdown in the properties panel. - -Once a place has a type, its tokens are accessible in code as structured objects. For example, a type with dimensions `x` and `y` means each token is `{ x: number, y: number }`. - ## Differential equations (dynamics) Differential equations define how token data evolves continuously over time. They are integrated at each simulation step using the Euler method. @@ -47,7 +43,7 @@ Differential equations define how token data evolves continuously over time. The **Setup:** 1. Create a differential equation in the **Differential Equations** tab (left sidebar). -2. Associate it with a **type** (the equation applies to tokens of that type). +2. Give it a name and associate it with a **type** (the equation applies to tokens of that type). 3. Select a place, enable **Dynamics**, and choose an equation that matches the type assigned to the place. **Function signature:** @@ -88,6 +84,8 @@ The component receives `tokens` (array of token objects) and `parameters` (globa Use the menu in the code editor header to **Load default template** for a starting point. +You can also toggle between the code, a preview, and both at once. + **Example:** the [Satellites in Orbit](examples.md#satellites-in-orbit) example includes a visualizer that renders Earth and orbiting satellites with velocity vectors. ## Transition kernel @@ -104,6 +102,8 @@ export default TransitionKernel((tokensByPlace, parameters) => { `tokensByPlace` is keyed by **place name**. Each value is an array of token objects from that input place. The return value is keyed by **output place name**, each containing an array of token objects to produce. +Use the menu in the code editor header to **Load default template** for a starting point. + ### Distributions Kernel output values can be numbers or `Distribution` objects for stochastic output: @@ -132,7 +132,7 @@ For transitions where all output places are **untyped**, the kernel code can be ## Firing rate / predicate -Each transition has a **firing rule** that controls when it fires, once structurally enabled (sufficient tokens in input places). Choose between two modes in the transition properties: +Each transition has a **firing rate** that controls when it fires, once structurally enabled (sufficient tokens in input places). Choose between two modes in the transition properties: ### Predicate @@ -176,6 +176,6 @@ Inhibitor arcs **do not consume tokens** when the transition fires. ## Diagnostics -The **Diagnostics** tab in the bottom panel shows TypeScript errors in your code (dynamics, lambdas, kernels, visualizers), grouped by entity. Click a diagnostic to select the relevant entity and see the error in context. +The **Diagnostics** tab in the bottom panel shows TypeScript errors in your code (dynamics, firing rate, kernels, visualizers), grouped by entity. Click a diagnostic to select the relevant entity and see the error in context. Diagnostics must be resolved before running a simulation -- pressing Play with unresolved errors opens the Diagnostics tab instead of starting the simulation. diff --git a/libs/@hashintel/petrinaut/docs/simulation.md b/libs/@hashintel/petrinaut/docs/simulation.md index 91e8af0144b..69c5cee1286 100644 --- a/libs/@hashintel/petrinaut/docs/simulation.md +++ b/libs/@hashintel/petrinaut/docs/simulation.md @@ -7,7 +7,7 @@ Before running a simulation, set the **initial marking** -- the starting tokens Select a place and open the **State** sub-view in its properties: - **Untyped places** -- set a token count (integer). -- **Typed places** -- define individual tokens with values for each dimension in a spreadsheet editor. +- **Typed places** -- define individual tokens with values for each dimension in a spreadsheet editor. Add a row to create a new token. initial-states @@ -30,7 +30,7 @@ The time step in seconds per frame. Controls the resolution of ODE integration a - **Smaller dt** -- finer approximation, but slower computation. - **Larger dt** -- faster, but less accurate for continuous dynamics. -Default: `0.1` seconds. +Default: `0.01` seconds. ### ODE solver @@ -55,9 +55,9 @@ Each simulation step proceeds in two phases: 1. **Continuous dynamics** -- for every place with dynamics enabled, the differential equation is integrated one step (Euler method, step size = dt). This updates all token dimension values. 2. **Discrete transitions** -- transitions are evaluated in definition order (deterministic, not random). For each transition: - - Check structural enablement (enough tokens in input places, inhibitor conditions met). - - Evaluate the lambda (predicate or stochastic rate). - - If the transition fires, remove input tokens **immediately** (subsequent transitions see the updated state). + - Checks structural enablement (enough tokens in input places, inhibitor conditions met). + - Evaluates the lambda (predicate or stochastic rate). + - If the transition fires, removes input tokens **immediately** (subsequent transitions see the updated state). All produced output tokens are added at the end of the step. @@ -87,7 +87,7 @@ The frame counter shows the current frame number, total frames, and elapsed simu ### Speed -Choose a playback speed multiplier: **1x**, **2x**, **5x**, **10x**, **30x**, **60x**, **120x**, or **Max** (as fast as possible). +Choose a playback speed multiplier via playback settings: **1x**, **2x**, **5x**, **10x**, **30x**, **60x**, **120x**, or **Max** (as fast as possible). ### Play mode @@ -114,7 +114,7 @@ The **Timeline** tab appears in the bottom panel during and after simulation. It - **Chart type** -- toggle between **Run** (line chart) and **Stacked** (area chart) using the control in the tab header. - **Scrub** -- click or drag on the chart to jump to any frame. A playhead indicator shows the current position. -- **Legend** -- click place names to show/hide individual traces. Hover to dim other traces. +- **Legend** -- click place names to show/hide individual traces. Hover to dim other traces. Y axis is automatically scaled to the maximum value. ## Viewing state during simulation diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md index e5cbbade85e..78250de315f 100644 --- a/libs/@hashintel/petrinaut/docs/visual-settings.md +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -48,4 +48,4 @@ 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. | +| **Adaptive Bezier** | Curved paths that adjust based on node positions. (Default) | diff --git a/libs/@hashintel/petrinaut/src/examples/supply-chain.ts b/libs/@hashintel/petrinaut/src/examples/supply-chain.ts deleted file mode 100644 index 58c0e51fefa..00000000000 --- a/libs/@hashintel/petrinaut/src/examples/supply-chain.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { SNAP_GRID_SIZE } from "../constants/ui"; -import type { SDCPN } from "../core/types/sdcpn"; - -export const supplyChainSDCPN: { title: string; petriNetDefinition: SDCPN } = { - title: "Drug Production", - petriNetDefinition: { - places: [ - { - id: "place__0", - name: "PlantASupply", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: SNAP_GRID_SIZE, - y: 8 * SNAP_GRID_SIZE, - }, - { - id: "place__1", - name: "PlantBSupply", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: SNAP_GRID_SIZE, - y: 40 * SNAP_GRID_SIZE, - }, - { - id: "place__2", - name: "ManufacturingPlant", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: 20 * SNAP_GRID_SIZE, - y: 20 * SNAP_GRID_SIZE, - }, - { - id: "place__3", - name: "QAQueue", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: 47 * SNAP_GRID_SIZE, - y: 23 * SNAP_GRID_SIZE, - }, - { - id: "place__4", - name: "Disposal", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: 73 * SNAP_GRID_SIZE, - y: 40 * SNAP_GRID_SIZE, - }, - { - id: "place__5", - name: "Dispatch", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: 67 * SNAP_GRID_SIZE, - y: 13 * SNAP_GRID_SIZE, - }, - { - id: "place__6", - name: "Hospital", - colorId: null, - dynamicsEnabled: false, - differentialEquationId: null, - x: 87 * SNAP_GRID_SIZE, - y: 25 * SNAP_GRID_SIZE, - }, - ], - transitions: [ - { - id: "transition__0", - name: "Deliver to Plant", - inputArcs: [ - { placeId: "place__0", weight: 1, type: "standard" }, - { placeId: "place__1", weight: 1, type: "standard" }, - ], - outputArcs: [{ placeId: "place__2", weight: 1 }], - lambdaType: "predicate", - lambdaCode: "export default Lambda(() => true);", - transitionKernelCode: "", - x: 7 * SNAP_GRID_SIZE, - y: 27 * SNAP_GRID_SIZE, - }, - { - id: "transition__1", - name: "Manufacture", - inputArcs: [{ placeId: "place__2", weight: 1, type: "standard" }], - outputArcs: [{ placeId: "place__3", weight: 1 }], - lambdaType: "predicate", - lambdaCode: "export default Lambda(() => true);", - transitionKernelCode: "", - x: 33 * SNAP_GRID_SIZE, - y: 23 * SNAP_GRID_SIZE, - }, - { - id: "transition__2", - name: "Quality Check", - inputArcs: [{ placeId: "place__3", weight: 1, type: "standard" }], - outputArcs: [ - { placeId: "place__5", weight: 1 }, - { placeId: "place__4", weight: 1 }, - ], - lambdaType: "predicate", - lambdaCode: "export default Lambda(() => true);", - transitionKernelCode: "", - x: 58 * SNAP_GRID_SIZE, - y: 27 * SNAP_GRID_SIZE, - }, - { - id: "transition__3", - name: "Ship", - inputArcs: [{ placeId: "place__5", weight: 1, type: "standard" }], - outputArcs: [{ placeId: "place__6", weight: 1 }], - lambdaType: "predicate", - lambdaCode: "export default Lambda(() => true);", - transitionKernelCode: "", - x: 77 * SNAP_GRID_SIZE, - y: 19 * SNAP_GRID_SIZE, - }, - ], - types: [], - differentialEquations: [], - parameters: [], - }, -}; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx index 8505804fa30..541f6045436 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx @@ -8,7 +8,6 @@ import { deploymentPipelineSDCPN } from "../../examples/deployment-pipeline"; import { satellitesSDCPN } from "../../examples/satellites"; import { probabilisticSatellitesSDCPN } from "../../examples/satellites-launcher"; import { sirModel } from "../../examples/sir-model"; -import { supplyChainSDCPN } from "../../examples/supply-chain"; import { supplyChainStochasticSDCPN } from "../../examples/supply-chain-stochastic"; import { exportSDCPN } from "../../file-format/export-sdcpn"; import { importSDCPN } from "../../file-format/import-sdcpn"; @@ -271,14 +270,6 @@ export const EditorView = ({ id: "load-example", label: "Load example", submenu: [ - { - id: "load-example-supply-chain", - label: "Supply Chain", - onClick: () => { - createNewNet(supplyChainSDCPN); - clearSelection(); - }, - }, { id: "load-example-supply-chain-stochastic", label: "Probabilistic Supply Chain", From 9c33aa962287035071bbbaaf84b9a7b8d7099018 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Wed, 15 Apr 2026 20:10:55 +0100 Subject: [PATCH 13/16] fix markdownlint --- libs/@hashintel/petrinaut/docs/visual-settings.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md index 78250de315f..6b9d4205427 100644 --- a/libs/@hashintel/petrinaut/docs/visual-settings.md +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -44,8 +44,8 @@ Replaces the tabbed left sidebar with a unified **tree view** showing all entiti Choose how arcs are drawn between nodes: -| Style | Description | -| ------------------- | -------------------------------------------------- | -| **Square** | Right-angle paths (smoothstep routing). | -| **Bezier** | Smooth curved paths. | +| Style | Description | +| ------------------- | -------------------------------------------------------------| +| **Square** | Right-angle paths (smoothstep routing). | +| **Bezier** | Smooth curved paths. (Default) | | **Adaptive Bezier** | Curved paths that adjust based on node positions. (Default) | From c010146857a1c4ead7bd6d5433db06299860e661 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Wed, 15 Apr 2026 20:16:50 +0100 Subject: [PATCH 14/16] Revert "attached screenshots to useful patterns.md" This reverts commit 11e8ea5b6b5663aba6260ddae57dd5e03086b0d6. --- libs/@hashintel/petrinaut/docs/useful-patterns.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md index 05cdadbf2f6..611393066af 100644 --- a/libs/@hashintel/petrinaut/docs/useful-patterns.md +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -56,7 +56,9 @@ Use a place as a **pool** of tokens representing limited resources (machines, wo **Structure:** -competing-transition-screenshot +```text +[Available] ---> (StartWork) ---> [InUse] ---> (FinishWork) ---> [Available] +``` The number of initial tokens in "Available" determines the resource capacity. If no tokens are available, "StartWork" cannot fire -- work is naturally queued. @@ -68,7 +70,9 @@ Use an [inhibitor arc](petri-net-extensions.md#inhibitor-arcs) from a "busy" or **Structure:** -inhibitor-arc-screenshot +```text +[Busy] ---o (StartNew) (inhibitor arc, weight 1) +``` "StartNew" can only fire when "Busy" has zero tokens. Once something enters the busy state, no new work can start until the token is removed. @@ -107,7 +111,11 @@ Multiple transitions consuming from the **same place** with **complementary pred **Structure:** -competing-transition-screenshot +```text + /--> (Pass) ---> [Dispatched] +[QAQueue] --< + \--> (Fail) ---> [Disposed] +``` ```ts // Pass transition From 66e60cec51d81a6b8df90b266a76f30858fbaa05 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Wed, 15 Apr 2026 21:33:52 +0100 Subject: [PATCH 15/16] PR feedback --- libs/@hashintel/petrinaut/docs/README.md | 2 +- libs/@hashintel/petrinaut/docs/drawing-a-net.md | 2 ++ libs/@hashintel/petrinaut/docs/examples.md | 2 +- libs/@hashintel/petrinaut/docs/useful-patterns.md | 2 +- libs/@hashintel/petrinaut/docs/visual-settings.md | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/README.md b/libs/@hashintel/petrinaut/docs/README.md index 30423f5f555..a7295f4b46b 100644 --- a/libs/@hashintel/petrinaut/docs/README.md +++ b/libs/@hashintel/petrinaut/docs/README.md @@ -2,7 +2,7 @@ Petrinaut is a visual editor for [Petri nets](https://en.wikipedia.org/wiki/Petri_net). -It lets you build, configure, and simulate Petri nets. It has support for various extensions including types tokens (colours), continuous dynamics, and stochastic transitions. +It lets you build, configure, and simulate Petri nets. It has support for various extensions including typed tokens (colours), continuous dynamics, and stochastic transitions. ## Live site diff --git a/libs/@hashintel/petrinaut/docs/drawing-a-net.md b/libs/@hashintel/petrinaut/docs/drawing-a-net.md index edf50bbfbd9..547e6377d7a 100644 --- a/libs/@hashintel/petrinaut/docs/drawing-a-net.md +++ b/libs/@hashintel/petrinaut/docs/drawing-a-net.md @@ -102,6 +102,8 @@ The recent history is displayed in the top-right corner. Click on a history entr | Cmd+F | Search | | Delete / Backspace | Delete selection | +On Windows/Linux, use Ctrl instead of Cmd. + ## Snap to grid When enabled, node positions snap to a grid when placing or dragging. Toggle this in [visual settings](visual-settings.md). diff --git a/libs/@hashintel/petrinaut/docs/examples.md b/libs/@hashintel/petrinaut/docs/examples.md index 84577c8c947..e70d1fcc745 100644 --- a/libs/@hashintel/petrinaut/docs/examples.md +++ b/libs/@hashintel/petrinaut/docs/examples.md @@ -31,7 +31,7 @@ A manufacturing pipeline from raw material suppliers through manufacturing, qual **Suggested initial state:** set PlantASupply and PlantBSupply to **10** tokens each. Everything else starts empty. The stochastic "Deliver to Plant" transition will begin consuming from both suppliers once the simulation starts. -**Key concepts:** [types](petri-net-extensions.md#types-colours), [distributions](petri-net-extensions.md#distributions), [competing transitions](useful-patterns.md#competing-transitions--routing). +**Key concepts:** [types](petri-net-extensions.md#typed-vs-untyped-places), [distributions](petri-net-extensions.md#distributions), [competing transitions](useful-patterns.md#competing-transitions--routing). probabilitic-supply-chain diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md index 611393066af..999d7a7841f 100644 --- a/libs/@hashintel/petrinaut/docs/useful-patterns.md +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -129,7 +129,7 @@ export default Lambda((tokensByPlace, parameters) => { }); ``` -**Example:** the [Drug Production (Stochastic)](examples.md#drug-production-stochastic) example routes products to dispatch or disposal based on a quality threshold. +**Example:** the [Supply Chain (Stochastic)](examples.md#supply-chain-stochastic) example routes products to dispatch or disposal based on a quality threshold. ## Arc weight for multi-token operations diff --git a/libs/@hashintel/petrinaut/docs/visual-settings.md b/libs/@hashintel/petrinaut/docs/visual-settings.md index 6b9d4205427..38f7875d07f 100644 --- a/libs/@hashintel/petrinaut/docs/visual-settings.md +++ b/libs/@hashintel/petrinaut/docs/visual-settings.md @@ -47,5 +47,5 @@ Choose how arcs are drawn between nodes: | Style | Description | | ------------------- | -------------------------------------------------------------| | **Square** | Right-angle paths (smoothstep routing). | -| **Bezier** | Smooth curved paths. (Default) | +| **Bezier** | Smooth curved paths. | | **Adaptive Bezier** | Curved paths that adjust based on node positions. (Default) | From 695d00113a8ac6889fe308918eb929372fb0e478 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan <37743469+CiaranMn@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:14:54 +0100 Subject: [PATCH 16/16] Fix formatting in useful-patterns.md --- libs/@hashintel/petrinaut/docs/useful-patterns.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/@hashintel/petrinaut/docs/useful-patterns.md b/libs/@hashintel/petrinaut/docs/useful-patterns.md index 999d7a7841f..a21a8d8713c 100644 --- a/libs/@hashintel/petrinaut/docs/useful-patterns.md +++ b/libs/@hashintel/petrinaut/docs/useful-patterns.md @@ -57,7 +57,7 @@ Use a place as a **pool** of tokens representing limited resources (machines, wo **Structure:** ```text -[Available] ---> (StartWork) ---> [InUse] ---> (FinishWork) ---> [Available] +(Available) ---> [StartWork] ---> (InUse) ---> [FinishWork] ---> [Available) ``` The number of initial tokens in "Available" determines the resource capacity. If no tokens are available, "StartWork" cannot fire -- work is naturally queued. @@ -71,7 +71,7 @@ Use an [inhibitor arc](petri-net-extensions.md#inhibitor-arcs) from a "busy" or **Structure:** ```text -[Busy] ---o (StartNew) (inhibitor arc, weight 1) +(Busy) ---o [StartNew] (inhibitor arc, weight 1) ``` "StartNew" can only fire when "Busy" has zero tokens. Once something enters the busy state, no new work can start until the token is removed. @@ -112,9 +112,9 @@ Multiple transitions consuming from the **same place** with **complementary pred **Structure:** ```text - /--> (Pass) ---> [Dispatched] -[QAQueue] --< - \--> (Fail) ---> [Disposed] + /--> [Pass] ---> (Dispatched) +(QAQueue) --< + \--> [Fail] ---> (Disposed) ``` ```ts