Add multi-event bowtie screenshot to README

The existing screenshots only show single-event bowties. Add a two-event
("chained") scenario - a flammable gas release escalating to an ignited
release - generated from the real layout engine, showing between-event
barriers separating two top events, and feature it in the README.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Andre482 2026-06-27 20:01:37 +03:00
parent 1f07328a29
commit 99cddf17ef
3 changed files with 58 additions and 0 deletions

View file

@ -10,6 +10,10 @@ Diagrams are stored as `.bowtie` files in your vault and auto-save as you edit.
*A bowtie for a cold-storage ammonia loss-of-primary-containment scenario.*
![A two-event bowtie where a loss of containment of flammable gas escalates to an ignited release, with between-event barriers (gas detection and emergency shutdown, ignition source control) separating the two top events](assets/screenshot-multi-event.png)
*A chained, multi-event bowtie: between-event barriers sit between two top events, so threats feed the first event and consequences flow from the second.*
![A prevention barrier with its full analysis stack — type, effectiveness, criticality, responsible party, validation method, and status — plus a safeguard and degradation factor below it](assets/screenshot-barrier.png)
*Per-barrier analysis stacks and escalation factors (safeguards and degradation factors).*

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View file

@ -141,6 +141,59 @@ function buildBarrierBowtie(model) {
return bt;
}
// Two-event ("chained") bowtie: a loss of containment that can escalate to an
// ignited release. Threats feed the first top event, between-event barriers sit
// between the two top events, and consequences flow from the second top event.
function buildMultiEventBowtie(model) {
const bt = model.createBowtie("Flammable gas release escalating to fire");
bt.events[0].label = "Loss of containment of flammable gas";
bt.events[0].hazard = "Pressurised flammable hydrocarbon";
const ignited = model.createTopEvent(
"Ignited release — jet fire / explosion",
"Ignition energy & confinement"
);
bt.events.push(ignited);
const gasDetect = model.createBarrier("Gas detection & emergency shutdown (ESD)");
addStack(model, gasDetect, [
["type", "Active Hardware+Human"],
["effectiveness", "Good"],
["criticality", "Very High"],
]);
const ignitionControl = model.createBarrier("Ignition source control / hazardous area");
addStack(model, ignitionControl, [
["type", "Passive Hardware"],
["status", "Available"],
]);
bt.events[0].transitionBarriers = [gasDetect, ignitionControl];
const corrosion = model.createThreat("Corrosion / erosion of pipework");
corrosion.preventionBarriers = [
model.createBarrier("Mechanical integrity inspection"),
model.createBarrier("Corrosion monitoring"),
];
const overpressure = model.createThreat("Process overpressure");
overpressure.preventionBarriers = [model.createBarrier("Pressure relief & high-pressure trip")];
const leak = model.createThreat("Flange / seal leak");
leak.preventionBarriers = [model.createBarrier("Flange management & leak testing")];
bt.threats = [corrosion, overpressure, leak];
const injury = model.createConsequence("Personnel burns / fatality");
const fireProt = model.createBarrier("Fireproofing & deluge protection");
addStack(model, fireProt, [
["type", "Active Hardware"],
["status", "Available"],
]);
injury.mitigationBarriers = [fireProt, model.createBarrier("Emergency response & evacuation")];
const escalation = model.createConsequence("Escalation to adjacent units");
escalation.mitigationBarriers = [model.createBarrier("Plant spacing & blast walls")];
bt.consequences = [injury, escalation];
return bt;
}
function renderNodeHtml(node, barriersById) {
const wrapStyle = `left:${node.x}px;top:${node.y}px;width:${node.width}px;height:${node.height}px`;
const inner = renderNodeInner(node, barriersById);
@ -271,6 +324,7 @@ async function main() {
const page = await browser.newPage({ deviceScaleFactor: 2 });
try {
await capture(page, engine, buildHeroBowtie(engine.model), join(assetsDir, "screenshot-diagram.png"));
await capture(page, engine, buildMultiEventBowtie(engine.model), join(assetsDir, "screenshot-multi-event.png"));
await capture(page, engine, buildBarrierBowtie(engine.model), join(assetsDir, "screenshot-barrier.png"));
} finally {
await browser.close();