Extensions

Small packages a math file imports. There is no plugin system, TS math can just import, so an extension is an ordinary package.

Generator<S> = (next) => Grid<S>          // makes a board
Selector<S>  = (grid, next) => Pos[]      // picks cells
Effect       = (grid, pos, next) => Grid  // changes a board

Three signatures carry all of it. next is always host.rng_next, nothing here makes randomness, everything receives it, and that is what lets one recorded seed replay a round.

New here? Build a slot walks the whole set end to end, from an empty grid to a running server.

The packages

Writing your own

Every extension point is one of the three signatures, so extending means writing a function. "Collect only from the same column" is a selector, not a new engine.

const sameColumn = (src) => (grid, next) =>
  coinCells()(grid, next).filter((p) => p.col === src.col);

const columnCollector = (src) => collector(sameColumn(src), JACKPOTS);

The one rule: take next, never make it. Code that reaches for Math.random() looks right, passes every test you would think to write, and silently voids any RTP measured from a replay.