Ad-hoc Scenarios
An ad-hoc scenario is an initial state and a set of parameter values defined inline, right where you run -- without saving a scenario first. Petrinaut compiles what you enter through a scenario generated for that run. Nothing is added to the net's scenario list, and leaving the form discards nothing: your entries stay until you clear them.
Use an ad-hoc scenario for one-off runs and quick exploration. When you want to keep a configuration, name it, or compare several setups, create a scenario -- the creation form is the same form, plus a Scenario Parameter toggle on each Variable.
Where the form appearsCopy link to this section
The same form appears in three places:
- Quick simulation -- in the Simulation Settings tab, with "No scenario" selected, the panel's two columns are the form's own tables: Variables above Parameters on the left, Initial state -- token counts and values -- on the right, no separate dialog. A quiet Clear button next to the Initial state title resets your entries. The next simulation run uses what you defined. Any compile error appears in the settings panel's error banner.
- Experiments -- in the create-experiment panel, choosing "No scenario" shows the form inside the Scenario section. The experiment's runs start from the state you defined, and the experiments table shows "Ad-hoc scenario" in its Scenario column. Every numeric value carries a Sweep interval toggle (see below).
- Scenario creation -- creating or editing a scenario uses the same form with a Scenario Parameter toggle on each top-level Variable; see Saving a scenario from the form.
The formCopy link to this section
The form has up to three sections. Variables come first -- parameter overrides may read them:
- Variables -- named values (real, integer, boolean, or ratio -- a real between 0 and 1) written as
scenario.<name>in every expression below, exactly as scenario parameters are written in scenario code. Use them to drive many values from one number. Add one from the dimmed Add a variable line at the bottom of the list: like any cell, a first click selects it and a second click (or Enter, or its gutter's+) adds the variable -- or reach it with the down arrow from the last row; the fresh name opens ready to type. Each row starts with a small variable-glyph gutter whose menu offers Delete variable, and the add line's gutter shows a+. A variable's name edits like any other cell: select it, then press Enter (or click again) to edit, and Enter or Escape to leave. Its type selector and compact dropdown chevron fit within the cell: arrow keys move past it, Enter opens it. In the quick-simulation embedding, Variables sit above Parameters in the left column. - Parameters -- one row per net-level parameter, showing its type and its value. An untouched parameter shows its default quietly, marked with a small
defaulttag; enter an expression to override the value for this run -- it may read the Variables above. In the quick-simulation embedding this section sits under Variables in the left column, beside Initial state. - Initial state -- one block per default starting place. Turn on the compact Show all places switch beside the Initial state title and info icon to include the other places. Turn it off to restore the filter. The switch appears only when there are other places to reveal. Each place's title carries its token colour dot (grey for untyped places). Filtering changes only what is visible; all place definitions are kept.
In the experiment panel each section collapses: click the chevron in its header, or focus the header and press Left to collapse and Right to expand. Place headers inside Initial state collapse the same way everywhere, and a collapsed place shows a one-line summary of its rows and token total. In the quick-simulation embedding, places start collapsed. Left on an expanded place collapses it and keeps focus on its header. Press Left again to move to the neighbouring focus group.
Every value in the form is an expression. A first click selects a value; a second click, a double-click, or Enter opens the editor in place: a code input with completion and type checking at exactly the cell's position, the value's path (for example Space › item 0 › x) above it, and -- in the experiment panel with sweeps enabled -- the interval toggle below it. Expressions may use your Variables (scenario.<name>), net parameters (parameters.<name>), and arithmetic -- the same expression language scenarios use. Press Enter, Escape, or click elsewhere to close the editor. Escape closes only the innermost thing that is open -- a completion list, a bound edit, the editor itself -- and never the panel or dialog around the form; close those from their own buttons. Closing tidies a valid expression's formatting (spacing, redundant parentheses) without changing its meaning. A value may also be left empty: an empty cell reads as its type's neutral value -- 0 for numbers, false for booleans, "" for text, the nil UUID -- shown grayed in the cell, and it is never an error. An empty dynamic-row count means 1 token; an empty place count means 0.
Opening a value with Enter or a second click selects its whole content, so typing replaces it. Opening by typing keeps the caret right after what you typed.
Keyboard editing and undoCopy link to this section
Section headers stack at the top as you scroll. Earlier headers fade slightly; click one to return to that section. Upcoming section headers stay at the bottom; click one to jump ahead. A soft fade marks the edge where content scrolls beneath the headers and clears when you return to the section's start. Spreadsheet text does not select when dragged; text selection remains available inside an open editor.
Every table in the form is a keyboard grid: arrow keys move between cells, phantom rows and type selects included, and moving up from a dynamic row's cells lands on its count strip, so counts and bounds are editable without the mouse. While an editor is open on a value that is just a number (or empty), the up and down arrows step it by 1 (by 10 with Shift held); a ratio steps by 0.1 (by 0.01 with Shift held) and stays between 0 and 1; on a boolean value, Up sets true and Down sets false; text and UUID values leave the arrows to the editor. Where the form lays its sections out as side-by-side columns (the quick-simulation embedding), vertical arrows stay within a column, and a horizontal arrow at a table's edge crosses into the neighbouring column, returning you to the cell you last used there. Tab keeps its usual browser behaviour throughout the form (inside an open row menu it dismisses the menu, as menus do). A token table's column headers are the grid's top line. In a token table, the left arrow from a row's first cell reaches the row gutter: focusing it highlights and selects the whole row, Enter opens the row's menu, and Delete removes the row. The menu is a keyboard menu too: it opens with the current kind focused, arrow keys move through the items, Enter chooses, and Escape returns to the gutter. Every row action lives in that menu -- the row kinds and Delete row.
The walk does not stop at a table's edge: moving down from a table's last row continues to the next part of the form -- a section header, a place header, the next table -- and moving up continues backwards the same way. Collapsed sections are skipped.
The whole form has one undo history: Cmd/Ctrl+Z undoes and Shift+Cmd/Ctrl+Z (or Ctrl+Y) redoes any edit -- a changed value, an added or deleted row, a shared column, an interval toggle. Typing in one value counts as a single step, however long the pause; editing another value starts the next step. Redo restores exactly the state you undid from. An open text editor keeps its own text-level undo until you close it.
Connections around the focused valueCopy link to this section
Focusing a value highlights what it is connected to, in amber. A cell that reads a Variable or a net parameter highlights those rows; focusing a Variable or a Parameter row highlights every cell whose expression reads it. The highlight follows the vocabulary: scenario.<name> connects to a top-level Variable, parameters.<name> to a net parameter, and a bare name to a variable of the same place.
Places without a token typeCopy link to this section
A place without a token type is its name above one full-width token count cell -- the same expression cell as everywhere else, in its own bordered box.
Places with a token typeCopy link to this section
A place with a token type is a token table with one column per field of the type. Each row is one of three kinds, chosen from the row menu: a click on the row's gutter selects the row, and the menu opens from the ⋯ button that appears there (or by pressing Enter on the gutter):
- Fixed (
#1,#2, ...) -- the row emits exactly one token. - Dynamic (
i, blue) -- the row emits many tokens: a quiet strip above the cells shows×and the row's count expression, and each cell is evaluated once per token withirunning from0tocount - 1(countis also available). The gutter's tooltip shows the row number. - Swept count (
i, purple; experiments with sweeps only) -- a dynamic row whose count is a swept parameter: the strip shows the count's bounds,× 0 … 12.
Changing a row's kind never loses anything: its count (bounds included) is restored when you change back. The dimmed trailing row is a phantom row, and its cells follow the same selection model as every other cell: a first click selects one, and a second click (or Enter, or the row's + gutter) materializes a new fixed row. Remove a row from its gutter: the menu offers Delete row, and the Delete key removes it directly. In fixed rows, i is the row's position in the list and count is 1.
Each typed place shows its token total at the top-right, aligned with its name, whether expanded or collapsed. This applies in Simulation Settings, scenario forms, and experiment forms, including computed-state previews. The total is a number when every count resolves, otherwise the unresolved counts printed as they are (for example 2 + scenario.n_satellites tokens).
Shared columnsCopy link to this section
Click a column header to give the whole column one shared value: the column takes a subtle wash, the shared value slot appears directly below the header, and the cells beneath turn dimmed and chevron-prefixed -- clicking one edits the shared value. Click the header again to release the column: every cell returns exactly to what it held before, and the shared value is remembered in case you share again.
Per-place variablesCopy link to this section
Each place block can declare its own variables from its Add a variable line, scoped to that place's rows and referenced by bare name. They are evaluated per row, so they may read i -- use one for a per-token intermediate value such as an angle.
A dynamic row's count may read the place's variables too, as long as their values don't use i or count -- the count runs once, before any token exists. A count that reads an i-dependent variable shows an error on the count itself.
Type checkingCopy link to this section
Every expression is type-checked as you work. The open editor marks problems inline; a closed value with a problem underlines in red and shows the message when you hover it. Cells inherit their type from the token type's field; declared types exist on Variables and counts only. Structural rules (duplicate names, bounds that do not resolve, sweeping a text field) surface the same way, on the value they belong to.
Interval selections (experiments)Copy link to this section
In the create-experiment panel, every numeric value slot -- cells, counts, variables, shared columns, and net parameters -- carries a labeled interval toggle, purple while on: under the open cell editor, and on the row for Variables and Parameters. It reads Sweep. Starting the in-browser optimizer is a separate choice, during creation or later from the results. Turning it on replaces the expression with Min and Max cells; an interval declares nothing else, so there is no Scale or Step. Each bound is an expression cell with the same selection model as the rest of the form -- select it, press Enter (or click again) to edit, Enter or Escape to leave; Escape from a selected cell closes the editor. Turning the toggle off restores the expression you had, and the bounds are remembered too. A selected value shows its bounds (0 … 12) on a purple slot. Boolean and text values offer no toggle, and changing a selected Variable to boolean turns its toggle off; a cell muted by a shared column does not count. A row's gutter menu offers Swept count for a dynamic row's count.
Each selection becomes a swept parameter of the experiment with a deterministic name, shown in the sweep navigator under the value's path (Space › item 0 › x):
adhoc_<place>_r<row>_<field>-- a cell in a fixed or dynamic row.adhoc_<place>_col_<field>-- a shared column value.adhoc_count_<place>-- an untyped place's count;adhoc_count_<place>_r<row>for a dynamic row's count.adhoc_var_net_<name>-- a top-level Variable; place-scoped variables use the place's name as the scope.adhoc_param_<variable_name>-- a net parameter override.
Bounds must resolve to constants, integer values need integer bounds, and the maximum must exceed the minimum; a value that does not run shows its problem on the bound, and the panel's footer names it. The experiment then behaves like any parameter sweep: the initial state compiles at the navigator's selection, parameter overrides follow each run's draw. When you start optimization, the study searches the generated parameters like any others; only Constraints need a saved scenario.
A saved scenario shown through the form in the experiment panel offers the same toggle on each numeric scenario parameter row.
Saving a scenario from the formCopy link to this section
Creating a scenario opens the same form -- name and description above it -- as the one authoring surface. Each top-level Variable's row carries a Scenario Parameter toggle: an exposed Variable becomes one of the saved scenario's tunable parameters, named after the Variable in snake_case (baseLoad becomes base_load), defaulting to its expression's value -- which must therefore be a constant, and between 0 and 1 for a ratio Variable, which becomes a ratio parameter. Everyone running the scenario can then adjust it wherever scenario parameters appear, without editing the scenario.
Saving keeps your form entries as the scenario's definition, so editing the scenario reopens exactly the form you left.
Selecting a saved ad-hoc scenario in Simulation Settings shows it through the same form, read-only: only the scenario parameters (the exposed Variables) take value edits, for that run alone. The Parameters and Initial state sections show computed values, updating when you change a scenario parameter. Select a value to see its source expression in a floating cell over the selected value. The expression disappears when focus moves away. Auxiliary Variables stay hidden. Editing any scenario opens this form: a scenario saved per place by an earlier version or by the AI assistant opens converted, and saving stores it in the form's format; a scenario that defines its initial state as code keeps that code, shown read-only -- edit its name, description, Variables and Parameters here, or recreate it from the form with a Dynamic row (see Scenarios). Such a scenario stores no form entries, so every Variable must be marked Scenario Parameter to be kept -- the form refuses to save one that is not.
ErrorsCopy link to this section
Ad-hoc definitions are validated as you type, on the value they belong to, and again when you run. Hover over an underlined value to read its error, or open the value editor to see the error below the input. In quick simulation, compile problems also appear in the Simulation Settings error banner; in the experiment panel, in the footer.