Replace the cramped Samples dropdown with a modal that lays the gallery
out as a card grid, sectioned by tier, so the growing set stays scannable
and the learning order is visible at once.
Move Farmed cobras to the left so the story reads in order (farm engine
-> release bridge -> wild -> cull) and the release bridge no longer
doubles back across the canvas. Positions only; dynamics unchanged.
Two equal researchers and one conserved prize (the field's attention):
a single gap-driven Flow tilts it to whoever is a hair ahead, so a 51-49
near-tie locks in to ~100-0. Escalation's zero-sum twin -- the same
two-Stock all-Reinforcing structure, concentrating instead of exploding.
2026-06-22 23:33:06 +02:00
3 changed files with 260 additions and 53 deletions
* 6. Predator and prey — two coupled Stocks whose interlocking loops oscillate.
* 6. Predator and prey — two coupled Stocks whose interlocking loops oscillate.
* 7. Epidemic — a chain of Stocks joined by Stock→Stock Flows: no clouds.
* 7. Epidemic — a chain of Stocks joined by Stock→Stock Flows: no clouds.
*
*
* Last, four of Donella Meadows' system *traps* — structures that reliably misbehave
* Last, five of Donella Meadows' system *traps* — structures that reliably misbehave
* (Thinking in Systems, ch. 5), to contrast the healthy dynamics above — and, paired
* (Thinking in Systems, ch. 5), to contrast the healthy dynamics above — and, paired
* with the first, the cure that escapes it:
* with the first, the cure that escapes it:
*
*
@@ -32,16 +32,20 @@
* *larger* than the trap's boom leaves alive.
* *larger* than the trap's boom leaves alive.
* 10. Escalation — a single Reinforcing loop spanning two Stocks, with
* 10. Escalation — a single Reinforcing loop spanning two Stocks, with
* no brake in the structure: an arms race.
* no brake in the structure: an arms race.
* 11. Fixes that fail — a fix drains the symptom Stock (B) while its side
* 11. Success to the successful — two equal rivals split one conserved prize (the field's
* attention); a gap-driven Flow tilts it to whoever leads,
* so a 51–49 near-tie locks in to ~100–0. Escalation's
* zero-sum twin — it concentrates instead of exploding.
* 12. Fixes that fail — a fix drains the symptom Stock (B) while its side
* effect refills it (R): the cure feeds the disease.
* effect refills it (R): the cure feeds the disease.
* 12. Drift to low performance — a goal that erodes toward actual performance, so the
* 13. Drift to low performance — a goal that erodes toward actual performance, so the
* effort it drives never overcomes a steady decay: a
* effort it drives never overcomes a steady decay: a
* Reinforcing loop ratchets both downward.
* Reinforcing loop ratchets both downward.
*
*
* Next, the dynamic the book is named for, and the one the gallery has saved until a
* Next, the dynamic the book is named for, and the one the gallery has saved until a
* reader knows every piece it needs:
* reader knows every piece it needs:
*
*
* 13. Overshoot and collapse — a Reinforcing harvester on a *renewable* Resource with
* 14. Overshoot and collapse — a Reinforcing harvester on a *renewable* Resource with
* an extinction threshold (an Allee floor): a fleet
* an extinction threshold (an Allee floor): a fleet
* overshoots the renewal rate and pushes the fishery past
* overshoots the renewal rate and pushes the fishery past
* the point of no return. The dark twin of "Limits to
* the point of no return. The dark twin of "Limits to
@@ -50,14 +54,14 @@
* Last, the language pointed at a live debate — a classic trap (Shifting the burden to
* Last, the language pointed at a live debate — a classic trap (Shifting the burden to
* the intervenor, ch. 5) wearing today's clothes:
* the intervenor, ch. 5) wearing today's clothes:
*
*
* 14. AI deskilling spiral — handing the burden of code quality to AI atrophies the
* 15. AI deskilling spiral — handing the burden of code quality to AI atrophies the
* Expertise that holds quality up, so the team leans on AI
* Expertise that holds quality up, so the team leans on AI
* harder and Technical debt spirals: addiction, not a fix.
* harder and Technical debt spirals: addiction, not a fix.
*
*
* And a mechanical coda — the gallery's one *hard* ceiling, to contrast the emergent
* And a mechanical coda — the gallery's one *hard* ceiling, to contrast the emergent
* ones (above all "Limits to growth"):
* ones (above all "Limits to growth"):
*
*
* 15. Bathtub with an overflow — the tap runs flat out (a Constant inflow that never
* 16. Bathtub with an overflow — the tap runs flat out (a Constant inflow that never
* reads the level) and a spillway carries whatever rises
* reads the level) and a spillway carries whatever rises
* past the brim into a second Stock, the floor. The only
* past the brim into a second Stock, the floor. The only
* model on the `overflow` rule — a one-sided Gap, the
* model on the `overflow` rule — a one-sided Gap, the
@@ -67,7 +71,7 @@
* Then one last trap, held back until the overflow rule existed to carry it — the
* Then one last trap, held back until the overflow rule existed to carry it — the
* language pointed at the most-told cautionary tale in systems thinking:
* language pointed at the most-told cautionary tale in systems thinking:
*
*
* 16. The cobra effect — a bounty on dead cobras (a Balancing fix) quietly funds a
* 17. The cobra effect — a bounty on dead cobras (a Balancing fix) quietly funds a
* cobra *farm* (a Reinforcing engine); breeding outruns what
* cobra *farm* (a Reinforcing engine); breeding outruns what
* the bounty can absorb, the farm gluts, and its now-worthless
* the bounty can absorb, the farm gluts, and its now-worthless
* surplus spills through an `overflow` gate into the wild —
* surplus spills through an `overflow` gate into the wild —
@@ -77,7 +81,7 @@
*
*
* And the capstone — every piece at once, at the scale the whole gallery points toward:
* And the capstone — every piece at once, at the scale the whole gallery points toward:
*
*
* 17. World on a warming planet — the Club of Rome's World3 (Meadows et al., *The Limits
* 18. World on a warming planet — the Club of Rome's World3 (Meadows et al., *The Limits
* to Growth*) in miniature, its pollution sector reframed
* to Growth*) in miniature, its pollution sector reframed
* as a climate channel: four coupled Stocks where two
* as a climate channel: four coupled Stocks where two
* Reinforcing engines (capital, population) overshoot a
* Reinforcing engines (capital, population) overshoot a
@@ -104,10 +108,31 @@ import {
typeSimSpec,
typeSimSpec,
}from"./types"
}from"./types"
/** A loadable example: a title and one-line blurb for the menu, plus a builder. */
/**
* The pedagogical tier a sample belongs to. Tiers run simplest-first and double as
* the section order in the sample browser (see SAMPLE_CATEGORIES).
*/
exporttypeSampleCategory=
|"Primer"
|"Classics"
|"System traps"
|"Dynamic edge"
|"Mechanics & capstone"
/** The categories in display order, simplest tier first. */
exportconstSAMPLE_CATEGORIES: SampleCategory[]=[
"Primer",
"Classics",
"System traps",
"Dynamic edge",
"Mechanics & capstone",
]
/** A loadable example: a title, one-line blurb and tier for the browser, plus a builder. */
exportinterfaceSample{
exportinterfaceSample{
title: string
title: string
blurb: string
blurb: string
category: SampleCategory
build:()=>Model
build:()=>Model
}
}
@@ -943,6 +968,82 @@ function escalation(): Model {
)
)
}
}
/**
* Success to the successful — Donella Meadows' competitive-exclusion trap (Thinking
* in Systems, ch. 5), known in the sociology of science as the *Matthew effect*
* (Robert Merton, after Matthew 25:29: "unto every one that hath shall be given").
* Two researchers of equal ability compete for one finite thing — the field's
* attention — and the only difference between them is that A begins a single point
* ahead (Renown 51 vs 49 of a fixed 100).
*
* The community's attention is a *conserved* budget: a citation, an invitation, a
* grant that goes to one does not go to the other, so Renown A + Renown B never
* leaves 100. The marginal piece of it drifts to whoever is already better known —
* `attention = factor × (Renown A − Renown B)`, a single Stock→Stock Flow draining
* the lesser name into the greater. There are no clouds: nothing enters or leaves
* the system, it only *redistributes*. That one valve carries *two* Reinforcing
* loops — Renown A → [+] → attention → (fills A) → Renown A (more renown wins more
* attention), and Renown B → [−] → attention → (drains B) → Renown B (the falling
* name is forgotten ever faster). Neither loop has a surviving `−`, so both are
* Reinforcing: nothing brakes the gap, and it can only widen.
*
* A tie is therefore an *unstable* equilibrium — the knife-edge this trap balances
* on. A's one-point lead is enough: attention tilts to A, the gap grows, attention
* tilts harder, and the field locks in. Renown A climbs 51 → 100 and Renown B fades
* 49 → 0 by t≈42 — a near-total monopoly of acclaim, though the two were equally
* able. The cruel lesson Meadows draws: where the prize for winning is more power to
* win, it is *initial conditions*, not merit, that decide the outcome.
*
* Contrast "Escalation", the gallery's other two-Stock all-Reinforcing trap: there
* the cross-loop has no minus and *both* arsenals blow up together (positive-sum,
* unbounded); here the single loop is zero-sum — A rises only as fast as B is drained
* — so the same Reinforcing structure *concentrates* instead of exploding. (The cure
* Meadows prescribes is to break the coupling — level the field, diversify the prize,
* or handicap the leader — none of which the structure here contains: that is the trap.)
*/
functionsuccessToTheSuccessful():Model{
// Two Stocks on one line, the lone attention valve nudged above their midpoint so
// the pipe (Renown B → attention → Renown A) and the two info links (each Stock
// into the valve) read apart instead of overlapping. Hand-placed, not at midpoint.
constrenownB=makeStock({x:-260,y: 80},"Renown B")
renownB.initialValue=49
renownB.description=
"Researcher B's standing — equal in ability to A, and a single point behind at the start. The lesser name the attention drains away from, fading to nothing though B never did anything wrong."
constrenownA=makeStock({x: 260,y: 80},"Renown A")
renownA.initialValue=51
renownA.description=
"Researcher A's standing — one point ahead at the start, and that hair's lead is all it takes. Attention concentrates here until A holds nearly the whole field's acclaim."
// attention = factor × (Renown A − Renown B): a Gap whose `+` level is A and `−`
// target is B. Source B, target A, so a positive rate drains the lesser name into
// the greater — and since draining B only widens the gap, the rate never reverses.
"The field's finite attention drifting to the better-known name, ∝ the lead (Renown A − Renown B). A conserved transfer: what A gains, B loses — the one valve through which both Reinforcing loops run."
returnmodel(
"Success to the successful",
[renownB,renownA,attention],
[
link(
renownA,
attention,
"+",
"Renown A is the level in the gap: the further ahead A is, the faster attention flows its way. With the inflow it fills, this closes A's Reinforcing loop — the rich getting richer.",
),
link(
renownB,
attention,
"-",
"Renown B is the target the gap is measured against (the − input). As B fades the gap only widens, so it is drained faster still — a second Reinforcing loop, the same minus on both the link and the outflow.",
),
],
// From a 51–49 near-tie the gap runs away: Renown A climbs 51 → ~100 and Renown B
// fades 49 → ~0 by t≈42, then both hold — a near-total monopoly of acclaim won on a
// one-point head start. The unstable 50–50 knife-edge a hair's difference tips.
{start: 0,stop: 50,dt: 1},
)
}
/**
/**
* Fixes that fail — the archetype where a quick fix relieves a symptom but feeds it
* Fixes that fail — the archetype where a quick fix relieves a symptom but feeds it
* through a side effect, so the symptom returns and the fix is reapplied for ever.
* through a side effect, so the symptom returns and the fix is reapplied for ever.
@@ -1485,23 +1586,23 @@ function bathtubOverflow(): Model {
* is a Stock the reward built, the brake is the overflow gate, and the damage is permanent.
* is a Stock the reward built, the brake is the overflow gate, and the damage is permanent.
*/
*/
functioncobraEffect():Model{
functioncobraEffect():Model{
// The policy lever (bounty) sits up top, centre, wired into three flows at once: the
// Laid out left→right: the farm engine on the left (a Source breeds Farmed cobras,
// intended cull of Wild cobras on the left, and on the right the farm's breeding and
// harvest draining up to a Sink), the release bridge in the centre spilling the glut
// cash-out. The release bridge dips below, carrying the farm's glut back across to the
// rightward into Wild cobras, and the bounty-driven cull running off to the right. The
// wild, with glut hanging beneath it. Valves are hand-placed, not at midpoints, so
// policy lever (bounty) sits up top, wired down into all three flows — cull, breeding,
// every Information Link lands in open space.
// cash-out — with glut beneath the bridge it gates. Hand-placed valves keep links clear.
"The reward paid per dead cobra — held at 1, a normalised policy lever, so every rate here scales with it (a bigger bounty would only run the whole story faster). One lever wired into three flows: the cull, the breeding, and the cash-out."
"The reward paid per dead cobra — held at 1, a normalised policy lever, so every rate here scales with it (a bigger bounty would only run the whole story faster). One lever wired into three flows: the cull, the breeding, and the cash-out."
// The intended fix: a bounty-driven cull empties the streets of wild cobras.
// The intended fix: a bounty-driven cull empties the streets of wild cobras.
constwild=makeStock({x:-360,y:-40},"Wild cobras")
constwild=makeStock({x: 380,y:-40},"Wild cobras")
wild.initialValue=100
wild.initialValue=100
wild.description=
wild.description=
"The actual problem the bounty targets — hunted down at first, then overrun once the farm's surplus is loosed on it. It has no inflow of its own, so any rebound can only be the farm's doing."
"The actual problem the bounty targets — hunted down at first, then overrun once the farm's surplus is loosed on it. It has no inflow of its own, so any rebound can only be the farm's doing."
"Cobras bred to cash in on the bounty — the Stock the reward calls into being. It compounds unseen while the streets look clear, then spills its surplus into the wild."
"Cobras bred to cash in on the bounty — the Stock the reward calls into being. It compounds unseen while the streets look clear, then spills its surplus into the wild."
// breeding = 0.31 × Farm × bounty: Farm → breeding → Farm, no `−` → the Reinforcing
// breeding = 0.31 × Farm × bounty: Farm → breeding → Farm, no `−` → the Reinforcing
// engine the bounty funds without meaning to.
// engine the bounty funds without meaning to.
breeding.rule={kind:"proportional",factor: 0.31}
breeding.rule={kind:"proportional",factor: 0.31}
breeding.description=
breeding.description=
"The farm breeding more cobras, ∝ Farmed cobras × bounty — the Reinforcing engine the bounty funds without intending to: more breeding stock, more bred."
"The farm breeding more cobras, ∝ Farmed cobras × bounty — the Reinforcing engine the bounty funds without intending to: more breeding stock, more bred."
// harvest = 0.10 × Farm × bounty: farmed cobras killed and turned in — the rule beating,
// harvest = 0.10 × Farm × bounty: farmed cobras killed and turned in — the rule beating,
// and a Balancing drain on the farm.
// and a Balancing drain on the farm.
harvest.rule={kind:"proportional",factor: 0.1}
harvest.rule={kind:"proportional",factor: 0.1}
@@ -1531,11 +1632,11 @@ function cobraEffect(): Model {
// The backfire bridge: once the farm gluts, its worthless surplus is dumped into the
// The backfire bridge: once the farm gluts, its worthless surplus is dumped into the
// wild. A one-sided overflow gate (shut below the glut) — no scripted policy reversal
// wild. A one-sided overflow gate (shut below the glut) — no scripted policy reversal
// needed; the release falls out of the farm outgrowing its own worth.
// needed; the release falls out of the farm outgrowing its own worth.
constglut=makeConverter({x: 0,y: 300},"glut")
constglut=makeConverter({x:-260,y: 260},"glut")
glut.rule={kind:"constant",value: 200}
glut.rule={kind:"constant",value: 200}
glut.description=
glut.description=
"The farm size past which cobras lose their worth (a fixed 200) — the threshold the spill opens above. A structural stand-in for the day the bounty was scrapped and the snakes became worthless."
"The farm size past which cobras lose their worth (a fixed 200) — the threshold the spill opens above. A structural stand-in for the day the bounty was scrapped and the snakes became worthless."
// releases = max(0, 0.6 × (Farm − glut)): shut while the farm is worth keeping, then it
// releases = max(0, 0.6 × (Farm − glut)): shut while the farm is worth keeping, then it
// carries off the surplus. The overflow that overruns the wild — and, draining the farm
// carries off the surplus. The overflow that overruns the wild — and, draining the farm
// above the glut, the Balancing brake that caps it.
// above the glut, the Balancing brake that caps it.
@@ -1862,88 +1963,116 @@ function worldOnAWarmingPlanet(): Model {
/** The gallery, ordered simplest first. */
/** The gallery, ordered simplest first. */
exportconstSAMPLES: Sample[]=[
exportconstSAMPLES: Sample[]=[
{title:"Bathtub",blurb:"A stock filled and drained — no feedback yet.",build: bathtub},
{
title:"Bathtub",
blurb:"A stock filled and drained — no feedback yet.",
category:"Primer",
build: bathtub,
},
{
{
title:"Savings account",
title:"Savings account",
blurb:"Interest on a balance: a Reinforcing loop.",
blurb:"Interest on a balance: a Reinforcing loop.",
category:"Primer",
build: savings,
build: savings,
},
},
{
{
title:"Coffee cooling",
title:"Coffee cooling",
blurb:"Settling toward room temperature: a Balancing loop.",
blurb:"Settling toward room temperature: a Balancing loop.",
category:"Primer",
build: coffee,
build: coffee,
},
},
{
{
title:"Population",
title:"Population",
blurb:"Births and deaths: Reinforcing and Balancing together.",
blurb:"Births and deaths: Reinforcing and Balancing together.",
category:"Primer",
build: population,
build: population,
},
},
{
{
title:"Limits to growth",
title:"Limits to growth",
blurb:"Growth into a ceiling: a Reinforcing and a Balancing loop on one Flow.",
blurb:"Growth into a ceiling: a Reinforcing and a Balancing loop on one Flow.",
category:"Classics",
build: limitsToGrowth,
build: limitsToGrowth,
},
},
{
{
title:"Predator and prey",
title:"Predator and prey",
blurb:"Two coupled Stocks whose loops make them oscillate.",
blurb:"Two coupled Stocks whose loops make them oscillate.",
category:"Classics",
build: predatorPrey,
build: predatorPrey,
},
},
{
{
title:"Epidemic",
title:"Epidemic",
blurb:"Susceptible → Infected → Recovered: a chain of Stocks, no clouds.",
blurb:"Susceptible → Infected → Recovered: a chain of Stocks, no clouds.",
category:"Classics",
build: epidemic,
build: epidemic,
},
},
{
{
title:"Tragedy of the commons",
title:"Tragedy of the commons",
blurb:"Two Reinforcing herds overgraze a renewable Stock, then starve with it: a system trap.",
blurb:"Two Reinforcing herds overgraze a renewable Stock, then starve with it: a system trap.",
category:"System traps",
build: tragedyOfTheCommons,
build: tragedyOfTheCommons,
},
},
{
{
title:"Tragedy of the commons, fixed",
title:"Tragedy of the commons, fixed",
blurb:"Regulate the same renewable commons with a reserve: it holds, and the herds last.",
blurb:"Regulate the same renewable commons with a reserve: it holds, and the herds last.",
category:"System traps",
build: tragedyOfTheCommonsFixed,
build: tragedyOfTheCommonsFixed,
},
},
{
{
title:"Escalation",
title:"Escalation",
blurb:"An arms race: one Reinforcing loop spanning two Stocks.",
blurb:"An arms race: one Reinforcing loop spanning two Stocks.",
category:"System traps",
build: escalation,
build: escalation,
},
},
{
title:"Success to the successful",
blurb:
"Two equal researchers, one a hair ahead: the field's attention locks onto the leader and the rival fades — a winner-take-all trap.",
category:"System traps",
build: successToTheSuccessful,
},
{
{
title:"Fixes that fail",
title:"Fixes that fail",
blurb:"Road building eases congestion (B) but induces the traffic that refills it (R).",
blurb:"Road building eases congestion (B) but induces the traffic that refills it (R).",
category:"System traps",
build: fixesThatFail,
build: fixesThatFail,
},
},
{
{
title:"Drift to low performance",
title:"Drift to low performance",
blurb:"An eroding goal leaves steady decay no floor: both slide downhill.",
blurb:"An eroding goal leaves steady decay no floor: both slide downhill.",
category:"System traps",
build: driftToLowPerformance,
build: driftToLowPerformance,
},
},
{
{
title:"Overshoot and collapse",
title:"Overshoot and collapse",
blurb:"A fleet overfishes past the point of no return: the stock collapses for good.",
blurb:"A fleet overfishes past the point of no return: the stock collapses for good.",
category:"Dynamic edge",
build: overshootAndCollapse,
build: overshootAndCollapse,
},
},
{
{
title:"AI deskilling spiral",
title:"AI deskilling spiral",
blurb:"Leaning on AI to hold quality erodes the expertise that holds it: shifting the burden.",
blurb:"Leaning on AI to hold quality erodes the expertise that holds it: shifting the burden.",
category:"Dynamic edge",
build: aiDeskillingSpiral,
build: aiDeskillingSpiral,
},
},
{
{
title:"Bathtub with an overflow",
title:"Bathtub with an overflow",
blurb:
blurb:
"A flat-out tap and a spillway: the excess spills to a second Stock and the level holds.",
"A flat-out tap and a spillway: the excess spills to a second Stock and the level holds.",
category:"Mechanics & capstone",
build: bathtubOverflow,
build: bathtubOverflow,
},
},
{
{
title:"The cobra effect",
title:"The cobra effect",
blurb:
blurb:
"A bounty on dead cobras breeds a cobra farm; its glut spills into the wild, leaving four times the snakes: a perverse incentive.",
"A bounty on dead cobras breeds a cobra farm; its glut spills into the wild, leaving four times the snakes: a perverse incentive.",
category:"Mechanics & capstone",
build: cobraEffect,
build: cobraEffect,
},
},
{
{
title:"World on a warming planet",
title:"World on a warming planet",
blurb:
blurb:
"The Club of Rome's World3 in miniature, with a climate channel: growth overshoots a finite planet and the carbon it burns locks in the heat that finishes it.",
"The Club of Rome's World3 in miniature, with a climate channel: growth overshoots a finite planet and the carbon it burns locks in the heat that finishes it.",
category:"Mechanics & capstone",
build: worldOnAWarmingPlanet,
build: worldOnAWarmingPlanet,
},
},
]
]
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.