Strombild — language reference
A model is a graph of stocks (things that accumulate) and
flows (things that move stuff between them). The engine walks it forward in
time — that walk is the simulation. Two channels: : is definition (what
a thing is), @ is visual (how it's drawn). Strip every
@ and the model still runs.
Stocks
- node x : range(0, 50), init(30)
- a stock that accumulates; clamped to range, optional start value
- external src
- a boundary source/sink — doesn't accumulate; role set by edge direction
Flows — edge : rate(...)
- constant(c)
- a fixed rate; reads nothing
- proportional(of, k)
- k · of (
of defaults to the edge source)
- hill(of, max, k, n)
- saturating/cooperative curve: max·ofⁿ/(kⁿ+ofⁿ)
- gated(of, k)
- proportional, throttled as the destination fills (soft backpressure)
- adjust(of, target, k)
- negative feedback to a setpoint: k·(target−of); may run backwards
Reactions & events — on the pathway
- a + b -> c : limiting(k)
- a recipe reading several inputs at one shared rate (the bottleneck)
- 2 a + b -> c : mass_action(k)
- stoichiometry; k·∏ inputᶜᵒᵉᶠᶠ
- event ship : x >= 20 : x = 0, y += 20
- a discrete snap — guard then resets a flow can't ooze
Visuals (@)
- @ bucket(fill, threshold)
- a tapered pail; fill = water | dots | squares; threshold = auto|<num>
- @ box(fill, threshold)
- a straight-sided crate/tank
- edge @ pipe | rotor
- pipe = animated flow (default); rotor = the flux drawn as a spinning wheel
Compose
node tub : range(0, 50) @ bucket
external faucet
external drain
faucet -> tub : constant(c = 3)
tub -> drain : proportional(k = 0.1)
pathway leaky_tub : faucet->tub, tub->drain
Notes
# starts a comment to the end of the line.
- A pathway names which edges are live — also how you "comment out" a path without deleting it.
- Influence (a rate's
of, an event's guard/writes) is drawn as dashed arrows — information, not mass — and is derived, never declared.
- Engine: forward Euler; stocks clamp to
range; externals don't accumulate.