/**
 * Input Map Remapping Demo - runtime `BT.inputMap` and `BT.inputMapReset`.
 * @description Remap face buttons at runtime with BT.inputMap: defaults, custom OR keys, and clearing a binding.
 *
 * Part of the BLIT386 demo series.
 * Prerequisites: Basics (https://demos.blit386.dev/basics),
 * Keyboard Input (https://demos.blit386.dev/keyboard-input).
 *
 * Live version: https://demos.blit386.dev/input-map-remapping
 *
 * The engine stores two runtime keyboard tables (players 0 and 1). Each
 * face button (`BT.BTN_UP` through `BT.BTN_SELECT`) can list zero or more
 * `KeyboardEvent.code` strings. If any listed key is held, the logical
 * button counts as down (OR). This demo switches presets so you can feel
 * defaults, a custom map, and a cleared binding.
 *
 * Important: `BT.isKeyDown('KeyW')` only watches the real W key. Changing the map
 * does not rename keys - it changes which keys feed face buttons through
 * `BT.isDown(BT.BTN_*, player)`.
 *
 * The preset switches are shared-UI-kit buttons (src/shared/ui.js), so on a phone
 * you can tap them; on a keyboard the number keys printed on each button still work.
 *
 * Try this:
 * - Press 1 (or tap the button) for built-in defaults (`BT.inputMapReset()`).
 * - Press 2 for a custom layout (see on-screen text).
 * - Press 3 to clear player 0's A button until you pick another preset.
 * - Press 0 or R anytime to restore defaults (same idea as 1).
 * - Click the canvas if preset keys stop responding (focus left the page).
 */

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 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 */ // Layout for a 640x480 logical framebuffer (set in configure(); wider than engine default). const const DISPLAY_W: 640DISPLAY_W = 640; const const DISPLAY_H: 480DISPLAY_H = 480; const const MARGIN_X: 24MARGIN_X = 24; const const GAP_PANELS: 24GAP_PANELS = 24; // Two equal columns: margin + panel + gap + panel + margin == DISPLAY_W. const const PANEL_W: anyPANEL_W = Math.floor((const DISPLAY_W: 640DISPLAY_W - 2 * const MARGIN_X: 24MARGIN_X - const GAP_PANELS: 24GAP_PANELS) / 2); const const PANEL0_X: 24PANEL0_X = const MARGIN_X: 24MARGIN_X; const const PANEL1_X: anyPANEL1_X = const MARGIN_X: 24MARGIN_X + const PANEL_W: anyPANEL_W + const GAP_PANELS: 24GAP_PANELS; // Where the intro text and the two player panels start, measured from the top of the // screen in pixels. The top bar strip drawn by the kit is 22 pixels tall, so 28 clears it. const const INTRO_Y: 28INTRO_Y = 28; const const PANEL_TOP_Y: 88PANEL_TOP_Y = 88; // All four preset buttons share one width so the column reads as a tidy block. const const PRESET_BUTTON_W: 200PRESET_BUTTON_W = 200; // The engine overlay (configured below) needs palette slot numbers, but configure() runs // BEFORE init(), where applyTheme() installs the shared UI colors. applyTheme() always // writes its twelve colors into slots 240..251 (its default start slot), so we can write // the slot numbers out here as named constants instead of magic numbers. const const THEME_SLOT_PANEL: 242THEME_SLOT_PANEL = 242; // Panel fill (dark blue). const const THEME_SLOT_TEXT: 244THEME_SLOT_TEXT = 244; // Primary text (off-white). const const THEME_SLOT_HEADER: 246THEME_SLOT_HEADER = 246; // Panel titles (warm amber). const const THEME_SLOT_ACCENT: 247THEME_SLOT_ACCENT = 247; // Lit / active (phosphor green). const const THEME_SLOT_WARM: 248THEME_SLOT_WARM = 248; // Warnings (warm orange). /** @type {Array<{ label: string, code: number }>} */ const
const FACE_BUTTONS: Array<{
    label: string;
    code: number;
}>
@type{Array<{ label: string, code: number }>}
FACE_BUTTONS
= [
{ label: stringlabel: 'Up', code: numbercode:
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
.type BTN_UP: number
Up button bit flag.
@since0.1.0
BTN_UP
},
{ label: stringlabel: 'Down', code: numbercode:
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
.type BTN_DOWN: number
Down button bit flag.
@since0.1.0
BTN_DOWN
},
{ label: stringlabel: 'Left', code: numbercode:
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
.type BTN_LEFT: number
Left button bit flag.
@since0.1.0
BTN_LEFT
},
{ label: stringlabel: 'Right', code: numbercode:
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
.type BTN_RIGHT: number
Right button bit flag.
@since0.1.0
BTN_RIGHT
},
{ label: stringlabel: 'A', code: numbercode:
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
.type BTN_A: number
A button bit flag.
@since0.1.0
BTN_A
},
{ label: stringlabel: 'B', code: numbercode:
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
.type BTN_B: number
B button bit flag.
@since0.1.0
BTN_B
},
{ label: stringlabel: 'Start', code: numbercode:
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
.type BTN_START: number
Start button bit flag.
@since0.1.0
BTN_START
},
{ label: stringlabel: 'Select', code: numbercode:
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
.type BTN_SELECT: number
Select button bit flag.
@since0.1.0
BTN_SELECT
},
]; /** * Cycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`. * * @implements {IBTDemo} */ class class Demo
Cycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`.
@implementsIBTDemo
Demo
{
/** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Palette slot map returned by applyTheme() - theme.bg, theme.text, and friends. /** @type {ReturnType<typeof applyTheme> | null} */ Demo.theme: any
@type{ReturnType<typeof applyTheme> | null}
theme
= null;
// Human-readable name for the active preset (we track it ourselves - the // engine does not expose a "get current map" API). Demo.presetLabel: stringpresetLabel = '1 Defaults (engine tables)'; /** * Wider logical canvas than `defaultConfig()` so two panels of key maps fit comfortably. * No post-process effects, so we upscale 2x in the browser (maxCanvasSize) instead * of allocating a larger drawing buffer (drawingBufferSize). * * @returns {Partial<HardwareSettings>} */ Demo.configure(): Partial<HardwareSettings>
Wider logical canvas than `defaultConfig()` so two panels of key maps fit comfortably. No post-process effects, so we upscale 2x in the browser (maxCanvasSize) instead of allocating a larger drawing buffer (drawingBufferSize).
@returns
configure
() {
return { displaySize: Vector2idisplaySize: 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 DISPLAY_W: 640DISPLAY_W, const DISPLAY_H: 480DISPLAY_H),
maxCanvasSize: Vector2imaxCanvasSize: 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 DISPLAY_W: 640DISPLAY_W * 2, const DISPLAY_H: 480DISPLAY_H * 2),
targetFPS: numbertargetFPS: 60,
overlayStyle: {
    barPaletteIndex: number;
    textPaletteIndex: number;
    gapPaletteIndex: number;
}
overlayStyle
: {
barPaletteIndex: numberbarPaletteIndex: const THEME_SLOT_PANEL: 242THEME_SLOT_PANEL, textPaletteIndex: numbertextPaletteIndex: const THEME_SLOT_TEXT: 244THEME_SLOT_TEXT, gapPaletteIndex: numbergapPaletteIndex: const THEME_SLOT_PANEL: 242THEME_SLOT_PANEL, }, isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true,
overlayTimingChartStyle: {
    updateBarPaletteIndex: number;
    renderBarPaletteIndex: number;
    warningPaletteIndex: number;
    errorPaletteIndex: number;
    tagPaletteIndex: number;
}
overlayTimingChartStyle
: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const THEME_SLOT_ACCENT: 247THEME_SLOT_ACCENT, renderBarPaletteIndex: numberrenderBarPaletteIndex: const THEME_SLOT_HEADER: 246THEME_SLOT_HEADER, warningPaletteIndex: numberwarningPaletteIndex: const THEME_SLOT_WARM: 248THEME_SLOT_WARM, errorPaletteIndex: numbererrorPaletteIndex: const THEME_SLOT_WARM: 248THEME_SLOT_WARM, tagPaletteIndex: numbertagPaletteIndex: const THEME_SLOT_ACCENT: 247THEME_SLOT_ACCENT, }, // Arrow keys and Space scroll the host page by default. This demo maps those keys // (player 1 uses arrows), so opt in so pressing them does not move the page. isCapturingKeyboardScroll: booleanisCapturingKeyboardScroll: true, }; } /** * Palette setup and a clean slate for keyboard maps when the page loads. * * @returns {Promise<boolean>} */ async Demo.init(): Promise<boolean>
Palette setup and a clean slate for keyboard maps when the page loads.
@returns
init
() {
this.Demo.palette: Palette | null
@type{Palette | null}
palette
=
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteCreate: (size?: number) => Palette
Creates a standalone palette instance.
@since1.0.3@paramsize - Palette size. Defaults to 256 colors.@returnsNew mutable palette.
paletteCreate
(256);
// Install the shared UI theme (twelve colors in slots 240..251) before handing // the palette to the engine. Every panel, button, and pip below draws with these. this.Demo.theme: any
@type{ReturnType<typeof applyTheme> | null}
theme
= import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteSet: (palette: Palette) => void
Stores the active engine palette. Use this to swap the **entire palette** (e.g. switch between a day and night theme). After this call the renderer uploads the new palette uniform on the next frame. **Palette-value swap (change what a slot looks like):** mutate the live {@link BT.palette } in place with `palette.set(slot, newColor)`. The renderer uploads dirty slots on the next frame; no `paletteSet()` or {@link BT.spritesRefresh } needed. **Palette-layout swap (same colors, different slot positions):** build a new palette with the same colors at new indices, call `paletteSet()`, then call {@link BT.spritesRefresh } so every sprite sheet re-maps its original RGBA pixels against the new slot layout.
@since1.0.3@parampalette - Palette to make active.
paletteSet
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Copy fresh maps from `BT.DEFAULT_KEYBOARD_PLAYER1` / `...PLAYER2` // so hot reload or revisiting this URL does not inherit another demo's edits.
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
.inputMapReset: () => void
Restores built-in default keyboard maps for players `0` and `1`. Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.
@since1.0.3
inputMapReset
();
this.Demo.presetLabel: stringpresetLabel = '1 Defaults (engine tables)'; return true; } /** * Update-side housekeeping for the UI kit, plus one extra keyboard alias. */ Demo.update(): void
Update-side housekeeping for the UI kit, plus one extra keyboard alias.
update
() {
// Let the kit latch keyboard shortcuts and touch contacts for this frame's // buttons. This must be the first line of update() when buttons use { key }. import uiui.tick(); // The reset button below is bound to Digit0, but the original demo also accepted // R as a second reset key. A kit button can only carry one key binding, so this // alias stays here in update() (keyboard edges are safe to read here - never in // render()). `isKeyPressed` without a repeat rate only fires once per press. if (
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
.isKeyPressed: (key: string, repeatRate?: number) => boolean
Checks whether a keyboard key was pressed on the current fixed-update tick. Optional `repeatRate` is in fixed ticks between repeats (`0` or omitted = edge only). When `repeatRate > 0`, repeats fire while held per `(ticks - firstPressTick) > 0 && (ticks - firstPressTick) % repeatRate === 0`. Call from `update()`, not `render()`: the press edge clears once per fixed-update tick, which always runs before that frame's `render()`, so a press read from `render()` can be intermittently missed under rapid input.
@since1.1.1@paramkey - DOM keyboard code string.@paramrepeatRate - Ticks between repeat triggers; omit or `0` for no repeat.@returns`true` on the press edge (and on repeat ticks when configured).
isKeyPressed
('KeyR')) {
this.Demo.applyPresetDefaults(): void
Restore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies).
applyPresetDefaults
();
} } /** * Draw the intro text, the preset buttons, and both player panels. */ Demo.render(): void
Draw the intro text, the preset buttons, and both player panels.
render
() {
// Wipe the whole screen with the theme's deep-navy background color.
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
(this.Demo.theme: any
@type{ReturnType<typeof applyTheme> | null}
theme
.bg);
// Full-width 22-pixel title strip across the top of the screen. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_BAR); import uiui.panel('Input Map Remapping - BT.inputMap / BT.inputMapReset'); import uiui.end(); // A borderless text group under the title: what the demo is about, plus the // classic "click the canvas" focus tip. No ui.panel() call means no box is drawn. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { x: numberx: const MARGIN_X: 24MARGIN_X, y: numbery: const INTRO_Y: 28INTRO_Y }); import uiui.label('Face buttons use BT.isDown(BTN_*, player). Remap at runtime with BT.inputMap.', { color: stringcolor: 'dim' }); import uiui.label('Tap a preset button or press its number key. Click the canvas if keys stop.', { color: stringcolor: 'dim' }); import uiui.end(); // One panel of live face-button pips per player, side by side. this.Demo.renderPlayerPanel(player: number, originX: number, originY: number): void
One player's panel: title, default-key hints, and a column of live face-button pips.
@paramplayer - 0 or 1.@paramoriginX - Left edge (pixels).@paramoriginY - Top edge (pixels).
renderPlayerPanel
(0, const PANEL0_X: 24PANEL0_X, const PANEL_TOP_Y: 88PANEL_TOP_Y);
this.Demo.renderPlayerPanel(player: number, originX: number, originY: number): void
One player's panel: title, default-key hints, and a column of live face-button pips.
@paramplayer - 0 or 1.@paramoriginX - Left edge (pixels).@paramoriginY - Top edge (pixels).
renderPlayerPanel
(1, const PANEL1_X: anyPANEL1_X, const PANEL_TOP_Y: 88PANEL_TOP_Y);
// The preset switcher lives in its own panel in the bottom-left corner. Each // ui.button() returns true on the one frame it is clicked, tapped, or its bound // key goes down - all three inputs behave exactly the same. import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_LEFT); import uiui.panel('Presets'); if (import uiui.button('1 - Defaults (inputMapReset)', { key: stringkey: 'Digit1', width: numberwidth: const PRESET_BUTTON_W: 200PRESET_BUTTON_W })) { this.Demo.applyPresetDefaults(): void
Restore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies).
applyPresetDefaults
();
} if (import uiui.button('2 - Custom map (Z, Q/E, I)', { key: stringkey: 'Digit2', width: numberwidth: const PRESET_BUTTON_W: 200PRESET_BUTTON_W })) { this.Demo.applyPresetCustom(): void
Custom layout: remap a few buttons, and give **two** keys for one direction so either key counts (OR) - hold Q **or** E and player 0 left should light.
applyPresetCustom
();
} if (import uiui.button('3 - Clear P0 A button', { key: stringkey: 'Digit3', width: numberwidth: const PRESET_BUTTON_W: 200PRESET_BUTTON_W })) { this.Demo.applyPresetClearPlayer0A(): void
Defaults everywhere, then **remove** keyboard bindings for player 0's A button. Passing **no** key strings clears that slot until you map again.
applyPresetClearPlayer0A
();
} if (import uiui.button('0 - Reset (also R key)', { key: stringkey: 'Digit0', width: numberwidth: const PRESET_BUTTON_W: 200PRESET_BUTTON_W })) { this.Demo.applyPresetDefaults(): void
Restore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies).
applyPresetDefaults
();
} // A thin rule, then the name of whichever preset is active right now. import uiui.separator(); import uiui.kv('Active', this.Demo.presetLabel: stringpresetLabel); import uiui.end(); } /** * Restore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies). */ Demo.applyPresetDefaults(): void
Restore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies).
applyPresetDefaults
() {
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
.inputMapReset: () => void
Restores built-in default keyboard maps for players `0` and `1`. Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.
@since1.0.3
inputMapReset
();
this.Demo.presetLabel: stringpresetLabel = '1 Defaults (BT.inputMapReset)';
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
.assignTag: (label?: string) => void
Places a labeled marker on the overlay timing chart at the current tick. Requires `isOverlayTimingChartEnabled: true` in `configure()`. Tags scroll with the chart history and are pruned when they leave the visible window. Empty labels become `"Untitled"`. Chart width resets add an automatic `"Start"` tag.
@since1.1.0@paramlabel - Short event name (for example `'Round start'`).
assignTag
('Map: defaults');
} /** * Custom layout: remap a few buttons, and give **two** keys for one direction * so either key counts (OR) - hold Q **or** E and player 0 left should light. */ Demo.applyPresetCustom(): void
Custom layout: remap a few buttons, and give **two** keys for one direction so either key counts (OR) - hold Q **or** E and player 0 left should light.
applyPresetCustom
() {
// Start from known defaults, then layer edits (order matters only for clarity).
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
.inputMapReset: () => void
Restores built-in default keyboard maps for players `0` and `1`. Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.
@since1.0.3
inputMapReset
();
// Player 0: A is **Z** only for this preset (Space no longer maps here until reset).
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
.inputMap: (player: number, button: number, ...keys: string[]) => void
Assigns one or more `KeyboardEvent.code` values to a face button for a keyboard player. Logical button state is the OR of all listed keys. Only players `0` and `1` support keyboard; other indices no-op. `button` must be one face-button bit flag (`BT.BTN_UP` … `BT.BTN_SELECT`). Pass an empty key list to clear keyboard bindings for that button until remapped again.
@since1.0.3@paramplayer - Zero-based player index (`0` or `1`).@parambutton - Face button constant.@paramkeys - DOM key codes (for example `'Space'`, `'KeyW'`).
inputMap
(0,
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
.type BTN_A: number
A button bit flag.
@since0.1.0
BTN_A
, 'KeyZ');
// Player 1: move **up** to **I** so arrow keys no longer drive UP for this preset // until we reset (we replace the whole key list for that button).
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
.inputMap: (player: number, button: number, ...keys: string[]) => void
Assigns one or more `KeyboardEvent.code` values to a face button for a keyboard player. Logical button state is the OR of all listed keys. Only players `0` and `1` support keyboard; other indices no-op. `button` must be one face-button bit flag (`BT.BTN_UP` … `BT.BTN_SELECT`). Pass an empty key list to clear keyboard bindings for that button until remapped again.
@since1.0.3@paramplayer - Zero-based player index (`0` or `1`).@parambutton - Face button constant.@paramkeys - DOM key codes (for example `'Space'`, `'KeyW'`).
inputMap
(1,
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
.type BTN_UP: number
Up button bit flag.
@since0.1.0
BTN_UP
, 'KeyI');
// Player 0: LEFT listens to **two** keys at once - first **or** second held counts.
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
.inputMap: (player: number, button: number, ...keys: string[]) => void
Assigns one or more `KeyboardEvent.code` values to a face button for a keyboard player. Logical button state is the OR of all listed keys. Only players `0` and `1` support keyboard; other indices no-op. `button` must be one face-button bit flag (`BT.BTN_UP` … `BT.BTN_SELECT`). Pass an empty key list to clear keyboard bindings for that button until remapped again.
@since1.0.3@paramplayer - Zero-based player index (`0` or `1`).@parambutton - Face button constant.@paramkeys - DOM key codes (for example `'Space'`, `'KeyW'`).
inputMap
(0,
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
.type BTN_LEFT: number
Left button bit flag.
@since0.1.0
BTN_LEFT
, 'KeyQ', 'KeyE');
this.Demo.presetLabel: stringpresetLabel = '2 Custom (P0: Z=A, Q|E=Lft | P1: I=Up)';
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
.assignTag: (label?: string) => void
Places a labeled marker on the overlay timing chart at the current tick. Requires `isOverlayTimingChartEnabled: true` in `configure()`. Tags scroll with the chart history and are pruned when they leave the visible window. Empty labels become `"Untitled"`. Chart width resets add an automatic `"Start"` tag.
@since1.1.0@paramlabel - Short event name (for example `'Round start'`).
assignTag
('Map: custom');
} /** * Defaults everywhere, then **remove** keyboard bindings for player 0's A button. * Passing **no** key strings clears that slot until you map again. */ Demo.applyPresetClearPlayer0A(): void
Defaults everywhere, then **remove** keyboard bindings for player 0's A button. Passing **no** key strings clears that slot until you map again.
applyPresetClearPlayer0A
() {
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
.inputMapReset: () => void
Restores built-in default keyboard maps for players `0` and `1`. Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.
@since1.0.3
inputMapReset
();
// Empty rest arguments -> empty list stored -> no key lights BTN_A for player 0.
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
.inputMap: (player: number, button: number, ...keys: string[]) => void
Assigns one or more `KeyboardEvent.code` values to a face button for a keyboard player. Logical button state is the OR of all listed keys. Only players `0` and `1` support keyboard; other indices no-op. `button` must be one face-button bit flag (`BT.BTN_UP` … `BT.BTN_SELECT`). Pass an empty key list to clear keyboard bindings for that button until remapped again.
@since1.0.3@paramplayer - Zero-based player index (`0` or `1`).@parambutton - Face button constant.@paramkeys - DOM key codes (for example `'Space'`, `'KeyW'`).
inputMap
(0,
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
.type BTN_A: number
A button bit flag.
@since0.1.0
BTN_A
);
this.Demo.presetLabel: stringpresetLabel = '3 Cleared P0 A (BT.inputMap(0, BTN_A) with no keys)';
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
.assignTag: (label?: string) => void
Places a labeled marker on the overlay timing chart at the current tick. Requires `isOverlayTimingChartEnabled: true` in `configure()`. Tags scroll with the chart history and are pruned when they leave the visible window. Empty labels become `"Untitled"`. Chart width resets add an automatic `"Start"` tag.
@since1.1.0@paramlabel - Short event name (for example `'Round start'`).
assignTag
('Map: cleared A');
} /** * One player's panel: title, default-key hints, and a column of live face-button pips. * * @param {number} player - 0 or 1. * @param {number} originX - Left edge (pixels). * @param {number} originY - Top edge (pixels). */ Demo.renderPlayerPanel(player: number, originX: number, originY: number): void
One player's panel: title, default-key hints, and a column of live face-button pips.
@paramplayer - 0 or 1.@paramoriginX - Left edge (pixels).@paramoriginY - Top edge (pixels).
renderPlayerPanel
(player: number
- 0 or 1.
@paramplayer - 0 or 1.
player
, originX: number
- Left edge (pixels).
@paramoriginX - Left edge (pixels).
originX
, originY: number
- Top edge (pixels).
@paramoriginY - Top edge (pixels).
originY
) {
// Pin the group at an exact position and force both panels to the same width so // the two columns line up regardless of how long each panel's text rows are. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { x: numberx: originX: number
- Left edge (pixels).
@paramoriginX - Left edge (pixels).
originX
, y: numbery: originY: number
- Top edge (pixels).
@paramoriginY - Top edge (pixels).
originY
, width: anywidth: const PANEL_W: anyPANEL_W });
import uiui.panel(player: number
- 0 or 1.
@paramplayer - 0 or 1.
player
=== 0 ? 'Player 0' : 'Player 1');
// Which physical keys feed this player's face buttons out of the box. The custom // preset changes some of these - that is the whole point of the demo. if (player: number
- 0 or 1.
@paramplayer - 0 or 1.
player
=== 0) {
import uiui.label('Default keys: W, A, S, D move', { color: stringcolor: 'dim' }); import uiui.label('Space or B=A, N=B, 5=Start, Esc=Select', { color: stringcolor: 'dim' }); } else { import uiui.label('Default keys: arrows move', { color: stringcolor: 'dim' }); import uiui.label('; or 1=A, quote or 2=B', { color: stringcolor: 'dim' }); import uiui.label('Backspace or Numpad / = Start', { color: stringcolor: 'dim' }); } import uiui.separator(); // One read-only pip per logical face button. The pip lights up while the button // is held. `code` is a BT.BTN_* constant (Up, A, Start, ...), not a raw key // string - the runtime map (changed by BT.inputMap) decides which physical keys // feed it. BT.isDown reads held state (not a press edge), so it is safe here in // render(). for (let let i: numberi = 0; let i: numberi <
const FACE_BUTTONS: Array<{
    label: string;
    code: number;
}>
@type{Array<{ label: string, code: number }>}
FACE_BUTTONS
.length; let i: numberi++) {
const {
const label: Array<{
    label: string;
    code: number;
}>
label
,
const code: Array<{
    label: string;
    code: number;
}>
code
} =
const FACE_BUTTONS: Array<{
    label: string;
    code: number;
}>
@type{Array<{ label: string, code: number }>}
FACE_BUTTONS
[let i: numberi];
import uiui.pip(
const label: Array<{
    label: string;
    code: number;
}>
label
,
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
.isDown: (button: number, player?: number) => boolean
Checks whether a button is currently held. For pointer buttons (`BTN_POINTER_A..D`), the second parameter is the pointer slot index (0 = mouse, 1-3 = touch / pen). For mouse slot 0: `A` is left, `B` is right, `C` is middle, `D` is back / forward (matches RetroBlit canonical, not DOM `PointerEvent.button` index). Touch / pen slots only support `A`; B/C/D return `false`. `button` accepts one or more bit flags from the `BTN_*` set (for example `BT.BTN_A | BT.BTN_B`). Matching uses ANY semantics: returns `true` when any selected button is held. For face buttons (`BTN_UP`…`BTN_SELECT`), players `0` and `1` merge keyboard and gamepad input (logical OR). Players `2` and `3` use gamepad only. Pointer flags (`BTN_POINTER_*`) use the `player` argument as pointer slot.
@since1.1.1@parambutton - Button constant from the `BTN_*` set.@paramplayer - Zero-based player index for gamepads / keyboard, or pointer slot (0-3) for `BTN_POINTER_*`.@returns`true` while the button remains pressed.
isDown
(
const code: Array<{
    label: string;
    code: number;
}>
code
, player: number
- 0 or 1.
@paramplayer - 0 or 1.
player
));
} import uiui.end(); } } 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
Cycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`.
@implementsIBTDemo
Demo
);