// Tilemap: build a grid world from a 2D array and scroll the camera across it.
// @description Build a grid world from a two-dimensional array and scroll a camera across it, drawing visible tiles.
//
// Prerequisites: Basics (https://demos.blit386.dev/basics),
// Primitives (https://demos.blit386.dev/primitives),
// Camera (https://demos.blit386.dev/camera).
// Optional background: Sprites (https://demos.blit386.dev/sprites) also
// places art on a grid, but this demo uses colored rectangles instead of a PNG sheet.
//
// Guide: https://blit386.dev/docs/api/camera
//
// A "tilemap" is like a floor made of same-sized square tiles. Each cell in a 2D array
// (a list of rows, each row a list of columns) stores a small number that means "which
// kind of tile goes here" - like a Lego instruction sheet that says which brick color
// fits each stud. The computer walks the grid with nested loops (one loop for rows,
// one loop for columns) and draws only the tiles the camera can see, which is faster
// than drawing thousands of off-screen tiles nobody would see.
//
// This demo uses a 30 by 20 tile world (480 by 320 pixels at 16 pixels per tile). The
// visible screen is only 320 by 240, so the camera slowly pans so you can explore the
// whole map. A mini-map in the corner shows the full world and the yellow box is the
// part you are looking at right now. Pond water on the main map shimmers (animated
// palette slot C_WATER); the mini-map uses a separate still blue (C_MINIMAP_WATER)
// so the overview stays calm and easy to read. The caption panel in the top-left
// corner is drawn with the shared UI kit (src/shared/ui.js), so it matches the
// panels in every other demo.

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 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').HardwareSettings} HardwareSettings */ /** @typedef {import('blit386').Palette} Palette */ // These numbers are the "tile IDs" stored inside the 2D array. // Using named constants helps you remember what each number means when you read the map. const const TILE_SKY: 0TILE_SKY = 0; // Empty air - we skip drawing and let the sky clear color show through. const const TILE_GRASS: 1TILE_GRASS = 1; // Green ground. const const TILE_DIRT: 2TILE_DIRT = 2; // Brown earth below or beside grass. const const TILE_STONE: 3TILE_STONE = 3; // Gray rocks. const const TILE_WATER: 4TILE_WATER = 4; // Blue water (we animate the shade a little each frame). const const TILE_TREE_TOP: 5TILE_TREE_TOP = 5; // Dark green tree canopy. // How many tiles wide and tall the world is. Multiply by TILE_SIZE to get pixel size. const const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES = 30; const const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES = 20; // Every tile is a small square on a pixel grid. 16 is a common retro size. const const TILE_SIZE: 16TILE_SIZE = 16; // World size in pixels: 30 * 16 = 480 wide, 20 * 16 = 320 tall. const const WORLD_WIDTH_PX: numberWORLD_WIDTH_PX = const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES * const TILE_SIZE: 16TILE_SIZE; const const WORLD_HEIGHT_PX: numberWORLD_HEIGHT_PX = const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES * const TILE_SIZE: 16TILE_SIZE; // Each color in this demo has a reserved palette slot (a number from 1 upward). // Index 0 is always transparent. Giving each slot a name makes the drawing code // easier to read - "draw in C_GRASS" is clearer than "draw in index 5." // The caption panel and the mini-map frame use the shared UI kit theme instead, // which applyTheme() installs into high palette slots (240 and up). const const C_SKY: 2C_SKY = 2; // Soft sky blue: fills the screen background const const C_HUD_BAR: 3C_HUD_BAR = 3; // Semi-transparent black: the engine overlay bar color const const C_TEXT_DIM: 4C_TEXT_DIM = 4; // Dimmed white: the engine overlay text color const const C_GRASS: 5C_GRASS = 5; // Green: grass tiles const const C_DIRT: 6C_DIRT = 6; // Brown: dirt tiles const const C_STONE: 7C_STONE = 7; // Gray: stone/rock tiles const const C_TREE_TOP: 8C_TREE_TOP = 8; // Dark green: tree canopy tiles // C_MINIMAP_WATER is a calm, fixed blue for the corner mini-map only. The main view // uses C_WATER, which update() animates every tick so the pond shimmers on screen. const const C_MINIMAP_WATER: 9C_MINIMAP_WATER = 9; // Static blue: water on the mini-map (never animated) const const C_CHART_WARNING: 11C_CHART_WARNING = 11; // Near-white: overlay timing chart warning color const const C_VIEWPORT: 12C_VIEWPORT = 12; // Yellow: rectangle showing the camera view on the mini-map const const C_CHART_TAG: 13C_CHART_TAG = 13; // Dim gray: overlay timing chart tag labels const const C_WATER: 14C_WATER = 14; // DYNAMIC: the animated water tile color, updated every tick in update() /** * Shows a scrolling tile-based landscape with a mini-map and animated water. * * @implements {IBTDemo} */ class class Demo
Shows a scrolling tile-based landscape with a mini-map and animated water.
@implementsIBTDemo
Demo
{
// tilemap is an array of rows. tilemap[row][column] is one cell. // row 0 is the top of the world; column 0 is the left edge. // Think of it like a spreadsheet: first index is how far down, second is how far right. Demo.map: {}map = []; // cameraPos is the top-left corner of the world (in pixels) that appears at the // top-left of the screen. When this moves right, the world seems to slide left. Demo.cameraPos: Vector2icameraPos = 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);
// Where the camera was at the START of the most recent update() tick, before this // tick's sine math moved it. render() blends between cameraPrevPos and cameraPos // using BT.renderAlpha so the camera pans smoothly between physics ticks instead // of jumping - see "Interpolating render state with renderAlpha" in the engine's // docs/api-game-loop.md. Demo.cameraPrevPos: Vector2icameraPrevPos = 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);
// Reused every render() call for the render-time (interpolated) camera position, // so we do not allocate a new Vector2i every frame. Both the actual camera offset // and the visible-tile culling window use this same value, so they never disagree // about which pixel row/column the camera is looking at. Demo.cameraRenderPos: Vector2icameraRenderPos = 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);
// palette holds all the colors this demo uses. We fill it in init() // so the engine knows every color before drawing begins. /** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Slot map for the shared UI kit theme, filled in init() by applyTheme(). // It tells us which palette slots hold the kit's panel, border, and text colors. Demo.theme: nulltheme = null; // One rectangle object we rewrite each time we draw a tile. Reusing it avoids // making a new Rect2i for every single tile, which would stress the garbage collector. Demo.tileRect: Rect2itileRect = 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 TILE_SIZE: 16TILE_SIZE, const TILE_SIZE: 16TILE_SIZE);
/** * @returns {Partial<HardwareSettings>} */ Demo.configure(): Partial<HardwareSettings>
Optional hook to declare display size, optional output drawing-buffer size, upscale filter, target fixed-update rate, rendering backend, and overlay. When omitted, the engine uses {@link defaultConfig } (`320x240` logical, `640x480` drawing buffer, `60` FPS, overlay enabled). When present, you may return only the fields you want to change; the engine merges them with {@link defaultConfig } via {@link mergeHardwareSettings } . Omit `displaySize` to inherit the full default resolution and output buffer. Include `displaySize` when you want a custom logical size; optional fields you omit then stay unset (for example no `drawingBufferSize` means a 1:1 drawing buffer).
@returns
configure
() {
return { isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true, overlayTimingChartDiagnostics: stringoverlayTimingChartDiagnostics: 'rich', isOverlayRendererDiagnosticsBarEnabled: booleanisOverlayRendererDiagnosticsBarEnabled: true,
overlayStyle: {
    barPaletteIndex: number;
    textPaletteIndex: number;
    gapPaletteIndex: number;
}
overlayStyle
: {
barPaletteIndex: numberbarPaletteIndex: const C_HUD_BAR: 3C_HUD_BAR, textPaletteIndex: numbertextPaletteIndex: const C_TEXT_DIM: 4C_TEXT_DIM, gapPaletteIndex: numbergapPaletteIndex: const C_HUD_BAR: 3C_HUD_BAR, },
overlayTimingChartStyle: {
    updateBarPaletteIndex: number;
    renderBarPaletteIndex: number;
    warningPaletteIndex: number;
    errorPaletteIndex: number;
    tagPaletteIndex: number;
}
overlayTimingChartStyle
: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const C_VIEWPORT: 12C_VIEWPORT, renderBarPaletteIndex: numberrenderBarPaletteIndex: const C_GRASS: 5C_GRASS, warningPaletteIndex: numberwarningPaletteIndex: const C_CHART_WARNING: 11C_CHART_WARNING, errorPaletteIndex: numbererrorPaletteIndex: const C_STONE: 7C_STONE, tagPaletteIndex: numbertagPaletteIndex: const C_CHART_TAG: 13C_CHART_TAG, }, }; } /** * Runs once at startup: builds the palette and fills the 2D tilemap array. * * @returns {Promise<boolean>} True when the demo is ready to run. */ async Demo.init(): Promise<boolean>
Runs once at startup: builds the palette and fills the 2D tilemap array.
@returnsTrue when the demo is ready to run.
init
() {
// Set up the color palette // A palette is like an artist's paint tray - we choose all our colors BEFORE // drawing anything. Each color gets a number (an "index") that we use in draw calls. 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);
// Static (fixed) colors: these never change from frame to frame. 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: 2C_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
(135, 206, 250)); // soft sky blue
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_HUD_BAR: 3C_HUD_BAR, 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
(0, 0, 0, 185)); // black with some transparency (alpha 185)
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_TEXT_DIM: 4C_TEXT_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
(200, 200, 200)); // dimmed white for the engine overlay
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_GRASS: 5C_GRASS, 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
(50, 160, 60)); // medium green grass
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_DIRT: 6C_DIRT, 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
(130, 90, 55)); // earthy brown dirt
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_STONE: 7C_STONE, 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
(120, 120, 130)); // cool gray stone
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_TOP: 8C_TREE_TOP, 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, 90, 30)); // very dark green canopy
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_MINIMAP_WATER: 9C_MINIMAP_WATER, 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
(30, 110, 200)); // solid blue for mini-map water
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_CHART_WARNING: 11C_CHART_WARNING, 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
(240, 240, 240)); // near-white chart warnings
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_VIEWPORT: 12C_VIEWPORT, 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, 230, 60)); // yellow camera-viewport box
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_CHART_TAG: 13C_CHART_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
(160, 160, 160)); // medium gray chart tag labels
// Dynamic color: the animated water tile. We give it a starting value here so // there is no empty slot on the very first frame before update() runs. 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_WATER: 14C_WATER, 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
(30, 110, 210)); // initial water blue (updated each tick)
// Install the shared UI kit theme. applyTheme() writes twelve UI colors into // high palette slots (240 and up), far above this demo's scene slots (1..14), // and returns a map of slot numbers we can draw with (panel, border, text...). this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Tell the engine to 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;
    ... 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
);
// Fill tilemap with a simple outdoor scene: sky, grass, dirt, trees, water, rocks. this.Demo.buildLandscape(): void
Creates the 2D array and paints a simple slice of nature: sky, ground strip, trees, a pond at the bottom, and a few stone patches in the water.
buildLandscape
();
return true; } /** * Runs at a fixed rate (60 Hz) for game logic. Moves the camera and updates the * animated water color in the palette so render() can use C_WATER as a plain index. */ Demo.update(): void
Runs at a fixed rate (60 Hz) for game logic. Moves the camera and updates the animated water color in the palette so render() can use C_WATER as a plain index.
update
() {
// Remember where the camera was before this tick's math moves it, so render() // has an "old" and "new" position to blend between. this.Demo.cameraPrevPos: Vector2icameraPrevPos.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
(this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
, this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: number
Vertical component (defaults to 0).
y
);
// BT.ticks counts how many fixed updates have happened since the demo started. // Multiplying by a small number makes the wave change slowly over time. const const t: numbert =
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
.ticks: number
Current fixed-update tick counter. Increments once per engine update. Reset via {@link BT.ticksReset } .
@since1.0.4@returnsCurrent tick count since initialization or last reset.
ticks
* 0.028;
// Math.sin(t) wiggles forever between -1 and +1, like a gentle wave on water. // We scale and shift it so the camera slides horizontally across most of the map. // Floor turns the float into a whole pixel position (BLIT386 uses integer pixels). const const viewSize: Vector2iviewSize =
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
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
;
const const maxCamX: numbermaxCamX = const WORLD_WIDTH_PX: numberWORLD_WIDTH_PX - const viewSize: Vector2iviewSize.Vector2i.x: number
Horizontal component (defaults to 0).
x
;
const const maxCamY: numbermaxCamY = const WORLD_HEIGHT_PX: numberWORLD_HEIGHT_PX - const viewSize: Vector2iviewSize.Vector2i.y: number
Vertical component (defaults to 0).
y
;
const const centerX: numbercenterX = const maxCamX: numbermaxCamX / 2; const const centerY: numbercenterY = const maxCamY: numbermaxCamY / 2; const const amplitudeX: anyamplitudeX = Math.max(0, const maxCamX: numbermaxCamX / 2); const const amplitudeY: anyamplitudeY = Math.max(0, const maxCamY: numbermaxCamY / 2); this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
= Math.floor(const centerX: numbercenterX + Math.sin(const t: numbert) * const amplitudeX: anyamplitudeX);
this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: number
Vertical component (defaults to 0).
y
= Math.floor(const centerY: numbercenterY + Math.sin(const t: numbert * 0.65) * const amplitudeY: anyamplitudeY);
// Clamp keeps the camera inside the world so you never see empty void past the edge. this.Demo.cameraPos: Vector2icameraPos =
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
.cameraClamp: (camera: Vector2i, worldSize: Vector2i, viewSize?: Vector2i) => Vector2i
Clamps a camera origin so the viewport stays within world bounds. Uses integer clamping per axis: `[0, worldSize - viewSize]`. If `viewSize` is omitted, the active {@link BT.displaySize } is used.
@since1.0.3@paramcamera - Desired camera origin in world coordinates.@paramworldSize - Full world size in pixels.@paramviewSize - Viewport size in pixels (defaults to {@link BT.displaySize}).@returnsClamped camera origin.
cameraClamp
(this.Demo.cameraPos: Vector2icameraPos, 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
(const WORLD_WIDTH_PX: numberWORLD_WIDTH_PX, const WORLD_HEIGHT_PX: numberWORLD_HEIGHT_PX), const viewSize: Vector2iviewSize);
// BT.cameraSet() now happens in render(), using a position blended between // cameraPrevPos and cameraPos - see render() below. // Update the animated water color in the palette // Instead of computing a new Color32 inside render() every frame, we compute it // here in update() and store it in the reserved C_WATER palette slot. // render() can then just write C_WATER as a plain number - no Color32 needed there. // This "palette animation" technique is how retro hardware made water shimmer! const const waterPulse: anywaterPulse = Math.sin(
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
.ticks: number
Current fixed-update tick counter. Increments once per engine update. Reset via {@link BT.ticksReset } .
@since1.0.4@returnsCurrent tick count since initialization or last reset.
ticks
* 0.12); // a slow gentle wave between -1 and +1
const const waterBlue: anywaterBlue = Math.floor(210 + const waterPulse: anywaterPulse * 28); // shifts the blue channel 28 units up and down 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_WATER: 14C_WATER, 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
(30, 110, const waterBlue: anywaterBlue));
} /** * Runs once per monitor refresh. Clears the sky, draws visible tiles, then draws HUD * in screen space after resetting the camera. */ Demo.render(): void
Runs once per monitor refresh. Clears the sky, draws visible tiles, then draws HUD in screen space after resetting the camera.
render
() {
// Soft sky blue behind everything. Tiles with ID 0 (sky) are not drawn, so this // color shows through in "empty" cells.
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: 2C_SKY);
// Blend cameraPrevPos toward cameraPos by BT.renderAlpha - a fraction from 0 // (a tick just finished) to just under 1 (the next tick is about to happen) - // so the camera's on-screen position matches this exact render moment instead // of only its last-tick position. Both the camera offset and the visible-tile // culling window below use this same smoothed value. this.Demo.cameraRenderPos: Vector2icameraRenderPos.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(this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
+ (this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
- this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
) *
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
.renderAlpha: number
Fractional progress between the last completed fixed update and the next. Intended for interpolating render state between fixed-update steps.
@since1.3.0@returnsInterpolation alpha in `[0, 1)`.
renderAlpha
),
Math.floor(this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.y: number
Vertical component (defaults to 0).
y
+ (this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: number
Vertical component (defaults to 0).
y
- this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.y: number
Vertical component (defaults to 0).
y
) *
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
.renderAlpha: number
Fractional progress between the last completed fixed update and the next. Intended for interpolating render state between fixed-update steps.
@since1.3.0@returnsInterpolation alpha in `[0, 1)`.
renderAlpha
),
);
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
.cameraSet: (offset: Vector2i) => void
Sets the global camera offset applied to subsequent draw calls.
@since0.1.0@paramoffset - Camera translation in display pixels.
cameraSet
(this.Demo.cameraRenderPos: Vector2icameraRenderPos);
// Draw the chunk of the world that might be visible right now. this.Demo.renderVisibleTiles(): void
Figures out which tile rows and columns overlap the screen and draws only those. That is a simple "culling" optimization: work scales with visible tiles, not the whole 30x20 map (though for this small map either way would be fine).
renderVisibleTiles
();
// HUD and mini-map should stick to the screen, not scroll away with the world.
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
.cameraReset: () => void
Resets the global camera offset to `(0, 0)`.
@since0.1.0
cameraReset
();
this.Demo.renderHud(): void
Draws labels and the mini-map after the camera is reset so they stay on the screen.
renderHud
();
} /** * Creates the 2D array and paints a simple slice of nature: sky, ground strip, trees, * a pond at the bottom, and a few stone patches in the water. */ Demo.buildLandscape(): void
Creates the 2D array and paints a simple slice of nature: sky, ground strip, trees, a pond at the bottom, and a few stone patches in the water.
buildLandscape
() {
// Start with a fresh empty array we will push rows into. this.Demo.map: {}map = []; // Outer loop: each row is one horizontal line of tiles from left to right. for (let let row: numberrow = 0; let row: numberrow < const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES; let row: numberrow++) { // Inner collection for this row's tile IDs. const const line: {}line = []; for (let let col: numbercol = 0; let col: numbercol < const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES; let col: numbercol++) { // Default every cell to sky until we overwrite it below. const line: {}line.push(const TILE_SKY: 0TILE_SKY); } // Attach the finished row to the map (rows stack from top to bottom). this.Demo.map: {}map.push(const line: {}line); } // Ground band: a few rows of grass and dirt in the middle-lower area. const const grassRow: 9grassRow = 9; for (let let col: numbercol = 0; let col: numbercol < const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES; let col: numbercol++) { this.Demo.map: {}map[const grassRow: 9grassRow][let col: numbercol] = const TILE_GRASS: 1TILE_GRASS; this.Demo.map: {}map[const grassRow: 9grassRow + 1][let col: numbercol] = const TILE_DIRT: 2TILE_DIRT; this.Demo.map: {}map[const grassRow: 9grassRow + 2][let col: numbercol] = const TILE_DIRT: 2TILE_DIRT; } // Small hills of dirt sticking up into the sky on the left and right. for (let let col: numbercol = 2; let col: numbercol < 8; let col: numbercol++) { this.Demo.map: {}map[const grassRow: 9grassRow - 1][let col: numbercol] = const TILE_DIRT: 2TILE_DIRT; } for (let let col: numbercol = 22; let col: numbercol < 28; let col: numbercol++) { this.Demo.map: {}map[const grassRow: 9grassRow - 1][let col: numbercol] = const TILE_DIRT: 2TILE_DIRT; } // Tree tops sit on top of grass like broccoli on a plate. const const treeCols: {}treeCols = [4, 5, 14, 15, 16, 25, 26]; for (const const col: anycol of const treeCols: {}treeCols) { this.Demo.map: {}map[const grassRow: 9grassRow - 1][const col: anycol] = const TILE_TREE_TOP: 5TILE_TREE_TOP; this.Demo.map: {}map[const grassRow: 9grassRow - 2][const col: anycol] = const TILE_TREE_TOP: 5TILE_TREE_TOP; } // Wider tree: two tiles side by side on the second canopy row only. this.Demo.map: {}map[const grassRow: 9grassRow - 2][6] = const TILE_TREE_TOP: 5TILE_TREE_TOP; this.Demo.map: {}map[const grassRow: 9grassRow - 2][7] = const TILE_TREE_TOP: 5TILE_TREE_TOP; // Lower area: more dirt, then water rows filling the bottom of the map. const const waterTopRow: 14waterTopRow = 14; for (let let row: numberrow = const grassRow: 9grassRow + 3; let row: numberrow < const waterTopRow: 14waterTopRow; let row: numberrow++) { for (let let col: numbercol = 0; let col: numbercol < const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES; let col: numbercol++) { this.Demo.map: {}map[let row: numberrow][let col: numbercol] = const TILE_DIRT: 2TILE_DIRT; } } // Pond: water across the bottom rows. for (let let row: numberrow = const waterTopRow: 14waterTopRow; let row: numberrow < const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES; let row: numberrow++) { for (let let col: numbercol = 0; let col: numbercol < const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES; let col: numbercol++) { this.Demo.map: {}map[let row: numberrow][let col: numbercol] = const TILE_WATER: 4TILE_WATER; } } // Stepping stones and little islands (stone replaces water in those cells). const const stoneSpots: {}stoneSpots = [ [15, 16], [15, 17], [16, 16], [17, 8], [17, 9], [18, 20], [18, 21], [19, 12], [19, 13], [19, 14], ]; for (const [const row: anyrow, const col: anycol] of const stoneSpots: {}stoneSpots) { this.Demo.map: {}map[const row: anyrow][const col: anycol] = const TILE_STONE: 3TILE_STONE; } // One stone tile peeking at the shoreline. this.Demo.map: {}map[const waterTopRow: 14waterTopRow - 1][10] = const TILE_STONE: 3TILE_STONE; this.Demo.map: {}map[const waterTopRow: 14waterTopRow - 1][11] = const TILE_STONE: 3TILE_STONE; } /** * Figures out which tile rows and columns overlap the screen and draws only those. * That is a simple "culling" optimization: work scales with visible tiles, not the * whole 30x20 map (though for this small map either way would be fine). */ Demo.renderVisibleTiles(): void
Figures out which tile rows and columns overlap the screen and draws only those. That is a simple "culling" optimization: work scales with visible tiles, not the whole 30x20 map (though for this small map either way would be fine).
renderVisibleTiles
() {
// How big is the virtual screen in pixels? const const viewW: numberviewW =
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
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
.Vector2i.x: number
Horizontal component (defaults to 0).
x
;
const const viewH: numberviewH =
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
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
.Vector2i.y: number
Vertical component (defaults to 0).
y
;
// Camera position is the world pixel at the top-left of the view. Use the same // render-time (interpolated) position render() just set with BT.cameraSet(), // so the culling window always agrees with what actually got drawn. const const camX: numbercamX = this.Demo.cameraRenderPos: Vector2icameraRenderPos.Vector2i.x: number
Horizontal component (defaults to 0).
x
;
const const camY: numbercamY = this.Demo.cameraRenderPos: Vector2icameraRenderPos.Vector2i.y: number
Vertical component (defaults to 0).
y
;
// Convert pixel edges to tile indices. Math.floor for the left/top tile, // Math.ceil for the pixel just past the right/bottom edge so we include partial tiles. const const startCol: anystartCol = Math.max(0, Math.floor(const camX: numbercamX / const TILE_SIZE: 16TILE_SIZE)); const const startRow: anystartRow = Math.max(0, Math.floor(const camY: numbercamY / const TILE_SIZE: 16TILE_SIZE)); const const endCol: anyendCol = Math.min(const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES - 1, Math.ceil((const camX: numbercamX + const viewW: numberviewW) / const TILE_SIZE: 16TILE_SIZE) - 1); const const endRow: anyendRow = Math.min(const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES - 1, Math.ceil((const camY: numbercamY + const viewH: numberviewH) / const TILE_SIZE: 16TILE_SIZE) - 1); // Nested loops: outer walks down the rows, inner walks across columns. // This visits every visible cell exactly once. for (let let row: anyrow = const startRow: anystartRow; let row: anyrow <= const endRow: anyendRow; let row: anyrow++) { for (let let col: anycol = const startCol: anystartCol; let col: anycol <= const endCol: anyendCol; let col: anycol++) { // Read which tile kind lives in this grid cell. const const id: anyid = this.Demo.map: {}map[let row: anyrow][let col: anycol]; // Sky tiles are invisible rectangles; the clear color already painted the sky. if (const id: anyid === const TILE_SKY: 0TILE_SKY) { continue; } // World pixel position of this tile's top-left corner. const const worldX: numberworldX = let col: anycol * const TILE_SIZE: 16TILE_SIZE; const const worldY: numberworldY = let row: anyrow * const TILE_SIZE: 16TILE_SIZE; // Reuse the same Rect2i: set(x, y, width, height). this.Demo.tileRect: Rect2itileRect.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
(const worldX: numberworldX, const worldY: numberworldY, const TILE_SIZE: 16TILE_SIZE, const TILE_SIZE: 16TILE_SIZE);
// Pick the palette index for this tile ID. if / else if is like a menu: first match wins. // We pass just a number (C_GRASS, C_DIRT, etc.) - the palette knows the actual color. if (const id: anyid === const TILE_GRASS: 1TILE_GRASS) {
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
(this.Demo.tileRect: Rect2itileRect, const C_GRASS: 5C_GRASS);
} else if (const id: anyid === const TILE_DIRT: 2TILE_DIRT) {
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
(this.Demo.tileRect: Rect2itileRect, const C_DIRT: 6C_DIRT);
} else if (const id: anyid === const TILE_STONE: 3TILE_STONE) {
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
(this.Demo.tileRect: Rect2itileRect, const C_STONE: 7C_STONE);
} else if (const id: anyid === const TILE_WATER: 4TILE_WATER) { // C_WATER is the animated water slot - update() already set its color this frame.
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
(this.Demo.tileRect: Rect2itileRect, const C_WATER: 14C_WATER);
} else if (const id: anyid === const TILE_TREE_TOP: 5TILE_TREE_TOP) {
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
(this.Demo.tileRect: Rect2itileRect, const C_TREE_TOP: 8C_TREE_TOP);
} } } } /** * Draws labels and the mini-map after the camera is reset so they stay on the screen. */ Demo.renderHud(): void
Draws labels and the mini-map after the camera is reset so they stay on the screen.
renderHud
() {
// The caption panel is built with the shared UI kit. Widgets declared between // ui.begin() and ui.end() stack into one anchored group; the kit measures the // rows, draws the panel background, and places the group for us. // The kit draws in whatever camera space is active, so this must run AFTER // BT.cameraReset() - otherwise the panel would scroll away with the world. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT); import uiui.panel('Tilemap'); import uiui.label('30x20 tiles, 16px each', { color: stringcolor: 'dim' }); import uiui.label('Camera scrolls automatically', { color: stringcolor: 'dim' }); import uiui.end(); // Mini-map sits in the bottom-right, like a treasure map corner-fold. this.Demo.renderMiniMap(): void
Scales the whole tilemap down so each tile is a 3x3 pixel square on the HUD. Draws a yellow rectangle around the area the main camera is showing.
renderMiniMap
();
} /** * Scales the whole tilemap down so each tile is a 3x3 pixel square on the HUD. * Draws a yellow rectangle around the area the main camera is showing. */ Demo.renderMiniMap(): void
Scales the whole tilemap down so each tile is a 3x3 pixel square on the HUD. Draws a yellow rectangle around the area the main camera is showing.
renderMiniMap
() {
const const mapX: 218mapX = 218; const const mapY: 158mapY = 158; const const scale: 3scale = 3; // Each world tile becomes a 3 by 3 block on the mini-map. const const mapPixelW: numbermapPixelW = const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES * const scale: 3scale; const const mapPixelH: numbermapPixelH = const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES * const scale: 3scale; // Backing panel from the shared UI kit (same look as every other demo panel). // spacer() reserves the tile area; the custom tile overlay draws on top after end(). import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { x: numberx: const mapX: 218mapX - 2, y: numbery: const mapY: 158mapY - 2, width: numberwidth: const mapPixelW: numbermapPixelW + 4, margin: numbermargin: 0, pad: numberpad: 2 }); import uiui.panel(); import uiui.spacer(const mapPixelH: numbermapPixelH); import uiui.end(); // Walk every tile in the entire world (the map is small, so this is cheap). for (let let row: numberrow = 0; let row: numberrow < const MAP_HEIGHT_TILES: 20MAP_HEIGHT_TILES; let row: numberrow++) { for (let let col: numbercol = 0; let col: numbercol < const MAP_WIDTH_TILES: 30MAP_WIDTH_TILES; let col: numbercol++) { const const id: anyid = this.Demo.map: {}map[let row: numberrow][let col: numbercol]; const const px: numberpx = const mapX: 218mapX + let col: numbercol * const scale: 3scale; const const py: numberpy = const mapY: 158mapY + let row: numberrow * const scale: 3scale; // Pick a palette index for each tile type. // Using C_SKY for sky tiles shows the background color as the map background. // We use C_MINIMAP_WATER for water on the mini-map - this is a static shade, // not the animated C_WATER, so the mini-map stays calm even as the tiles shimmer. let let c: numberc = const C_SKY: 2C_SKY; if (const id: anyid === const TILE_GRASS: 1TILE_GRASS) { let c: numberc = const C_GRASS: 5C_GRASS; } else if (const id: anyid === const TILE_DIRT: 2TILE_DIRT) { let c: numberc = const C_DIRT: 6C_DIRT; } else if (const id: anyid === const TILE_STONE: 3TILE_STONE) { let c: numberc = const C_STONE: 7C_STONE; } else if (const id: anyid === const TILE_WATER: 4TILE_WATER) { let c: numberc = const C_MINIMAP_WATER: 9C_MINIMAP_WATER; } else if (const id: anyid === const TILE_TREE_TOP: 5TILE_TREE_TOP) { let c: numberc = const C_TREE_TOP: 8C_TREE_TOP; } this.Demo.tileRect: Rect2itileRect.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
(const px: numberpx, const py: numberpy, const scale: 3scale, const scale: 3scale);
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
(this.Demo.tileRect: Rect2itileRect, let c: numberc);
} } // Viewport indicator: where is the 320x240 window inside the 480x320 world? // Use this.cameraPos, not BT.camera: render() already called BT.cameraReset(), // which zeroes BT.camera - our own field still remembers the real position. const const cam: Vector2icam = this.Demo.cameraPos: Vector2icameraPos; const const disp: Vector2idisp =
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
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
;
const const vx: anyvx = const mapX: 218mapX + Math.floor((const cam: Vector2icam.Vector2i.x: number
Horizontal component (defaults to 0).
x
/ const WORLD_WIDTH_PX: numberWORLD_WIDTH_PX) * const mapPixelW: numbermapPixelW);
const const vy: anyvy = const mapY: 158mapY + Math.floor((const cam: Vector2icam.Vector2i.y: number
Vertical component (defaults to 0).
y
/ const WORLD_HEIGHT_PX: numberWORLD_HEIGHT_PX) * const mapPixelH: numbermapPixelH);
const const vw: anyvw = Math.max(1, Math.floor((const disp: Vector2idisp.Vector2i.x: number
Horizontal component (defaults to 0).
x
/ const WORLD_WIDTH_PX: numberWORLD_WIDTH_PX) * const mapPixelW: numbermapPixelW));
const const vh: anyvh = Math.max(1, Math.floor((const disp: Vector2idisp.Vector2i.y: number
Vertical component (defaults to 0).
y
/ const WORLD_HEIGHT_PX: numberWORLD_HEIGHT_PX) * const mapPixelH: numbermapPixelH));
this.Demo.tileRect: Rect2itileRect.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
(const vx: anyvx, const vy: anyvy, const vw: anyvw, const vh: anyvh);
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
(this.Demo.tileRect: Rect2itileRect, const C_VIEWPORT: 12C_VIEWPORT);
} } // bootstrap() wires this class into the engine: it creates an instance and runs the 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 Demo
Shows a scrolling tile-based landscape with a mini-map and animated water.
@implementsIBTDemo
Demo
);