Scenario: a boiler house
A coal fire under a boiler. Steam goes through a throttle to an engine; the engine turns a shaft; the shaft turns a generator; the generator feeds a lamp. Nothing is scripted: the lamp is bright because the pressure is high, and the pressure is high because the fire is hot.
This page shows how capabilities talk to each other, and where the energy goes.
The chain#
| Stage | Capability | Object | Passed to the next stage by |
|---|---|---|---|
| Fire (a power in watts) | none | a number | boiler.step(dt, heat) |
| Boiler: water and steam, safety valve | combustion | Boiler | the engineOnBoiler link |
| Engine: steam through a throttle | links | engineOnBoiler | a torque on the shaft |
| Shaft with a flywheel | machines | Drivetrain | gen.omega = shaft.omega, drive(shaft, () => gen.torque) |
| Generator and load | electricity | Circuit, DCMachine, Resistor | the lamp's power |
Every arrow is either a link from the links package or two lines of glue: read one side's field, write the other's. The capabilities know nothing about each other. The scene closes the loop.
Building it#
const boiler = new Boiler({ volume: 0.5, water: 200, T: 450, safety: { pressure: 1.2e6, area: 5e-4 } });
const train = new Drivetrain();
const shaft = train.shaft({ name: 'flywheel', J: 20, b: 0.5 });
const engine = engineOnBoiler(boiler, shaft, { area: 3e-5, exhaust: 101325,
work: (p1, p2) => steamWork(p1, p2, 0.15), maxTorque: 500 });
const circuit = new Circuit();
const gen = circuit.add(new DCMachine('G', 'a', '0', 1.0, 0.2));
const lamp = circuit.add(new Resistor('Lamp', 'a', '0', 5));
train.drive(shaft, () => gen.torque); // the generator loads the shaft
Each step, in this order: heat the boiler (boiler.step(dt, fire)), step the engine link, copy the shaft speed into the generator (gen.omega = shaft.omega), step the drive train, step the circuit. In a game the capabilities and the links capability do this for you.
What to read off#
- Pressure is set by the fire against the engine's demand for steam and the valve. Open the throttle (a larger
area) and the boiler is drawn down; close it and the valve lifts. The valve holds the pressure to within a few percent of its setting. - The ledger. Only a small part of the fire's heat reaches the lamp as electricity; a steam engine at 15 % efficiency delivers well under 20 %. The rest leaves with exhaust steam and vented steam.
boiler.heatIn,boiler.energyOut,boiler.ventedand the engine link'smovedsay where each joule went. Put them in the links capability's account (cap.account({ name, joules })) and a leak anywhere shows up as a drifting total. - The load. A smaller resistance instead of the lamp draws more current, loads the shaft harder and slows it; a short circuit would stall the engine. Put a
Fusein series to protect it.
Making it a game scene#
Show the boiler's pressure and the shaft speed on a gauge. Expose the fire's power as a command (heat.add) so a stoker can feed it. Hand the lamp's circuit node to lampLight (fx).
If the safety valve is blocked (safety.area = 0), the pressure climbs until the drum gives out. Hand that vessel to explosions (detonate({ vessel })), and the boiler explosion every steam age feared is one call.
What to change#
| Change | Effect |
|---|---|
| Fire doubled | the pressure rises to the valve, the valve vents the excess; more power to the lamp until the engine's torque cap |
| Throttle closed | the engine stops and the boiler builds pressure to the valve |
| Smaller generator resistance | more current, more load on the shaft, lower speed |
Cold feed water (boiler.feed(kg, T)) | pressure drops while the cold water is heated |
A second consumer on boiler.take | the engine starves and the pressure sags |
The complete run, with the numbers it must produce, is in tests/unit/examples/physics-scenarios-boiler-house.test.ts.