All extensions

@open-rgs/recipes

Every board comes from exactly one declared recipe.

A mixture, not a decoration

Draw a board and then stamp extra symbols on it and the real distribution stops matching the one RTP was computed from, silently. A mixture avoids that: RTP is a sum over recipes, each independently measurable.

One recipe chosen per board, at its declared probability.
import { recipes } from "@open-rgs/recipes";

const board = recipes([
  { name: "base",        p: 0.94, draw: reels },
  { name: "two-scatter", p: 0.05, draw: tease },
  { name: "high-stack",  p: 0.01, draw: stacked },
]);

const { grid, recipe } = board(host.rng_next);

A tease is a real draw

The tease board goes through the pay evaluator honestly. You bias which boards appear, at a rate you wrote down, and never fake an outcome - which is also what keeps near-miss behaviour on the right side of the rules.

A tease is a real draw that goes through the pay evaluator honestly.
import { place, stack } from "@open-rgs/recipes";
import { randomN, cols } from "@open-rgs/selectors";

const tease = place(2, "SC", randomN(2, cols([0, 1])), reels);

board.probabilityOf("two-scatter");

Placement building blocks

A recipe is written as a pipeline rather than a special case buried inside the base draw. Probabilities must sum to 1: a mixture summing to 0.98 misprices every spin by an amount nobody will notice.

place() writes symbols into the cells a selector picked.
import { placeAt, placeDrawn, fixed } from "@open-rgs/recipes";

placeAt("WILD", cols([2]), reels);
placeDrawn(3, highs, randomN(3), reels);
stack("HIGH", 2, reels);