/**
 * Pointer Basics Demo - read mouse position, buttons, delta, and scroll wheel.
 * @description Read mouse position, movement delta, scroll wheel, and four pointer buttons, with a live crosshair.
 *
 * Prerequisites: Basics - https://demos.blit386.dev/basics
 *
 * Live version: https://demos.blit386.dev/pointer-basics
 *
 * This demo is the simplest introduction to BT's pointer API. It draws a
 * crosshair that follows your mouse or finger, lights up indicator pips when you
 * press mouse buttons, and fills a meter that follows the scroll wheel. All the
 * readout panels come from the shared UI kit in src/shared/ui.js; the raw
 * pointer reads (BT.pointerPos, BT.pointerDelta, BT.isDown, and friends) are
 * the lesson and stay hand-written below.
 *
 * Try this:
 * - Move the mouse over the demo to see the crosshair track your cursor (slot 0).
 * - Click left, right, or middle to light up the A, B, or C button pip.
 * - Spin the scroll wheel to fill or empty the scroll meter.
 * - On a touchscreen: tap and drag to move the crosshair on touch slots 1-3
 *   (slot 0 stays reserved for the mouse). Mouse buttons B/C/D and the wheel
 *   have no touch equivalent, so a note appears once a touch is detected.
 *   (See https://demos.blit386.dev/pointer-paint for the full multi-touch paint
 *   version with all four slots.)
 */

import { function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>
One-liner bootstrap function for BLIT386 demos. Handles canvas retrieval and engine initialization. Backend selection (WebGPU or software fallback) is managed internally by BTAPI. This function provides a streamlined way to start a demo with sensible defaults while allowing customization through options.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
,
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
, class 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 */ // Scene palette slots. Index 0 is always transparent. All the UI colors // (panels, text, meter fill) come from the shared theme installed by // applyTheme() in init(), so the demo only needs slots for its own artwork: // the crosshair and the cyan trail behind it. const const C_CROSSHAIR: 1C_CROSSHAIR = 1; // white crosshair that follows the pointer const const C_TRAIL: 2C_TRAIL = 2; // cyan trail line behind the crosshair // Number of past positions remembered for the cursor trail. // Each frame we shift in the latest position and draw a line through them. const const TRAIL_LENGTH: 24TRAIL_LENGTH = 24; // Multiplier applied to the raw scroll delta (BT.pointerScrollDelta) before it // is added to the scroll position. The browser reports scrolling in CSS pixels, // which adds up fast - shrinking each report to a quarter keeps one wheel click // moving the meter a few pixels instead of a big jump. update() then clamps the // scroll position to [0, displayHeight] so the meter fill always stays between // empty and full. const const SCROLL_SENSITIVITY: 0.25SCROLL_SENSITIVITY = 0.25; /** * Demonstrates the basic pointer API: position, delta, scroll wheel, and the * four pointer buttons (A, B, C, D) on slot 0 (the mouse). * * @implements {IBTDemo} */ class class Demo
Demonstrates the basic pointer API: position, delta, scroll wheel, and the four pointer buttons (A, B, C, D) on slot 0 (the mouse).
@implementsIBTDemo
Demo
{
/** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Palette slot map returned by applyTheme() - theme.bg, theme.dim, and so // on. Filled in init(); used for the screen clear and the fallback hint. Demo.theme: nulltheme = null; // Ring-buffer of recent positions (oldest first). We push the current // position each frame and drop the oldest, so the trail shows the cursor's // recent path. Each entry is [x, y]. Demo.trail: {}trail = []; // Accumulated scroll position (in display pixels). Centered in init() from // BT.displaySize. BT.pointerScrollDelta pushes it up or down, and the // scroll meter in the readouts panel shows it as a 0..1 fill. Demo.scrollPos: numberscrollPos = 0; /** * Enables the timing chart so pointer milestones appear on the overlay HUD. * * @returns {Partial<HardwareSettings>} */ Demo.configure(): Partial<HardwareSettings>
Enables the timing chart so pointer milestones appear on the overlay HUD.
@returns
configure
() {
return { // Opt into canvas wheel capture so BT.pointerScrollDelta works and the // page does not scroll while the pointer is over the demo. isCapturingPointerScroll: booleanisCapturingPointerScroll: true, isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true,
overlayTimingChartStyle: {
    updateBarPaletteIndex: number;
    renderBarPaletteIndex: number;
    tagPaletteIndex: number;
}
overlayTimingChartStyle
: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const C_TRAIL: 2C_TRAIL, renderBarPaletteIndex: numberrenderBarPaletteIndex: const C_CROSSHAIR: 1C_CROSSHAIR, tagPaletteIndex: numbertagPaletteIndex: const C_CROSSHAIR: 1C_CROSSHAIR, }, }; } /** * Runs once at startup. Sets up the palette and prefills the trail. * * @returns {Promise<boolean>} */ async Demo.init(): Promise<boolean>
Runs once at startup. Sets up the palette and prefills the trail.
@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);
// Scene colors: just the crosshair and its trail. Everything else on // screen (panels, labels, the meter) is drawn by the shared UI kit. this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_CROSSHAIR: 1C_CROSSHAIR, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(255, 255, 255));
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_TRAIL: 2C_TRAIL, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(80, 200, 255));
// Install the shared UI colors (slots 240-251) and keep the slot map // so we can clear with the theme background and reuse the dim text // color for the "move pointer" hint. this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteSet: (palette: Palette) => void
Stores the active engine palette. Use this to swap the **entire palette** (e.g. switch between a day and night theme). After this call the renderer uploads the new palette uniform on the next frame. **Palette-value swap (change what a slot looks like):** mutate the live {@link BT.palette } in place with `palette.set(slot, newColor)`. The renderer uploads dirty slots on the next frame; no `paletteSet()` or {@link BT.spritesRefresh } needed. **Palette-layout swap (same colors, different slot positions):** build a new palette with the same colors at new indices, call `paletteSet()`, then call {@link BT.spritesRefresh } so every sprite sheet re-maps its original RGBA pixels against the new slot layout.
@since1.0.3@parampalette - Palette to make active.
paletteSet
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
const const screen: Vector2iscreen =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
;
this.Demo.scrollPos: numberscrollPos = Math.floor(const screen: Vector2iscreen.Vector2i.y: number
Vertical component (defaults to 0).
y
/ 2);
// Hide the native OS cursor so the drawn crosshair is the only cursor // visible while the pointer is over the canvas.
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
.hideCursor: () => void
Hides the native OS cursor while the pointer is over the canvas. Call once from `init()` when the demo draws its own crosshair or cursor sprite in place of the system arrow. The cursor is restored automatically when the engine shuts down. No-op before the engine is initialized.
@since1.0.3
hideCursor
();
// Prefill the trail with the center point so the very first frame has // something to draw without a special-case "no history yet" path. for (let let i: numberi = 0; let i: numberi < const TRAIL_LENGTH: 24TRAIL_LENGTH; let i: numberi++) { this.Demo.trail: {}trail.push([Math.floor(const screen: Vector2iscreen.Vector2i.x: number
Horizontal component (defaults to 0).
x
/ 2), Math.floor(const screen: Vector2iscreen.Vector2i.y: number
Vertical component (defaults to 0).
y
/ 2)]);
} return true; } /** * Per-tick update: push the current pointer position into the trail and * apply the scroll-wheel delta to the accumulated scroll position. */ Demo.update(): void
Per-tick update: push the current pointer position into the trail and apply the scroll-wheel delta to the accumulated scroll position.
update
() {
// Let the UI kit do its per-tick housekeeping first. This demo asks // the kit whether a touchscreen has been used (ui.hasTouch() in // render()), and that answer is kept fresh here. import uiui.tick(); // Only record the trail when a pointer is over the canvas. Mouse uses // slot 0; touches use slots 1-3. If none are active, keep the previous // trail intact so the line doesn't snap to (0, 0). const const slot: numberslot = this.Demo.activePointerSlot(): number
First active pointer slot this frame: mouse (0) preferred, then touch (1-3).
@returnsSlot index, or -1 when no pointer is over the canvas.
activePointerSlot
();
if (const slot: numberslot >= 0) { const const pos: Vector2ipos =
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
.pointerPos: (pointerIndex?: number) => Vector2i
Returns the position of the pointer in the given slot, in display coordinates. Slot 0 is the mouse; slots 1 through 3 are touch / pen contacts assigned in arrival order. Returns `Vector2i.zero()` when the engine has not been initialized, the slot index is out of `[0, 3]`, or the slot has no live pointer.
@since1.0.3@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returnsPointer position in display coordinates.
pointerPos
(const slot: numberslot);
// Drop the oldest sample and append the new one. this.Demo.trail: {}trail.shift(); this.Demo.trail: {}trail.push([const pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
, const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
]);
} // Convert scroll delta (pixels of CSS scroll) into a small movement. // Multiplying by a fraction makes one wheel-click move the meter a few // pixels instead of jumping a full screen height. this.Demo.scrollPos: numberscrollPos +=
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
.pointerScrollDelta: number
Wheel scroll delta accumulated during the current frame, in pixels. Aggregates `WheelEvent.deltaY` across all wheel events received since the last frame, normalizing line and page delta modes to pixels. Requires {@link HardwareSettings.isCapturingPointerScroll } (or overlay palette-band force capture); otherwise this stays `0` and the host page scrolls normally.
@since1.0.4@changed1.3.1 Requires `HardwareSettings.isCapturingPointerScroll` (or overlay force); opt-in now, not default.@returnsVertical scroll delta in pixels for the current frame, or `0` when not initialized.
pointerScrollDelta
* const SCROLL_SENSITIVITY: 0.25SCROLL_SENSITIVITY;
// Keep the scroll position inside the visible range (use display height, not a hard-coded 240). const const maxScrollY: numbermaxScrollY =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
.Vector2i.y: number
Vertical component (defaults to 0).
y
;
if (this.Demo.scrollPos: numberscrollPos < 0) { this.Demo.scrollPos: numberscrollPos = 0; } else if (this.Demo.scrollPos: numberscrollPos > const maxScrollY: numbermaxScrollY) { this.Demo.scrollPos: numberscrollPos = const maxScrollY: numbermaxScrollY; } } /** * Per-frame render: clear, draw the UI kit panels (readouts and button * pips), then the cursor trail and the crosshair on top so the "cursor" * is never hidden behind a panel. */ Demo.render(): void
Per-frame render: clear, draw the UI kit panels (readouts and button pips), then the cursor trail and the crosshair on top so the "cursor" is never hidden behind a panel.
render
() {
// Clear to the shared theme background so this demo matches the rest // of the series.
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: nulltheme.bg);
// Full-width title strip with the one-line instructions. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_BAR); import uiui.panel('Pointer Basics - move, click, spin the wheel'); import uiui.end(); this.Demo.renderReadouts(): void
Readouts panel in the top-left: pointer position, delta, wheel delta, whether slot 0 is active, and a meter showing the accumulated scroll position. The raw BT.pointer* reads here are the whole point of the demo - pointer state (unlike keyboard edges) is safe to read from render().
renderReadouts
();
this.Demo.renderButtonPips(): void
Buttons panel in the top-right: four read-only pips, one per pointer button. A pip lights up while its button is held and goes hollow when released. BT.isDown() checks held state, which is safe from render().
renderButtonPips
();
this.Demo.renderTouchNote(): void
A dim one-line note shown only after a touchscreen has been used. Fingers can move the crosshair, but there is no touch equivalent of the scroll wheel or the extra mouse buttons - better to say so than to let touch users hunt for something that cannot happen.
renderTouchNote
();
this.Demo.renderTrail(): void
Polyline through the recent pointer positions, all drawn in uniform C_TRAIL.
renderTrail
();
this.Demo.renderCrosshair(): void
Crosshair drawn at the current pointer position. Only shown while a mouse (slot 0) or touch (slots 1-3) pointer is over the canvas.
renderCrosshair
();
this.Demo.renderPointerHint(): void
"Move pointer over canvas" hint in the middle of the screen. Only shown while no mouse or touch pointer is over the canvas, so newcomers know what to do. Uses the theme's dim text color so it matches the rest of the UI.
renderPointerHint
();
} /** * Readouts panel in the top-left: pointer position, delta, wheel delta, * whether slot 0 is active, and a meter showing the accumulated scroll * position. The raw BT.pointer* reads here are the whole point of the * demo - pointer state (unlike keyboard edges) is safe to read from * render(). */ Demo.renderReadouts(): void
Readouts panel in the top-left: pointer position, delta, wheel delta, whether slot 0 is active, and a meter showing the accumulated scroll position. The raw BT.pointer* reads here are the whole point of the demo - pointer state (unlike keyboard edges) is safe to read from render().
renderReadouts
() {
// Is the pointer currently over the canvas (or a finger touching it)? const const active: booleanactive =
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
.isPointerActive: (pointerIndex?: number) => boolean
Reports whether the given pointer slot has a live pointer. For slot 0 (mouse) this is true while the mouse is hovering inside the canvas; cleared on `pointerleave`. For slots 1-3 (touch / pen) this is true while the contact is down.
@since1.1.1@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returns`true` while the slot has live position data.
isPointerActive
(0);
// How far the wheel moved this frame (positive = scrolling down). const const scroll: numberscroll =
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
.pointerScrollDelta: number
Wheel scroll delta accumulated during the current frame, in pixels. Aggregates `WheelEvent.deltaY` across all wheel events received since the last frame, normalizing line and page delta modes to pixels. Requires {@link HardwareSettings.isCapturingPointerScroll } (or overlay palette-band force capture); otherwise this stays `0` and the host page scrolls normally.
@since1.0.4@changed1.3.1 Requires `HardwareSettings.isCapturingPointerScroll` (or overlay force); opt-in now, not default.@returnsVertical scroll delta in pixels for the current frame, or `0` when not initialized.
pointerScrollDelta
;
// The panel starts below the title strip (y: 28 skips past it). import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { y: numbery: 28 }); import uiui.panel('Slot 0 (mouse)'); import uiui.kv('Active', const active: booleanactive ? 'yes' : 'no'); // Only read position and delta when the pointer is over the canvas. // BT.pointerPos / BT.pointerDelta may hold stale data when not active. if (const active: booleanactive) { const const pos: Vector2ipos =
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
.pointerPos: (pointerIndex?: number) => Vector2i
Returns the position of the pointer in the given slot, in display coordinates. Slot 0 is the mouse; slots 1 through 3 are touch / pen contacts assigned in arrival order. Returns `Vector2i.zero()` when the engine has not been initialized, the slot index is out of `[0, 3]`, or the slot has no live pointer.
@since1.0.3@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returnsPointer position in display coordinates.
pointerPos
(0);
const const delta: Vector2idelta =
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
.pointerDelta: (pointerIndex?: number) => Vector2i
Returns the position delta `(pos - prevPos)` for a pointer slot since the previous frame. Reflects movement accumulated between the previous and current frame. Snapshotted and reset by the engine at `endFrame()`, which runs after `update()` and `render()`. Returns `Vector2i.zero()` when the engine is not initialized or `pointerIndex` is out of range.
@since1.0.3@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returnsPer-frame movement in display coordinates.
pointerDelta
(0);
import uiui.kv('Pos', `${const pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
},${const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
}`);
import uiui.kv('Delta', `${const delta: Vector2idelta.Vector2i.x: number
Horizontal component (defaults to 0).
x
},${const delta: Vector2idelta.Vector2i.y: number
Vertical component (defaults to 0).
y
}`);
} else { import uiui.kv('Pos', '--,--'); import uiui.kv('Delta', '--,--'); } // toFixed(1) turns the number into text with one digit after the // decimal point, so the readout does not jitter through long fractions. import uiui.kv('Wheel', const scroll: numberscroll.toFixed(1)); // The meter fills up as you scroll down and empties as you scroll up. // Dividing by the display height turns 0..240 pixels into the 0..1 // fraction the meter expects. import uiui.meter('Scroll pos', this.Demo.scrollPos: numberscrollPos /
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
.Vector2i.y: number
Vertical component (defaults to 0).
y
);
import uiui.end(); } /** * Buttons panel in the top-right: four read-only pips, one per pointer * button. A pip lights up while its button is held and goes hollow when * released. BT.isDown() checks held state, which is safe from render(). */ Demo.renderButtonPips(): void
Buttons panel in the top-right: four read-only pips, one per pointer button. A pip lights up while its button is held and goes hollow when released. BT.isDown() checks held state, which is safe from render().
renderButtonPips
() {
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_RIGHT, { y: numbery: 28 }); import uiui.panel('Buttons'); // Each pip pairs a label with the live held-state of one button code. import uiui.pip('A (left)',
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 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_POINTER_A: number
Primary pointer button code. Maps to mouse left for slot 0; touch contact for slots 1-3.
@since0.1.0
BTN_POINTER_A
, 0));
import uiui.pip('B (right)',
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 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_POINTER_B: number
Secondary pointer button code. Maps to mouse right for slot 0 (matches RetroBlit canonical, not the DOM `PointerEvent.button` index where 1 is middle and 2 is right). Always `false` for touch slots 1-3.
@since0.1.0
BTN_POINTER_B
, 0));
import uiui.pip('C (middle)',
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 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_POINTER_C: number
Tertiary pointer button code. Maps to mouse middle for slot 0 (matches RetroBlit canonical, not the DOM `PointerEvent.button` index where 1 is middle and 2 is right). Always `false` for touch slots 1-3.
@since0.1.0
BTN_POINTER_C
, 0));
import uiui.pip('D (extra)',
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 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_POINTER_D: number
Auxiliary pointer button code. Maps to mouse back/forward extra buttons (DOM `PointerEvent.button` 3 or 4) for slot 0. Always `false` for touch slots 1-3.
@since1.0.3
BTN_POINTER_D
, 0));
import uiui.end(); } /** * A dim one-line note shown only after a touchscreen has been used. * Fingers can move the crosshair, but there is no touch equivalent of the * scroll wheel or the extra mouse buttons - better to say so than to let * touch users hunt for something that cannot happen. */ Demo.renderTouchNote(): void
A dim one-line note shown only after a touchscreen has been used. Fingers can move the crosshair, but there is no touch equivalent of the scroll wheel or the extra mouse buttons - better to say so than to let touch users hunt for something that cannot happen.
renderTouchNote
() {
if (!import uiui.hasTouch()) { return; } // A borderless group (no ui.panel call) is just floating text. import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_RIGHT); import uiui.label('Scroll wheel and right-click: desktop only', { color: stringcolor: 'dim' }); import uiui.end(); } /** * Polyline through the recent pointer positions, all drawn in uniform C_TRAIL. */ Demo.renderTrail(): void
Polyline through the recent pointer positions, all drawn in uniform C_TRAIL.
renderTrail
() {
if (this.Demo.activePointerSlot(): number
First active pointer slot this frame: mouse (0) preferred, then touch (1-3).
@returnsSlot index, or -1 when no pointer is over the canvas.
activePointerSlot
() < 0) {
return; } for (let let i: numberi = 1; let i: numberi < this.Demo.trail: {}trail.length; let i: numberi++) { const [const ax: anyax, const ay: anyay] = this.Demo.trail: {}trail[let i: numberi - 1]; const [const bx: anybx, const by: anyby] = this.Demo.trail: {}trail[let i: numberi];
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(const ax: anyax, const ay: anyay), 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 bx: anybx, const by: anyby), const C_TRAIL: 2C_TRAIL);
} } /** * Crosshair drawn at the current pointer position. Only shown while a * mouse (slot 0) or touch (slots 1-3) pointer is over the canvas. */ Demo.renderCrosshair(): void
Crosshair drawn at the current pointer position. Only shown while a mouse (slot 0) or touch (slots 1-3) pointer is over the canvas.
renderCrosshair
() {
const const slot: numberslot = this.Demo.activePointerSlot(): number
First active pointer slot this frame: mouse (0) preferred, then touch (1-3).
@returnsSlot index, or -1 when no pointer is over the canvas.
activePointerSlot
();
if (const slot: numberslot < 0) { return; } const const pos: Vector2ipos =
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
.pointerPos: (pointerIndex?: number) => Vector2i
Returns the position of the pointer in the given slot, in display coordinates. Slot 0 is the mouse; slots 1 through 3 are touch / pen contacts assigned in arrival order. Returns `Vector2i.zero()` when the engine has not been initialized, the slot index is out of `[0, 3]`, or the slot has no live pointer.
@since1.0.3@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returnsPointer position in display coordinates.
pointerPos
(const slot: numberslot);
const const size: 6size = 6; // Horizontal arm.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(const pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
- const size: 6size, const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
), 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 pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
+ const size: 6size, const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
), const C_CROSSHAIR: 1C_CROSSHAIR);
// Vertical arm.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(new new Vector2i(x?: number, y?: number): Vector2i
Creates an integer 2D vector, truncating inputs toward zero.
@paramx - Horizontal component (defaults to 0).@paramy - Vertical component (defaults to 0).
Vector2i
(const pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
, const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
- const size: 6size), 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 pos: Vector2ipos.Vector2i.x: number
Horizontal component (defaults to 0).
x
, const pos: Vector2ipos.Vector2i.y: number
Vertical component (defaults to 0).
y
+ const size: 6size), const C_CROSSHAIR: 1C_CROSSHAIR);
// Center dot.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawPixel: (posOrX: Vector2i | number, yOrColor: number, maybeColor?: number) => void
Draws a single pixel. Accepts either: - `(posOrX: Vector2i, yOrColor: number)` where `yOrColor` is the palette index. - `(posOrX: number, yOrColor: number, maybeColor: number)` for `(x, y, paletteIndex)`.
@since0.1.0@paramposOrX - Pixel position as `Vector2i`, or x coordinate when using numeric overload.@paramyOrColor - Palette index for vector overload, or y coordinate for numeric overload.@parammaybeColor - Palette index when using numeric overload.
drawPixel
(const pos: Vector2ipos, const C_CROSSHAIR: 1C_CROSSHAIR);
} /** * "Move pointer over canvas" hint in the middle of the screen. Only shown * while no mouse or touch pointer is over the canvas, so newcomers know what * to do. Uses the theme's dim text color so it matches the rest of the UI. */ Demo.renderPointerHint(): void
"Move pointer over canvas" hint in the middle of the screen. Only shown while no mouse or touch pointer is over the canvas, so newcomers know what to do. Uses the theme's dim text color so it matches the rest of the UI.
renderPointerHint
() {
if (this.Demo.activePointerSlot(): number
First active pointer slot this frame: mouse (0) preferred, then touch (1-3).
@returnsSlot index, or -1 when no pointer is over the canvas.
activePointerSlot
() >= 0) {
return; } // `screen` holds the full display size; halving it below finds the // middle, and the small offsets nudge the text so its center (not its // top-left corner) sits on that middle point. const const screen: Vector2iscreen =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 106 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.displaySize: Vector2i
Active logical render resolution in pixels. This is the game/simulation coordinate space configured by the demo, not the canvas element's CSS size. Each read returns a clone.
@since1.0.4@returnsConfigured logical size, or `Vector2i.zero()` before initialization.
displaySize
;
const 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
.systemPrint: (pos: Vector2i, paletteIndex: number, text: string) => void
Draws text using the built-in 6x14 system font. The system font covers printable ASCII (characters 32-126). For custom bitmap fonts with proportional glyphs, use {@link BT.printFont } instead.
@since1.0.3@parampos - Text origin in display coordinates.@parampaletteIndex - Palette color index for the text.@paramtext - String to render.
systemPrint
(
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
(Math.floor(const screen: Vector2iscreen.Vector2i.x: number
Horizontal component (defaults to 0).
x
/ 2) - 60, Math.floor(const screen: Vector2iscreen.Vector2i.y: number
Vertical component (defaults to 0).
y
/ 2) - 7),
this.Demo.theme: nulltheme.dim, 'Move pointer over canvas', ); // The engine overlay (FPS + demo name) draws on top automatically. } /** * First active pointer slot this frame: mouse (0) preferred, then touch (1-3). * * @returns {number} Slot index, or -1 when no pointer is over the canvas. */ Demo.activePointerSlot(): number
First active pointer slot this frame: mouse (0) preferred, then touch (1-3).
@returnsSlot index, or -1 when no pointer is over the canvas.
activePointerSlot
() {
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
.isPointerActive: (pointerIndex?: number) => boolean
Reports whether the given pointer slot has a live pointer. For slot 0 (mouse) this is true while the mouse is hovering inside the canvas; cleared on `pointerleave`. For slots 1-3 (touch / pen) this is true while the contact is down.
@since1.1.1@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returns`true` while the slot has live position data.
isPointerActive
(0)) {
return 0; } for (let let slot: numberslot = 1; let slot: numberslot < 4; let slot: numberslot++) { 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
.isPointerActive: (pointerIndex?: number) => boolean
Reports whether the given pointer slot has a live pointer. For slot 0 (mouse) this is true while the mouse is hovering inside the canvas; cleared on `pointerleave`. For slots 1-3 (touch / pen) this is true while the contact is down.
@since1.1.1@parampointerIndex - Pointer slot (defaults to 0 = mouse).@returns`true` while the slot has live position data.
isPointerActive
(let slot: numberslot)) {
return let slot: numberslot; } } return -1; } } 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
Demonstrates the basic pointer API: position, delta, scroll wheel, and the four pointer buttons (A, B, C, D) on slot 0 (the mouse).
@implementsIBTDemo
Demo
);