// Seeded Worlds: the same number always builds the same world.
// @description Two worlds side by side, each labeled with its seed. Copy one seed over and the halves match exactly.
//
// Part of the BLIT386 demo series.
//
// Prerequisites:
//   Basics        https://demos.blit386.dev/basics
//   Random Basics https://demos.blit386.dev/random-basics
//
// WHAT YOU WILL SEE
// Two little worlds side by side. Each one was built out of random numbers - the hills, the
// buildings, the trees, the stars. Above each world is the number it grew from, called its
// "seed". Press the buttons to give either side a new seed and watch it rebuild.
//
// Then press "Copy left seed" and watch the right world turn into an exact twin of the left
// one. Same number in, same world out, every single time.
//
// WHAT YOU WILL LEARN
//   - BT.randomSeed(n) tells the engine which number to start its randomness from
//   - The same seed always produces the same sequence, so it produces the same world
//   - BT.random.seedValue reads that number back, even the one the engine picked by itself
//   - clone() copies a generator so both continue with the same numbers
//   - fork() splits off a new generator that goes its own way
//
// WHY THIS IS USEFUL
// A game can hand you a puzzle from seed 4821 and know every player gets the identical
// puzzle. A saved game can store one number instead of a whole map. And when a run goes
// really well, you can write the seed down and play it again.
//
// The engine splits work the usual way: update() moves things; render() only draws.
// See the Basics demo for the full story: https://demos.blit386.dev/basics

import { function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>
One-liner bootstrap function for BLIT386 demos. Handles canvas retrieval and engine initialization. Backend selection (WebGPU or software fallback) is managed internally by BTAPI. This function provides a streamlined way to start a demo with sensible defaults while allowing customization through options.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
,
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
, class Random
Seeded PRNG with integer-first generators and stream control (`seed` / `clone` / `fork`).
@since1.5.0
Random
, class Rect2i
Integer rectangle for pixel-perfect bounds and regions. Used throughout the engine for sprite regions, display-space bounds, and zero-allocation geometry helpers. Both convenience getters and allocation-free `*To()` helpers are provided so callers can choose between readability and hot-path efficiency.
@since0.1.0
Rect2i
, class Vector2i
Integer 2D vector for pixel-perfect positioning. Used for points, sizes, directions, and camera offsets throughout the engine. The API includes both allocation-free `*To()` / `*InPlace()` variants and convenience methods that return new vectors.
@since0.1.0
Vector2i
} from 'blit386';
import { import applyThemeapplyTheme, import uiui, import UI_ANCHORSUI_ANCHORS } from './shared/ui.js'; /** @typedef {import('blit386').IBTDemo} IBTDemo */ /** @typedef {import('blit386').Palette} Palette */ // This demo runs at the engine's default screen size of 320x240 "game pixels". // Each world gets its own framed box. Two boxes, side by side, with a gap between them. const const WORLD_W: 152WORLD_W = 152; const const WORLD_H: 100WORLD_H = 100; const const WORLD_Y: 18WORLD_Y = 18; const const WORLD_LEFT_X: 4WORLD_LEFT_X = 4; const const WORLD_RIGHT_X: 164WORLD_RIGHT_X = 164; // How many of each thing lives in a world. Fixed counts keep the two sides comparable: // only the positions and sizes change from seed to seed. const const STAR_COUNT: 16STAR_COUNT = 16; const const BUILDING_COUNT: 4BUILDING_COUNT = 4; const const TREE_COUNT: 7TREE_COUNT = 7; // The ground is drawn as a run of columns whose height is worked out from four control // points. Fewer points means smoother, rounder hills. const const HILL_POINTS: 4HILL_POINTS = 4; // Seeds are kept small so they are easy to read and easy to type back in. const const SEED_MIN: 1000SEED_MIN = 1000; const const SEED_MAX: 9999SEED_MAX = 9999; // How many numbers the stream comparison shows for each generator. const const STREAM_SAMPLE: 3STREAM_SAMPLE = 3; // Color slots. The shared UI kit owns slots 240-251, so scene colors stay well below that. const const C_SKY: 1C_SKY = 1; // Night sky inside each world box. const const C_STAR: 2C_STAR = 2; // Stars. const const C_GROUND: 3C_GROUND = 3; // Solid earth under the hills. const const C_HILL: 4C_HILL = 4; // The hill surface line. const const C_TREE: 5C_TREE = 5; // Tree leaves. const const C_TRUNK: 6C_TRUNK = 6; // Tree trunks. const const C_INK: 7C_INK = 7; // Frames and bright text. const const C_DIM: 8C_DIM = 8; // Faded lines. // Four building tints, in slots 10-13. const const C_BUILDING_BASE: 10C_BUILDING_BASE = 10; const const BUILDING_TINTS: 4BUILDING_TINTS = 4; /** * Builds one complete world from a single seed. * * This is the heart of the demo. Every random number it needs comes from BT.random, and * BT.random was just told where to start, so running this twice with the same seed walks * through the exact same numbers in the exact same order - and therefore builds the exact * same world. * * @param {number} seed - The number this world grows from. * @returns {{ seed: number, hills: Array<number>, buildings: Array<object>, trees: Array<object>, stars: Array<Vector2i> }} */ function
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(seed: number
- The number this world grows from.
@paramseed - The number this world grows from.
seed
) {
// This is the line that makes everything below repeatable. From here on the engine's // random numbers are no longer a surprise - they are decided by `seed`.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.randomSeed: (seed: number) => void
Reseeds the default engine PRNG so subsequent draws are reproducible.
@since1.5.0@paramseed - Any finite number; only its lower 32 bits are used.@exampleBT.randomSeed(1234); const a = BT.random.next(); BT.randomSeed(1234); const b = BT.random.next(); // a === b
randomSeed
(seed: number
- The number this world grows from.
@paramseed - The number this world grows from.
seed
);
// Stars first, scattered across the top two thirds of the box. const const stars: {}stars = []; for (let let i: numberi = 0; let i: numberi < const STAR_COUNT: 16STAR_COUNT; let i: numberi++) { // insideRect() hands back a Vector2i somewhere inside the rectangle we describe - // like closing your eyes and pointing at a spot on a map. const stars: {}stars.push(
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.insideRect(rect: Rect2i): Vector2i
Returns a random integer point inside a rectangle (half-open, like {@link Rect2i.isContaining } ).
@paramrect - Rectangle to sample; must have positive width and height.@returnsNew point with `x` in `[rect.x, rect.right)` and `y` in `[rect.y, rect.bottom)`.@since1.5.0
insideRect
(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2i
Creates an integer rectangle, truncating all inputs toward zero.
@paramx - Left-edge X coordinate (defaults to 0).@paramy - Top-edge Y coordinate (defaults to 0).@paramwidth - Width in pixels (defaults to 0).@paramheight - Height in pixels (defaults to 0).
Rect2i
(0, 0, const WORLD_W: 152WORLD_W, Math.floor(const WORLD_H: 100WORLD_H * 0.6))));
} // The hills. We pick a few heights spread across the width, then fill in the columns // between them by sliding smoothly from one height to the next. const const controls: {}controls = []; for (let let i: numberi = 0; let i: numberi < const HILL_POINTS: 4HILL_POINTS; let i: numberi++) { // int(a, b) gives a whole number from a up to (but not including) b, so these // heights land somewhere in the lower half of the box. const controls: {}controls.push(
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(Math.floor(const WORLD_H: 100WORLD_H * 0.55), Math.floor(const WORLD_H: 100WORLD_H * 0.8)));
} const const hills: {}hills = []; for (let let x: numberx = 0; let x: numberx < const WORLD_W: 152WORLD_W; let x: numberx++) { // Work out which pair of control points this column sits between, and how far along // it is between them (0 means "right on the left point", 1 means "right on the right"). const const spanW: numberspanW = const WORLD_W: 152WORLD_W / (const HILL_POINTS: 4HILL_POINTS - 1); const const span: anyspan = Math.min(const HILL_POINTS: 4HILL_POINTS - 2, Math.floor(let x: numberx / const spanW: numberspanW)); const const t: numbert = (let x: numberx - const span: anyspan * const spanW: numberspanW) / const spanW: numberspanW; // Sliding straight from one height to the next gives sharp corners. Feeding the // position through this curve first eases in and out, so the hills look rounded. const const eased: numbereased = const t: numbert * const t: numbert * (3 - 2 * const t: numbert); const hills: {}hills.push(Math.round(const controls: {}controls[const span: anyspan] + (const controls: {}controls[const span: anyspan + 1] - const controls: {}controls[const span: anyspan]) * const eased: numbereased)); } // Buildings, sitting on whatever ground height is under them. const const buildings: {}buildings = []; for (let let i: numberi = 0; let i: numberi < const BUILDING_COUNT: 4BUILDING_COUNT; let i: numberi++) { const const w: numberw =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(12, 24);
const const x: numberx =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(4, const WORLD_W: 152WORLD_W - const w: numberw - 4);
const const h: numberh =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(14, 34);
const buildings: {}buildings.push({ x: numberx, w: numberw, h: numberh, // The building stands on the ground, so its top is the ground height minus its // own height. groundY: anygroundY: const hills: {}hills[const x: numberx + Math.floor(const w: numberw / 2)], // int(4) is shorthand for int(0, 4): 0, 1, 2, or 3. That picks one of the four // building shades. tint: numbertint:
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(const BUILDING_TINTS: 4BUILDING_TINTS),
}); } // Trees, scattered along the ground. const const trees: {}trees = []; for (let let i: numberi = 0; let i: numberi < const TREE_COUNT: 7TREE_COUNT; let i: numberi++) { const const x: numberx =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(3, const WORLD_W: 152WORLD_W - 4);
const trees: {}trees.push({ x: numberx, groundY: anygroundY: const hills: {}hills[const x: numberx], h: numberh:
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(6, 13),
}); } return { seed: numberseed, hills: Array<number>hills, buildings: Array<object>buildings, trees: Array<object>trees, stars: Array<Vector2i>stars }; } /** * Two worlds side by side, proving that the same seed rebuilds the same world. * * @implements {IBTDemo} */ class class Demo
Two worlds side by side, proving that the same seed rebuilds the same world.
@implementsIBTDemo
Demo
{
/** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Slot map for the shared UI kit theme, filled in by applyTheme() during init(). Demo.theme: nulltheme = null; // The two worlds. Each remembers everything it was built from - that is the difference // between this demo and the Coordinate Patterns one, which remembers nothing at all: // https://demos.blit386.dev/coordinate-patterns Demo.left: nullleft = null; Demo.right: nullright = null; // Whether the engine picked the very first seeds by itself. Once the user presses a // button this turns false, because from then on the seeds were chosen on purpose. Demo.seedsWereAutomatic: booleanseedsWereAutomatic = true; // A snapshot of what clone() and fork() do, worked out once in init().
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
= { seed: numberseed: 0, base: {}base: [], cloned: {}cloned: [], forked: {}forked: [], forkSeed: undefinedforkSeed: var undefinedundefined };
// A private generator used only for choosing new seeds. // // It cannot be the shared BT.random, because generateWorld() reseeds that one. Drawing the // next seed from a stream we just reseeded makes the answer a fixed consequence of the // seed we reseeded it with - so "Copy left seed" followed by "New right" would hand back // the very same number every time, and the button would look broken. /** @type {Random | null} */ Demo.seedPicker: Random | null
@type{Random | null}
seedPicker
= null;
/** * Builds the palette, then grows both worlds from seeds nobody chose. * * @returns {Promise<boolean>} */ async Demo.init(): Promise<boolean>
Builds the palette, then grows both worlds from seeds nobody chose.
@returns
init
() {
this.Demo.palette: Palette | null
@type{Palette | null}
palette
=
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteCreate: (size?: number) => Palette
Creates a standalone palette instance.
@since1.0.3@paramsize - Palette size. Defaults to 256 colors.@returnsNew mutable palette.
paletteCreate
(256);
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_SKY: 1C_SKY, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(16, 20, 38)); // Night sky.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_STAR: 2C_STAR, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(220, 228, 245)); // Stars.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_GROUND: 3C_GROUND, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(28, 40, 32)); // Solid earth.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_HILL: 4C_HILL, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(74, 116, 80)); // Grassy hill surface.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_TREE: 5C_TREE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(96, 168, 104)); // Leaves.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_TRUNK: 6C_TRUNK, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(90, 68, 48)); // Trunks.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_INK: 7C_INK, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(226, 232, 244)); // Frames and bright text.
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_DIM: 8C_DIM, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(72, 80, 102)); // Faded lines.
// Four window-lit building shades, from dull to bright. this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_BUILDING_BASE: 10C_BUILDING_BASE + 0, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(64, 72, 96));
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_BUILDING_BASE: 10C_BUILDING_BASE + 1, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(84, 92, 118));
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_BUILDING_BASE: 10C_BUILDING_BASE + 2, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(104, 112, 140));
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_BUILDING_BASE: 10C_BUILDING_BASE + 3, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(126, 134, 162));
// Install the shared UI colors, then hand the finished palette to the engine. this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteSet: (palette: Palette) => void
Stores the active engine palette. Use this to swap the **entire palette** (e.g. switch between a day and night theme). After this call the renderer uploads the new palette uniform on the next frame. **Palette-value swap (change what a slot looks like):** mutate the live {@link BT.palette } in place with `palette.set(slot, newColor)`. The renderer uploads dirty slots on the next frame; no `paletteSet()` or {@link BT.spritesRefresh } needed. **Palette-layout swap (same colors, different slot positions):** build a new palette with the same colors at new indices, call `paletteSet()`, then call {@link BT.spritesRefresh } so every sprite sheet re-maps its original RGBA pixels against the new slot layout.
@since1.0.3@parampalette - Palette to make active.
paletteSet
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Set up the seed picker before anything asks it for a number. Left to itself, a new // Random seeds from the clock, so this stream is unrelated to the shared one. this.Demo.seedPicker: Random | null
@type{Random | null}
seedPicker
= new new Random(seed?: number): Random
Creates a PRNG. Omit `seed` to time-seed from `Date.now()` (lower 32 bits).
@paramseed - Any finite number; only its lower 32 bits affect the sequence.@since1.5.0
Random
();
// Nobody has chosen a seed yet. The engine seeded itself from the clock when it // started up, and seedValue hands that number back - so we can build a world from // it and still show which number it was. // // That is the part worth noticing: even the run you did not plan has a seed you can // write down and return to. this.Demo.left: nullleft =
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.random: Random
Default engine PRNG (live reference - not a copy). Time-seeded when the engine singleton is created. Call {@link BT.randomSeed } for a reproducible run. Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.seedValue: number | undefined
The last seed passed to the constructor or {@link seed } , normalized to an unsigned 32-bit value (the same representation {@link getState } uses, not necessarily the raw number passed in). `undefined` after {@link setState } (the stream position no longer corresponds to a known seed) or on a {@link fork } ed child (a fork is a new stream and should not claim to have been seeded by its caller). {@link clone } copies whatever value the parent currently holds.
@returnsLast known seed, or `undefined` if the origin seed is not known.@since1.5.0
seedValue
?? const SEED_MIN: 1000SEED_MIN);
this.Demo.right: nullright =
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(this.Demo.rollSeed(): number
Picks a fresh, easy-to-read seed.
@returns
rollSeed
());
this.Demo.sampleStreams(): void
Works out, once, what clone() and fork() do to a generator.
sampleStreams
();
return true; } /** * Nothing moves in this demo, so update() only keeps the UI kit's key shortcuts alive. */ Demo.update(): void
Nothing moves in this demo, so update() only keeps the UI kit's key shortcuts alive.
update
() {
// Always first: this is what makes the { key } shortcuts on buttons work. import uiui.tick(); } /** * Draws both worlds, their seeds, and the control panels. */ Demo.render(): void
Draws both worlds, their seeds, and the control panels.
render
() {
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.clear: (paletteIndex: number) => void
Sets the frame clear color using a palette index. The renderer uses this color when clearing the full display at the start of the next frame.
@since0.1.0@parampaletteIndex - Palette index for the full-screen clear pass.
clear
(const C_SKY: 1C_SKY);
this.
Demo.renderWorld(world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}, originX: number): void
Draws one world inside its frame.
@paramworld@paramoriginX - Left edge of this world's box on screen.
renderWorld
(this.Demo.left: nullleft, const WORLD_LEFT_X: 4WORLD_LEFT_X);
this.
Demo.renderWorld(world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}, originX: number): void
Draws one world inside its frame.
@paramworld@paramoriginX - Left edge of this world's box on screen.
renderWorld
(this.Demo.right: nullright, const WORLD_RIGHT_X: 164WORLD_RIGHT_X);
// Each world's seed sits directly above it, so there is no doubt which is which. import uiui.caption(const WORLD_LEFT_X: 4WORLD_LEFT_X, 8, `seed ${this.Demo.left: nullleft.seed}`); import uiui.caption(const WORLD_RIGHT_X: 164WORLD_RIGHT_X, 8, `seed ${this.Demo.right: nullright.seed}`); // When both seeds match, say so plainly - this is the moment the demo exists for. if (this.Demo.left: nullleft.seed === this.Demo.right: nullright.seed) { import uiui.caption(96, const WORLD_Y: 18WORLD_Y + const WORLD_H: 100WORLD_H + 4, 'Same seed, same world', { color: stringcolor: 'accent' }); } else if (this.Demo.seedsWereAutomatic: booleanseedsWereAutomatic) { // The left seed is long because nobody typed it: the engine made it from the // clock when the demo started. seedValue is how we can still read it. import uiui.caption(48, const WORLD_Y: 18WORLD_Y + const WORLD_H: 100WORLD_H + 4, 'Left seed came from the clock', { color: stringcolor: 'dim' }); } this.Demo.renderSeedPanel(): void
The three buttons that reseed the worlds.
renderSeedPanel
();
this.Demo.renderStreamPanel(): void
The clone-versus-fork comparison.
renderStreamPanel
();
} /** * Draws one world inside its frame. * * @param {{ hills: Array<number>, buildings: Array<object>, trees: Array<object>, stars: Array<Vector2i> }} world * @param {number} originX - Left edge of this world's box on screen. */
Demo.renderWorld(world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}, originX: number): void
Draws one world inside its frame.
@paramworld@paramoriginX - Left edge of this world's box on screen.
renderWorld
(
world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
@paramworld
world
, originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
) {
// Everything inside a world is stored in "world coordinates" starting at 0, so each // thing is drawn by adding the box's own corner to it. That is what lets the exact // same world data be drawn on either side of the screen. for (const const star: Array<Vector2i>star of
world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
@paramworld
world
.stars: Array<Vector2i>stars) {
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawPixel: (posOrX: Vector2i | number, yOrColor: number, maybeColor?: number) => void
Draws a single pixel. Accepts either: - `(posOrX: Vector2i, yOrColor: number)` where `yOrColor` is the palette index. - `(posOrX: number, yOrColor: number, maybeColor: number)` for `(x, y, paletteIndex)`.
@since0.1.0@paramposOrX - Pixel position as `Vector2i`, or x coordinate when using numeric overload.@paramyOrColor - Palette index for vector overload, or y coordinate for numeric overload.@parammaybeColor - Palette index when using numeric overload.
drawPixel
(new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ const star: Array<Vector2i>star.x, const WORLD_Y: 18WORLD_Y + const star: Array<Vector2i>star.y), const C_STAR: 2C_STAR);
} // The ground: one vertical line per column, from the hill surface down to the bottom. for (let let x: numberx = 0; let x: numberx < const WORLD_W: 152WORLD_W; let x: numberx++) { const const top: Array<number>top =
world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
@paramworld
world
.hills: Array<number>hills[let x: numberx];
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(
new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ let x: numberx, const WORLD_Y: 18WORLD_Y + const top: Array<number>top),
new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ let x: numberx, const WORLD_Y: 18WORLD_Y + const WORLD_H: 100WORLD_H - 1),
const C_GROUND: 3C_GROUND, );
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawPixel: (posOrX: Vector2i | number, yOrColor: number, maybeColor?: number) => void
Draws a single pixel. Accepts either: - `(posOrX: Vector2i, yOrColor: number)` where `yOrColor` is the palette index. - `(posOrX: number, yOrColor: number, maybeColor: number)` for `(x, y, paletteIndex)`.
@since0.1.0@paramposOrX - Pixel position as `Vector2i`, or x coordinate when using numeric overload.@paramyOrColor - Palette index for vector overload, or y coordinate for numeric overload.@parammaybeColor - Palette index when using numeric overload.
drawPixel
(new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ let x: numberx, const WORLD_Y: 18WORLD_Y + const top: Array<number>top), const C_HILL: 4C_HILL);
} for (const const b: Array<object>b of
world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
@paramworld
world
.buildings: Array<object>buildings) {
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawRectFill: (rect: Rect2i, paletteIndex: number) => void
Draws a filled rectangle.
@since0.1.0@paramrect - Rectangle bounds in display coordinates.@parampaletteIndex - Palette color index.
drawRectFill
(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2i
Creates an integer rectangle, truncating all inputs toward zero.
@paramx - Left-edge X coordinate (defaults to 0).@paramy - Top-edge Y coordinate (defaults to 0).@paramwidth - Width in pixels (defaults to 0).@paramheight - Height in pixels (defaults to 0).
Rect2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ const b: Array<object>b.x, const WORLD_Y: 18WORLD_Y + const b: Array<object>b.groundY - const b: Array<object>b.h, const b: Array<object>b.w, const b: Array<object>b.h), const C_BUILDING_BASE: 10C_BUILDING_BASE + const b: Array<object>b.tint);
} for (const const t: Array<object>t of
world: {
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
@paramworld
world
.trees: Array<object>trees) {
// A trunk, then a blob of leaves on top of it.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(
new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ const t: Array<object>t.x, const WORLD_Y: 18WORLD_Y + const t: Array<object>t.groundY),
new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ const t: Array<object>t.x, const WORLD_Y: 18WORLD_Y + const t: Array<object>t.groundY - const t: Array<object>t.h),
const C_TRUNK: 6C_TRUNK, );
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawRectFill: (rect: Rect2i, paletteIndex: number) => void
Draws a filled rectangle.
@since0.1.0@paramrect - Rectangle bounds in display coordinates.@parampaletteIndex - Palette color index.
drawRectFill
(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2i
Creates an integer rectangle, truncating all inputs toward zero.
@paramx - Left-edge X coordinate (defaults to 0).@paramy - Top-edge Y coordinate (defaults to 0).@paramwidth - Width in pixels (defaults to 0).@paramheight - Height in pixels (defaults to 0).
Rect2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
+ const t: Array<object>t.x - 2, const WORLD_Y: 18WORLD_Y + const t: Array<object>t.groundY - const t: Array<object>t.h - 3, 5, 5), const C_TREE: 5C_TREE);
} // The frame goes on last so it sits cleanly on top of everything.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawRect: (rect: Rect2i, paletteIndex: number) => void
Draws an unfilled rectangle outline.
@since0.1.0@paramrect - Rectangle bounds in display coordinates.@parampaletteIndex - Palette color index.
drawRect
(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2i
Creates an integer rectangle, truncating all inputs toward zero.
@paramx - Left-edge X coordinate (defaults to 0).@paramy - Top-edge Y coordinate (defaults to 0).@paramwidth - Width in pixels (defaults to 0).@paramheight - Height in pixels (defaults to 0).
Rect2i
(originX: number
- Left edge of this world's box on screen.
@paramoriginX - Left edge of this world's box on screen.
originX
- 1, const WORLD_Y: 18WORLD_Y - 1, const WORLD_W: 152WORLD_W + 2, const WORLD_H: 100WORLD_H + 2), const C_DIM: 8C_DIM);
} /** * The three buttons that reseed the worlds. */ Demo.renderSeedPanel(): void
The three buttons that reseed the worlds.
renderSeedPanel
() {
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_LEFT); import uiui.panel('Seeds'); if (import uiui.button('New left', { key: stringkey: 'KeyQ' })) { this.Demo.left: nullleft =
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(this.Demo.rollSeed(): number
Picks a fresh, easy-to-read seed.
@returns
rollSeed
());
this.Demo.seedsWereAutomatic: booleanseedsWereAutomatic = false; } if (import uiui.button('New right', { key: stringkey: 'KeyW' })) { this.Demo.right: nullright =
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(this.Demo.rollSeed(): number
Picks a fresh, easy-to-read seed.
@returns
rollSeed
());
this.Demo.seedsWereAutomatic: booleanseedsWereAutomatic = false; } if (import uiui.button('Copy left seed', { key: stringkey: 'KeyE' })) { // Nothing about the right world is copied here - only the number. The world is // rebuilt from scratch, and it comes back identical because the number is the same. this.Demo.right: nullright =
function generateWorld(seed: number): {
    seed: number;
    hills: Array<number>;
    buildings: Array<object>;
    trees: Array<object>;
    stars: Array<Vector2i>;
}
Builds one complete world from a single seed. This is the heart of the demo. Every random number it needs comes from BT.random, and BT.random was just told where to start, so running this twice with the same seed walks through the exact same numbers in the exact same order - and therefore builds the exact same world.
@paramseed - The number this world grows from.@returns
generateWorld
(this.Demo.left: nullleft.seed);
this.Demo.seedsWereAutomatic: booleanseedsWereAutomatic = false; } import uiui.end(); } /** * The clone-versus-fork comparison. */ Demo.renderStreamPanel(): void
The clone-versus-fork comparison.
renderStreamPanel
() {
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_RIGHT); import uiui.panel(`One more generator (seed ${this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.seed: numberseed})`);
import uiui.kv('original', this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.base: {}base.join(' '));
import uiui.kv('clone()', this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.cloned: {}cloned.join(' '));
import uiui.kv('fork()', this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.forked: {}forked.join(' '));
import uiui.separator(); import uiui.label('A clone carries on identically.', { color: stringcolor: 'dim' }); import uiui.label('A fork goes its own way, and its', { color: stringcolor: 'dim' }); import uiui.label(`seedValue reads ${this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.forkSeed: undefinedforkSeed ?? 'unknown'}.`, { color: stringcolor: 'dim' });
import uiui.end(); } /** * Picks a fresh, easy-to-read seed. * * @returns {number} */ Demo.rollSeed(): number
Picks a fresh, easy-to-read seed.
@returns
rollSeed
() {
// intInclusive(a, b) can return b itself, unlike int(a, b) which stops just short of // it. For a seed range meant to read as "1000 to 9999", inclusive is what we want. // // This comes from seedPicker rather than BT.random - see the field for why. return this.Demo.seedPicker: Random | null
@type{Random | null}
seedPicker
.Random.intInclusive(min: number, max: number): number
Returns a pseudo-random integer in [min, max] (inclusive on both ends).
@parammin - Inclusive lower bound.@parammax - Inclusive upper bound.@returnsWhole number in the closed range.@since1.5.0
intInclusive
(const SEED_MIN: 1000SEED_MIN, const SEED_MAX: 9999SEED_MAX);
} /** * Works out, once, what clone() and fork() do to a generator. */ Demo.sampleStreams(): void
Works out, once, what clone() and fork() do to a generator.
sampleStreams
() {
// A generator of our own, separate from the shared BT.random, so sampling it cannot // disturb the worlds we just built. `new Random(seed)` is how you make one. const const seed: numberseed = this.Demo.rollSeed(): number
Picks a fresh, easy-to-read seed.
@returns
rollSeed
();
const const original: Randomoriginal = new new Random(seed?: number): Random
Creates a PRNG. Omit `seed` to time-seed from `Date.now()` (lower 32 bits).
@paramseed - Any finite number; only its lower 32 bits affect the sequence.@since1.5.0
Random
(const seed: numberseed);
// Order matters here. fork() has to draw one number from the parent to seed the child, // which nudges the parent forward. So we fork FIRST, and only then take the clone - // that way the original and its clone are standing in the same place, and any // difference you see between them would be a real one. const const forked: Randomforked = const original: Randomoriginal.Random.fork(): Random
Returns an independent sub-stream. Advances this generator once to seed the child. The child's {@link seedValue } is always `undefined` - a fork should not claim a caller-chosen seed.
@returnsNew generator whose sequence diverges from this one.@since1.5.0
fork
();
const const cloned: Randomcloned = const original: Randomoriginal.Random.clone(): Random
Returns a new generator with the same state (identical stream from this point). The copy also shares this generator's {@link seedValue } , including `undefined`.
@returnsIndependent copy that will produce the same subsequent values.@since1.5.0
clone
();
for (let let i: numberi = 0; let i: numberi < const STREAM_SAMPLE: 3STREAM_SAMPLE; let i: numberi++) { // int(100) is shorthand for int(0, 100): a whole number from 0 to 99. this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.base: {}base.push(const original: Randomoriginal.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(100));
this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.cloned: {}cloned.push(const cloned: Randomcloned.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(100));
this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.forked: {}forked.push(const forked: Randomforked.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(100));
} this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.seed: numberseed = const seed: numberseed;
// A fork is a brand new stream, so the engine refuses to claim it was seeded by us - // its seedValue is deliberately left unknown. this.
Demo.streams: {
    seed: number;
    base: {};
    cloned: {};
    forked: {};
    forkSeed: undefined;
}
streams
.forkSeed: undefinedforkSeed = const forked: Randomforked.Random.seedValue: number | undefined
The last seed passed to the constructor or {@link seed } , normalized to an unsigned 32-bit value (the same representation {@link getState } uses, not necessarily the raw number passed in). `undefined` after {@link setState } (the stream position no longer corresponds to a known seed) or on a {@link fork } ed child (a fork is a new stream and should not claim to have been seeded by its caller). {@link clone } copies whatever value the parent currently holds.
@returnsLast known seed, or `undefined` if the origin seed is not known.@since1.5.0
seedValue
;
} } function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>
One-liner bootstrap function for BLIT386 demos. Handles canvas retrieval and engine initialization. Backend selection (WebGPU or software fallback) is managed internally by BTAPI. This function provides a streamlined way to start a demo with sensible defaults while allowing customization through options.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
(class Demo
Two worlds side by side, proving that the same seed rebuilds the same world.
@implementsIBTDemo
Demo
);