/**
* 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.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 Vector2iInteger 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.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;
}>
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: numberUp button bit flag.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: numberDown button bit flag.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: numberLeft button bit flag.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: numberRight button bit flag.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: numberA button bit flag.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: numberB button bit flag.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: numberStart button bit flag.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: numberSelect button bit flag.BTN_SELECT },
];
/**
* Cycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`.
*
* @implements {IBTDemo}
*/
class class DemoCycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`.Demo {
/** @type {Palette | null} */
Demo.palette: Palette | nullpalette = null;
// Palette slot map returned by applyTheme() - theme.bg, theme.text, and friends.
/** @type {ReturnType<typeof applyTheme> | null} */
Demo.theme: anytheme = 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).configure() {
return {
displaySize: Vector2idisplaySize: new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const DISPLAY_W: 640DISPLAY_W, const DISPLAY_H: 480DISPLAY_H),
maxCanvasSize: Vector2imaxCanvasSize: new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.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.init() {
this.Demo.palette: Palette | nullpalette = 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) => PaletteCreates a standalone palette instance.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: anytheme = import applyThemeapplyTheme(this.Demo.palette: Palettepalette);
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) => voidStores 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.paletteSet(this.Demo.palette: Palettepalette);
// 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: () => voidRestores built-in default keyboard maps for players `0` and `1`.
Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.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(): voidUpdate-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) => booleanChecks 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.isKeyPressed('KeyR')) {
this.Demo.applyPresetDefaults(): voidRestore the shipped tables (`BT.DEFAULT_KEYBOARD_PLAYER1` / PLAYER2 copies).applyPresetDefaults();
}
}
/**
* Draw the intro text, the preset buttons, and both player panels.
*/
Demo.render(): voidDraw 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) => voidSets 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.clear(this.Demo.theme: anytheme.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): voidOne player's panel: title, default-key hints, and a column of live face-button pips.renderPlayerPanel(0, const PANEL0_X: 24PANEL0_X, const PANEL_TOP_Y: 88PANEL_TOP_Y);
this.Demo.renderPlayerPanel(player: number, originX: number, originY: number): voidOne player's panel: title, default-key hints, and a column of live face-button pips.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(): voidRestore 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(): voidCustom 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(): voidDefaults 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(): voidRestore 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(): voidRestore 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: () => voidRestores built-in default keyboard maps for players `0` and `1`.
Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.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) => voidPlaces 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.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(): voidCustom 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: () => voidRestores built-in default keyboard maps for players `0` and `1`.
Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.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[]) => voidAssigns 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.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: numberA button bit flag.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[]) => voidAssigns 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.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: numberUp button bit flag.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[]) => voidAssigns 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.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: numberLeft button bit flag.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) => voidPlaces 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.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(): voidDefaults 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: () => voidRestores built-in default keyboard maps for players `0` and `1`.
Same tables as `BT.DEFAULT_KEYBOARD_PLAYER1` and `BT.DEFAULT_KEYBOARD_PLAYER2`.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[]) => voidAssigns 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.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: numberA button bit flag.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) => voidPlaces 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.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): voidOne player's panel: title, default-key hints, and a column of live face-button pips.renderPlayerPanel(player: number- 0 or 1.player, originX: number- Left edge (pixels).originX, originY: number- 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).originX, y: numbery: originY: number- Top edge (pixels).originY, width: anywidth: const PANEL_W: anyPANEL_W });
import uiui.panel(player: number- 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.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;
}>
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;
}>
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) => booleanChecks 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.isDown(const code: Array<{
label: string;
code: number;
}>
code, player: number- 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.bootstrap(class DemoCycles keyboard face-button maps with `BT.inputMap` / `BT.inputMapReset`.Demo);