/*

Patterns: animated mathematical art using only primitive drawing.
@description Animated mathematical art from primitives alone: spirals, Lissajous curves, waves, and a tunnel.

Part of the BLIT386 demo series.

Prerequisites:
  - Basics: https://demos.blit386.dev/basics
  - Primitives: https://demos.blit386.dev/primitives
  - Colors: https://demos.blit386.dev/colors

Live version: https://demos.blit386.dev/patterns

Guides:
  - Palette: https://blit386.dev/docs/guides/palette#draw-using-absolute-palette-indices
  - Overlay: https://blit386.dev/docs/guides/overlay#optional-bands

Reference:
  - Rendering: https://blit386.dev/docs/api/rendering#primitives
  - Core Types: https://blit386.dev/docs/api/core-types#color32
  - Overlay: https://blit386.dev/docs/api/overlay#timing-chart-optional

---

WHAT YOU WILL SEE
-----------------

Six small animated patterns on a near-black screen, arranged in two rows of three, each
with an amber caption under it:

- Spiral: 100 dots coiling out from the center, spinning, with colors that slide along
  the coil.
- Radial: 12 rays shooting out from a center point like sun rays, each pulsing in length
  while the whole set slowly turns.
- Wave: a blue sine wave, an orange cosine wave, and a green "interference" wave that is
  the two added together, all scrolling sideways.
- Circle: a ring of 32 short line segments in rainbow colors that slowly spins while its
  radius breathes in and out.
- Lissajous: a smooth looping curve (the kind physics and electronics people draw on
  oscilloscopes) that slowly changes shape, with 32 color bands rotating around it.
- Tunnel: 20 nested squares that shrink toward the center, wobble, and orbit, like
  looking down a pipe.

The engine overlay is open from the start with the full 256-slot palette grid and a
timing chart in "rich" diagnostics mode, so you can watch the animated palette ranges
change color every tick.

WHAT YOU WILL LEARN
-------------------

- Drawing with just three primitives: BT.drawPixel(), BT.drawLine(), and BT.drawRect().
  No images, no sprites.
- Turning an angle and a distance into x and y with Math.cos() and Math.sin().
- Palette-first animation: update() recomputes colors with Color32.fromHSL() and writes
  them into reserved palette ranges; render() only passes slot numbers.
- Reusing a few Vector2i and Rect2i objects (tempVec1, tempVec2, tempRect) with .set()
  instead of creating new ones every frame.
- Styling the overlay from configure() with overlayStyle and overlayTimingChartStyle,
  and turning on the renderer diagnostics bar.

HOW COLORS WORK IN THIS DEMO
----------------------------

Every color must be registered in a palette before drawing. Think of it like choosing
all your paint colors before starting a painting: you pick them out first, then use them
by number ("color 5", "color 12", and so on).

Some colors never change (white, the background, the three wave colors, the 32 circle
hues, the 12 ray hues). Those are set once in init(). Other colors animate (the 100
spiral dots, the 32 Lissajous bands, the 20 tunnel squares). Those are recalculated every
tick in update() and stored back in the palette. render() only ever uses palette index
numbers, never Color32 objects.

TRY THIS
--------

- Watch the overlay's palette grid: slots 60-159 (spiral), 160-191 (Lissajous), and
  192-211 (tunnel) keep changing, while 8-39 (circle) and 40-51 (rays) stay still.
- Press the backquote key (`) to hide the overlay and see the patterns alone.

*/

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;
    ... 124 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 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 } from './shared/ui.js'; /** @typedef {import('blit386').Palette} Palette */ // These numbers are the "addresses" in the palette table. Slot 0 is always reserved for // transparent, so we never use it. Each color gets a readable name so the code is easier // to follow. // Static colors: set once in init(), never changed. const const C_WHITE: 1C_WHITE = 1; // pure white: the overlay bar color (see configure()) const const C_BG: 2C_BG = 2; // very dark blue-black background const const C_TAG: 3C_TAG = 3; // dim white: only feeds the overlay timing-chart tag color const const C_WAVE_1: 5C_WAVE_1 = 5; // blue: the sine wave const const C_WAVE_2: 6C_WAVE_2 = 6; // orange: the cosine wave const const C_WAVE_3: 7C_WAVE_3 = 7; // green: the interference wave (both added together) // Circle segments: 32 slots at 8-39. Each segment gets its own hue. The hues never // change, so these are static too. const const C_CIRCLE_BASE: 8C_CIRCLE_BASE = 8; const const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS = 32; // Radial rays: 12 slots at 40-51, one fixed hue per ray. Static. const const C_RADIAL_BASE: 40C_RADIAL_BASE = 40; const const RADIAL_LINES: 12RADIAL_LINES = 12; // The dynamic colors start here: everything below is repainted every tick in update(). // Spiral dots: 100 slots at 60-159. Each dot's hue moves forward as animTime grows, so // the colors slide along the coil. const const C_SPIRAL_BASE: 60C_SPIRAL_BASE = 60; const const SPIRAL_POINTS: 100SPIRAL_POINTS = 100; // Lissajous curve: 32 color bands at 160-191. The 200-point curve is split into 32 color // groups whose hues rotate over time. const const C_LISSAJOUS_BASE: 160C_LISSAJOUS_BASE = 160; const const LISSAJOUS_BANDS: 32LISSAJOUS_BANDS = 32; // Tunnel squares: 20 slots at 192-211. The large outer square is darkest; the squares get // brighter as they shrink toward the center. const const C_TUNNEL_BASE: 192C_TUNNEL_BASE = 192; const const TUNNEL_RECTS: 20TUNNEL_RECTS = 20; // Animated mathematical patterns drawn with primitives only, six of them in a 2x3 grid. class class DemoDemo { // A clock that counts up in seconds. It makes the patterns move. Demo.animTime: numberanimTime = 0; // The palette holds every color we are allowed to use: a box of 256 numbered paints. /** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Where the shared UI theme colors landed in the palette, filled by applyTheme() in // init(). The UI kit draws the six captions with these slots. Demo.theme: nulltheme = null; // These Vector2i and Rect2i objects are created once and reused every frame. Making // new objects inside a loop every frame can slow things down, because the browser has // to clean up the old ones. Reusing them avoids that. Demo.tempVec1: Vector2itempVec1 = 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
(0, 0);
Demo.tempVec2: Vector2itempVec2 = 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
(0, 0);
Demo.tempRect: Rect2itempRect = 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, 0, 0);
// Optional engine settings. We keep the default 320x240 screen, open the overlay from // the start with the full 256-slot palette grid (default column count), and turn on // the timing chart in "rich" mode plus the renderer diagnostics bar, so GPU pipeline // pressure is visible while the patterns run.
Demo.configure(): {
    isOverlayPaletteEnabled: boolean;
    isOverlayVisibleAtStart: boolean;
    overlayStyle: {
        barPaletteIndex: number;
        textPaletteIndex: number;
        gapPaletteIndex: number;
    };
    isOverlayTimingChartEnabled: boolean;
    overlayTimingChartDiagnostics: string;
    isOverlayRendererDiagnosticsBarEnabled: boolean;
    overlayTimingChartStyle: {
        updateBarPaletteIndex: number;
        renderBarPaletteIndex: number;
        warningPaletteIndex: number;
        errorPaletteIndex: number;
        tagPaletteIndex: number;
    };
}
configure
() {
return { isOverlayPaletteEnabled: booleanisOverlayPaletteEnabled: true, isOverlayVisibleAtStart: booleanisOverlayVisibleAtStart: true, // Overlay bar: white with dark text.
overlayStyle: {
    barPaletteIndex: number;
    textPaletteIndex: number;
    gapPaletteIndex: number;
}
overlayStyle
: {
barPaletteIndex: numberbarPaletteIndex: const C_WHITE: 1C_WHITE, textPaletteIndex: numbertextPaletteIndex: const C_BG: 2C_BG, gapPaletteIndex: numbergapPaletteIndex: const C_BG: 2C_BG, }, isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true, overlayTimingChartDiagnostics: stringoverlayTimingChartDiagnostics: 'rich', isOverlayRendererDiagnosticsBarEnabled: booleanisOverlayRendererDiagnosticsBarEnabled: true, // The timing chart bars borrow the wave colors: green for update(), blue for // render(), orange for warnings and errors.
overlayTimingChartStyle: {
    updateBarPaletteIndex: number;
    renderBarPaletteIndex: number;
    warningPaletteIndex: number;
    errorPaletteIndex: number;
    tagPaletteIndex: number;
}
overlayTimingChartStyle
: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const C_WAVE_3: 7C_WAVE_3, renderBarPaletteIndex: numberrenderBarPaletteIndex: const C_WAVE_1: 5C_WAVE_1, warningPaletteIndex: numberwarningPaletteIndex: const C_WAVE_2: 6C_WAVE_2, errorPaletteIndex: numbererrorPaletteIndex: const C_WAVE_2: 6C_WAVE_2, tagPaletteIndex: numbertagPaletteIndex: const C_TAG: 3C_TAG, }, }; } // Runs once when the demo starts and sets up the palette. The order matters: // // 1. Create the palette: the 256-slot color table. // 2. Fill in the static colors: the ones that never change. // 3. BT.paletteSet(): tell the engine to use this palette. // // Returns true when ready to run. async Demo.init(): unknowninit() { // Step 1: create the palette. BT.paletteCreate(256) makes a color table with 256 // numbered slots. Slot 0 is always transparent and cannot be changed. 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;
    ... 124 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);
// Step 2: register the static colors. First the basic ones. 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_WHITE: 1C_WHITE, 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
(255, 255, 255)); // overlay bar white
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_BG: 2C_BG, 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
(15, 15, 25)); // very dark blue-black
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_TAG: 3C_TAG, 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
(200, 200, 200)); // dim white for chart tags
// Wave pattern: three fixed colors. 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_WAVE_1: 5C_WAVE_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
(100, 200, 255)); // blue wave
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_WAVE_2: 6C_WAVE_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
(255, 150, 100)); // orange wave
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_WAVE_3: 7C_WAVE_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
(150, 255, 150)); // green interference
// Circle segments: 32 colors spread across the rainbow. These hues do not depend // on animTime, so we set them here once. for (let let i: numberi = 0; let i: numberi < const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS; let i: numberi++) { // Spread 32 evenly spaced hues across the 0-360 degree color wheel. const const hue: numberhue = (let i: numberi / const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS) * 360; 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_CIRCLE_BASE: 8C_CIRCLE_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue, 100, 50));
} // Radial rays: 12 colors, one per ray. for (let let i: numberi = 0; let i: numberi < const RADIAL_LINES: 12RADIAL_LINES; let i: numberi++) { // A little less saturated and a little brighter than the circle colors. const const hue: numberhue = (let i: numberi / const RADIAL_LINES: 12RADIAL_LINES) * 360; 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_RADIAL_BASE: 40C_RADIAL_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue, 80, 60));
} // The spiral, Lissajous, and tunnel slots are left empty here. update() fills // them in before the first frame renders. // Install the shared UI theme the captions draw with. It writes 12 colors into // slots 240-251, above every range this demo touches (the highest animated range // is the tunnel at 192-211), so the per-tick palette animation never collides // with the UI colors. Must run before BT.paletteSet(). this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Step 3: activate the palette. This tells the engine "use this palette for all // drawing from now on".
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;
    ... 124 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
);
return true; } // Runs at a fixed rate (60 times per second by default). Advances the animation clock // and recomputes the dynamic palette entries for the spiral, Lissajous, and tunnel. // All color math happens here; render() only uses palette index numbers. Demo.update(): voidupdate() { // deltaSeconds is the length of one fixed update step in seconds (usually 1/60). this.Demo.animTime: numberanimTime +=
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;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.deltaSeconds: number
Fixed-step seconds per update tick. Equivalent to `1 / BT.targetFPS` when `BT.targetFPS` is finite and positive. Falls back to `1 / 60` when target FPS is non-finite or non-positive.
@since1.0.4@returnsSeconds advanced by one fixed update tick.
deltaSeconds
;
// Spiral colors: 100 animated dots. Each dot's hue depends on its place along the // coil and on the current time, so the colors slide along the coil as animTime // grows. for (let let i: numberi = 0; let i: numberi < const SPIRAL_POINTS: 100SPIRAL_POINTS; let i: numberi++) { // Spread the base hue from 0 to 360 across the 100 dots. animTime * 50 // scrolls the colors by 50 degrees per second. const const hue: numberhue = (let i: numberi / const SPIRAL_POINTS: 100SPIRAL_POINTS) * 360 + this.Demo.animTime: numberanimTime * 50; // fromHSL takes hue (0-360), saturation (0-100), and lightness (0-100). // Full saturation and mid lightness give vivid rainbow colors. `% 360` // wraps the hue back onto the color wheel once it passes 360. this.Demo.palette: Palette | null
@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_SPIRAL_BASE: 60C_SPIRAL_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue % 360, 100, 50));
} // Lissajous color bands: 32 bands for the 200-point curve. Splitting the points // into 32 groups saves palette slots. for (let let i: numberi = 0; let i: numberi < const LISSAJOUS_BANDS: 32LISSAJOUS_BANDS; let i: numberi++) { // animTime * 30 rotates the color cycle by 30 degrees per second. const const hue: numberhue = (let i: numberi / const LISSAJOUS_BANDS: 32LISSAJOUS_BANDS) * 360 + this.Demo.animTime: numberanimTime * 30; this.Demo.palette: Palette | null
@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_LISSAJOUS_BASE: 160C_LISSAJOUS_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue % 360, 100, 50));
} // Tunnel colors: 20 squares. Low i is the big outer square, high i the small // inner one (drawTunnel() sizes them with 1 - t), so the lightness ramp below // makes the tunnel brighter toward the center. for (let let i: numberi = 0; let i: numberi < const TUNNEL_RECTS: 20TUNNEL_RECTS; let i: numberi++) { // t goes from 0 (outer, largest) to just under 1 (inner, smallest). const const t: numbert = let i: numberi / const TUNNEL_RECTS: 20TUNNEL_RECTS; // The hue rotates at 50 degrees per second, and each square is offset by // t * 360 so the colors spread across the rainbow from outer to inner. const const hue: numberhue = (const t: numbert * 360 + this.Demo.animTime: numberanimTime * 50) % 360; // Lightness goes from 30 (dark, outer) to nearly 70 (bright, inner). const const lightness: numberlightness = 30 + const t: numbert * 40; this.Demo.palette: Palette | null
@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_TUNNEL_BASE: 192C_TUNNEL_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue, 100, const lightness: numberlightness));
} } // Runs once per screen refresh and draws all six patterns in a 2x3 grid. Notice there // are no Color32 objects here: every draw call uses a palette index. Demo.render(): voidrender() { // Fill the whole screen with the very dark blue-black background.
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;
    ... 124 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_BG: 2C_BG);
// Top row: three patterns centered at y = 80. this.Demo.drawSpiral(center: any): voiddrawSpiral(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
(60, 80));
this.Demo.drawRadialLines(center: any): voiddrawRadialLines(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
(160, 80));
this.Demo.drawWavePattern(center: any): voiddrawWavePattern(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
(260, 80));
// Bottom row: three more centered at y = 150. this.Demo.drawCircleApproximation(center: any): voiddrawCircleApproximation(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
(60, 150));
this.Demo.drawLissajous(center: any): voiddrawLissajous(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
(160, 150));
this.Demo.drawTunnel(center: any): voiddrawTunnel(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
(260, 150));
// Caption each grid cell so viewers know which pattern they are looking at. // ui.caption() is the shared UI kit's pinned one-line caption, the same widget // every demo in the series uses. Text draws left-aligned, so each x is nudged // until the name sits under its pattern's center. import uiui.caption(42, 100, 'Spiral'); import uiui.caption(120, 100, 'Radial'); import uiui.caption(250, 100, 'Wave'); import uiui.caption(42, 180, 'Circle'); import uiui.caption(133, 180, 'Lissajous'); import uiui.caption(243, 180, 'Tunnel'); } // Draws an Archimedean spiral: a coil of colored dots that expands outward from // `center` while rotating. Inner dots sit near the center, outer ones far away. The // colors are animated: update() computes them and stores them in the slots // C_SPIRAL_BASE + i. Demo.drawSpiral(center: any): voiddrawSpiral(center: anycenter) { const const maxRadius: 35maxRadius = 35; for (let let i: numberi = 0; let i: numberi < const SPIRAL_POINTS: 100SPIRAL_POINTS; let i: numberi++) { // The angle runs from animTime (inner) to animTime + 2 * PI (outer). 2 * PI // is one full turn, so the coil wraps around once, and adding animTime spins // it. const const t: numbert = (let i: numberi / const SPIRAL_POINTS: 100SPIRAL_POINTS) * Math.PI * 2 + this.Demo.animTime: numberanimTime; // How far from the center this dot is: dot 0 sits at the center, dot 99 is // almost maxRadius pixels away. const const radius: numberradius = (let i: numberi / const SPIRAL_POINTS: 100SPIRAL_POINTS) * const maxRadius: 35maxRadius; // Convert polar coordinates (angle t, distance radius) to x and y on screen. // Math.cos and Math.sin turn an angle into how far to move along each axis. // Think of a clock hand: cos is how far right or left the tip is, sin how far // up or down. Math.PI is half a turn (180 degrees); 2 * PI is a full turn // (360 degrees). Multiplying by radius stretches that direction to the dot's // distance from the center. const const x: anyx = center: anycenter.x + Math.cos(const t: numbert) * const radius: numberradius; const const y: anyy = center: anycenter.y + Math.sin(const t: numbert) * const radius: numberradius; // Draw the dot with its animated color, already updated in update(). this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(const x: anyx), Math.floor(const y: anyy));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, const C_SPIRAL_BASE: 60C_SPIRAL_BASE + let i: numberi);
} } // Draws lines radiating from `center` like sun rays. Each ray has its own fixed color // (set once in init()) and its length pulses. Demo.drawRadialLines(center: any): voiddrawRadialLines(center: anycenter) { const const radius: 35radius = 35; // maximum length of each ray for (let let i: numberi = 0; let i: numberi < const RADIAL_LINES: 12RADIAL_LINES; let i: numberi++) { // Space the rays evenly around the circle: the full circle is 2 * PI radians. // Adding animTime rotates the whole pattern over time. const const angle: numberangle = (let i: numberi / const RADIAL_LINES: 12RADIAL_LINES) * Math.PI * 2 + this.Demo.animTime: numberanimTime; // Each ray gets a different phase offset (i) so they pulse at different // times. The length swings between 0 and the full radius. const const length: numberlength = const radius: 35radius * (0.5 + 0.5 * Math.sin(this.Demo.animTime: numberanimTime * 2 + let i: numberi)); // Where the tip of this ray is. const const x: anyx = center: anycenter.x + Math.cos(const angle: numberangle) * const length: numberlength; const const y: anyy = center: anycenter.y + Math.sin(const angle: numberangle) * const length: numberlength; // Draw the ray from the center to the tip in its fixed color. this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(const x: anyx), Math.floor(const y: anyy));
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;
    ... 124 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
(center: anycenter, this.Demo.tempVec1: Vector2itempVec1, const C_RADIAL_BASE: 40C_RADIAL_BASE + let i: numberi);
} } // Draws three wave curves on top of each other around `center`: a sine wave, a cosine // wave, and an "interference" wave that shows what happens when the two are added. // All three wave colors are static. Demo.drawWavePattern(center: any): voiddrawWavePattern(center: anycenter) { const const width: 60width = 60; // the waves span 60 pixels for (let let x: numberx = 0; let x: numberx < const width: 60width; let x: numberx++) { // Map x from 0..width to a screen column centered on center.x. const const baseX: numberbaseX = center: anycenter.x - const width: 60width / 2 + let x: numberx; // Primary wave: a sine wave. Adding animTime * 20 makes it scroll to the // left. Multiplying by 0.2 sets the frequency (how many waves fit in the // space) and multiplying by 15 sets the amplitude (how tall the wave is in // pixels). const const y1: numbery1 = Math.sin((let x: numberx + this.Demo.animTime: numberanimTime * 20) * 0.2) * 15; this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(const baseX: numberbaseX, center: anycenter.y + Math.floor(const y1: numbery1));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, const C_WAVE_1: 5C_WAVE_1);
// Secondary wave: a cosine wave with a different speed and size. const const y2: numbery2 = Math.cos((let x: numberx + this.Demo.animTime: numberanimTime * 15) * 0.15) * 10; this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(const baseX: numberbaseX, center: anycenter.y + Math.floor(const y2: numbery2));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, const C_WAVE_2: 6C_WAVE_2);
// Interference: both waves added together, divided by 2 to keep it in range. // Where the waves line up they reinforce each other; where they are opposite // they cancel out. const const y3: numbery3 = Math.sin((let x: numberx + this.Demo.animTime: numberanimTime * 20) * 0.2) * 15 + Math.cos((let x: numberx + this.Demo.animTime: numberanimTime * 15) * 0.15) * 10; this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(const baseX: numberbaseX, center: anycenter.y + Math.floor(const y3: numbery3 / 2));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, const C_WAVE_3: 7C_WAVE_3);
} } // Draws a circle by joining many short line segments around its edge, showing how a // circle can be approximated with nothing but lines. The radius pulses and the whole // ring slowly rotates. Segment colors are static (set once in init() by hue). Demo.drawCircleApproximation(center: any): voiddrawCircleApproximation(center: anycenter) { // The radius pulses between 2 and 30 pixels (16 plus or minus 14) using Math.sin. const const radius: numberradius = 16 + Math.sin(this.Demo.animTime: numberanimTime) * 14; for (let let i: numberi = 0; let i: numberi < const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS; let i: numberi++) { // The start and end angle of this segment. Together all 32 segments cover the // full circle (2 * PI radians). const const angle1: numberangle1 = (let i: numberi / const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS) * Math.PI * 2; const const angle2: numberangle2 = ((let i: numberi + 1) / const CIRCLE_SEGMENTS: 32CIRCLE_SEGMENTS) * Math.PI * 2; // Adding animTime to both angles rotates the whole circle over time. const const x1: anyx1 = center: anycenter.x + Math.cos(const angle1: numberangle1 + this.Demo.animTime: numberanimTime) * const radius: numberradius; const const y1: anyy1 = center: anycenter.y + Math.sin(const angle1: numberangle1 + this.Demo.animTime: numberanimTime) * const radius: numberradius; const const x2: anyx2 = center: anycenter.x + Math.cos(const angle2: numberangle2 + this.Demo.animTime: numberanimTime) * const radius: numberradius; const const y2: anyy2 = center: anycenter.y + Math.sin(const angle2: numberangle2 + this.Demo.animTime: numberanimTime) * const radius: numberradius; // Each segment uses its own static color from the palette. this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(const x1: anyx1), Math.floor(const y1: anyy1));
this.Demo.tempVec2: Vector2itempVec2.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(const x2: anyx2), Math.floor(const y2: anyy2));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, this.Demo.tempVec2: Vector2itempVec2, const C_CIRCLE_BASE: 8C_CIRCLE_BASE + let i: numberi);
} } // Draws a Lissajous curve: a figure where x and y swing back and forth at different // frequencies. The 3:4 ratio here gives an interlocking looping curve (a classic // figure-eight usually comes from a 1:2 ratio). Lissajous figures are used in physics // and electronics to visualize frequency ratios. The colors are animated: 200 curve // points map to 32 color bands, and those bands rotate through the rainbow over time. Demo.drawLissajous(center: any): voiddrawLissajous(center: anycenter) { const const points: 200points = 200; // more points, smoother curve const const a: 3a = 3; // frequency of the horizontal swing const const b: 4b = 4; // frequency of the vertical swing const const radius: 30radius = 30; // Remember the previous point so each step draws a line from it to the new one. let let prevX: numberprevX = 0; let let prevY: numberprevY = 0; for (let let i: numberi = 0; let i: numberi <= const points: 200points; let i: numberi++) { // t runs from 0 to 2 * PI, tracing the full curve. const const t: numbert = (let i: numberi / const points: 200points) * Math.PI * 2; // x swings at frequency a, y at frequency b. Adding animTime to the x phase // makes the figure slowly change shape over time. const const x: anyx = center: anycenter.x + Math.sin(const a: 3a * const t: numbert + this.Demo.animTime: numberanimTime) * const radius: 30radius; const const y: anyy = center: anycenter.y + Math.sin(const b: 4b * const t: numbert) * const radius: 30radius; if (let i: numberi > 0) { // Map this point to one of the 32 color bands: Math.floor((i / points) * // LISSAJOUS_BANDS) gives 0..32, so Math.min caps it at 31 to stay in // range. const const band: anyband = Math.min(Math.floor((let i: numberi / const points: 200points) * const LISSAJOUS_BANDS: 32LISSAJOUS_BANDS), const LISSAJOUS_BANDS: 32LISSAJOUS_BANDS - 1); this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(let prevX: numberprevX), Math.floor(let prevY: numberprevY));
this.Demo.tempVec2: Vector2itempVec2.Vector2i.set(x: number, y: number): Vector2i
Sets both components of this vector. Modifies this vector directly for maximum performance. WARNING: Mutates this vector. Don't use on frozen/cached singletons.
@paramx - New x component.@paramy - New y component.@returnsThis vector for chaining.
set
(Math.floor(const x: anyx), Math.floor(const y: anyy));
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;
    ... 124 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
(this.Demo.tempVec1: Vector2itempVec1, this.Demo.tempVec2: Vector2itempVec2, const C_LISSAJOUS_BASE: 160C_LISSAJOUS_BASE + const band: anyband);
} // Save this point as "previous" for the next step. let prevX: numberprevX = const x: anyx; let prevY: numberprevY = const y: anyy; } } // Draws a tunnel by stacking 20 nested squares of shrinking size. They slowly orbit // and wobble, which gives the illusion of depth. Colors are animated: each square's // hue and brightness come from update(). Demo.drawTunnel(center: any): voiddrawTunnel(center: anycenter) { for (let let i: numberi = 0; let i: numberi < const TUNNEL_RECTS: 20TUNNEL_RECTS; let i: numberi++) { // t = i / TUNNEL_RECTS: i = 0 is the big outer square, the last i the small // inner one (the size uses 1 - t below). const const t: numbert = let i: numberi / const TUNNEL_RECTS: 20TUNNEL_RECTS; // Outer squares are large, inner ones small. The sine term adds a gentle // pulsing wobble to the size. const const size: numbersize = (1 - const t: numbert) * 60 + Math.sin(this.Demo.animTime: numberanimTime * 2 + let i: numberi * 0.3) * 5; // Each square orbits a little around the center. The orbit radius is i, so // the inner squares swing farther, and i * 0.2 gives each one a different // phase. const const angle: numberangle = this.Demo.animTime: numberanimTime + let i: numberi * 0.2; const const offsetX: numberoffsetX = Math.cos(const angle: numberangle) * let i: numberi; const const offsetY: numberoffsetY = Math.sin(const angle: numberangle) * let i: numberi; // Position the square so it is centered on the offset point. const const x: numberx = center: anycenter.x - const size: numbersize / 2 + const offsetX: numberoffsetX; const const y: numbery = center: anycenter.y - const size: numbersize / 2 + const offsetY: numberoffsetY; // Draw the outline in its animated color (updated in update()). this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2i
Sets all components of this rectangle. Modifies this rectangle directly for maximum performance. WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.
@paramx - New x position.@paramy - New y position.@paramwidth - New width.@paramheight - New height.@returnsThis rectangle for chaining.
set
(Math.floor(const x: numberx), Math.floor(const y: numbery), Math.floor(const size: numbersize), Math.floor(const size: numbersize));
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;
    ... 124 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
(this.Demo.tempRect: Rect2itempRect, const C_TUNNEL_BASE: 192C_TUNNEL_BASE + let i: numberi);
} } } // Hand the Demo class to BLIT386 to start the demo loop. 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 DemoDemo);