Links between capabilities
Package @ferret/physics-links, capability name links, phase stretch (order 1000, last).
What it is for#
Each physics capability knows only itself. A link is where one capability's output becomes another's input, so a world closes its loops: a chemical vessel sits in a water bath, a hot wall warms the gas of a tank, a slipping brake heats its drum, steam from a boiler turns a shaft, a reactor's coolant drives a turbine, a screw on a shaft pushes a ship and loads the engine, an arc fault blasts, an overloaded wire lights a fire.
Links read and write the plain fields and methods of the objects they join (a heat part, a chemical vessel, a gas volume, a shaft, a reactor, a thruster, a kernel body), so the package imports none of their packages and you can write your own in a dozen lines.
The model#
A Link is { kind, moved, step(dt, host, contacts) }. step reads one side, writes the other, once per world step after the capabilities have stepped; moved counts the energy that crossed (J). The links capability holds a list of them and keeps the scene energy account: you register terms (stores such as kinetic, heat, chemical, electric; and sinks such as losses and the condenser), and energy() sums them. In a closed scene the total stays where it started.
| Link | Joins | Does |
|---|---|---|
vesselInPart(vessel, part, net) | Q → H | the part is the vessel's surroundings; what the vessel loses goes into the part |
gasInPart(gas, part, net, G, at?) | gas ↔ H | heat flows through G W/K; a hot wall raises the pressure of a tank |
slipHeats(coupling, part, net) | M → H | what a slipping clutch, belt or brake loses heats the part |
plasticHeats(link, part, net, share?) | E → H | 90 % of the plastic work of a stretched link becomes heat |
stagnationHeats(part, net, {speed, ambient, G}) | air → H | a skin warms toward T + r v² / 2cp |
reservoirInPart(res, part, net, {G, density, cp}) | L → H | a tank's liquid warms to its wall; the wall pays what the liquid took |
reactorHeatsPart(reactor, part, net, G) | N → H | decay heat that the coolant no longer carries warms the structure |
turbineOnReactor(reactor, shaft, {efficiency, maxTorque}) | N → M | a share of the coolant's heat becomes shaft torque |
engineOnBoiler(boiler, shaft, {area, exhaust, work, maxTorque, throttle?}) | K → M | steam through a throttle turns the shaft; the boiler loses it with its enthalpy |
boilerFed(boiler, tank, {setpoint, rate}) | L → K | a feed pump moves liquid into a boiler; an empty tank starves it |
screwOnShaft(thruster, shaft, {diameter, kt, kq}) | M → V | thrust from shaft speed, the water's torque back on the shaft |
armatureOf(coil, body, pole, kernel), coilPulls(...) | W → bodies | an electromagnet pulls an armature |
arcFlash(world, {circuit, at, voltage, detonate}) | W → X | from a short until the circuit clears, the arc's energy goes into a blast |
wireFire(world, {circuit, element, target}) | W → fire | an overheated wire ignites its target once |
mudOver(terrain, media, {box}) | T → D | wet ground makes a mud medium; it goes when the ground dries |
navFollowsTerrain(world, terrain, {rebuild}) | T → nav | a dug trench or heap rebuilds the navigation mesh once digging stops |
First use: a brake heats its drum, and the energy adds up#
import { slipHeats, links } from '@ferret/physics-links';
const cap = links();
cap.add(slipHeats(brake, drum, net)); // the brake's losses become heat in the drum
cap.account({ name: 'wheel', joules: () => train.kinetic() }); // the stores that make up the scene's energy
cap.account({ name: 'drum', joules: () => drum.H });
cap.energy().total; // stays where it started, in a closed scene
When the brake slows the wheel, its rotation goes into the drum: the wheel's term falls, the drum's rises by the same amount, and the total stays put. If the sum of your terms drifts, a link or a capability is losing energy. That is the way to find a bug in a scene.
Recipes#
A hot wall and a tank#
cap.add(gasInPart(gas, wall, net, 2)); // 2 W/K between the wall and the gas
A hot wall warms the gas, and the pressure in a closed tank rises with it. The same pattern with a cooling wall and a vessel (vesselInPart) gives a reactor in a water bath; a vessel that raises chem:runaway in a bath that cannot carry the heat is a thermal-runaway scenario.
A turbine on a reactor#
import { turbineOnReactor } from '@ferret/physics-links';
cap.add(turbineOnReactor(reactor, shaft, { efficiency: 0.33, maxTorque: 1e5 }));
A third of the coolant's heat becomes torque on the shaft. Chain it on: a generator on that shaft (electric bindMachine) lights a lamp whose power comes from the reactor. The steam path in between has its own link, engineOnBoiler.
In a world#
const cap = links();
host.register(cap);
host.enable('links');
cap.add(slipHeats(brake, drum, heat.network));
cap.account({ name: 'wheel', joules: () => train.kinetic() });
The capability steps every link after the other capabilities, once per world step. links.energy (command) returns { total, terms }. Events from the capabilities (circuit:short, circuit:trip, circuit:overheat) are what arcFlash and wireFire listen to; each fires once per fault and has dispose().
Write your own link#
A link is any object with kind, moved and step. Read the source, write the target, add the energy that crossed to moved:
const solarHeatsRoof: Link = {
kind: 'sun→roof', moved: 0,
step(dt) { const q = irradiance() * area * dt; net.add(roofPart, q); this.moved += q; },
};
cap.add(solarHeatsRoof);
Budget#
A few reads and writes per link per step; hundreds of links are free.
Debugging#
| Symptom | Cause |
|---|---|
| The energy total drifts | a link writes without taking from the other side, or a store is missing from terms |
| A link does nothing | it was not added to the capability, or links is not enabled |
| Heat appears twice | two links join the same pair (a part in a vessel and the vessel in the part) |
| Order effects | a link runs after the capabilities have stepped: what it writes is used next step |
arcFlash fires twice | it does not: one blast per fault; a second needs the circuit to clear first |
Reference#
links, LinksCapability, Link, EnergyTerm, vesselInPart, gasInPart, slipHeats, turbineOnReactor, engineOnBoiler, screwOnShaft, arcFlash, wireFire, mudOver, boilerFed, @ferret/physics-links.