/*

Bitmap Font: load a .btfont file and compare it to the built-in system font.
@description Load a .btfont bitmap font and draw rainbow, alpha-pulsing, and measured text with it.

Part of the BLIT386 demo series.

Prerequisites:
  - Basics: https://demos.blit386.dev/basics
  - Colors: https://demos.blit386.dev/colors
  - Fonts: https://demos.blit386.dev/fonts

Live version: https://demos.blit386.dev/bitmap-font

Guides:
  - Bitmap Fonts: https://blit386.dev/docs/guides/bitmap-fonts#custom-bitmap-fonts-btfont
  - Palette: https://blit386.dev/docs/guides/palette#per-draw-palette-offsets-zero-cost-color-variants

Reference:
  - Assets: https://blit386.dev/docs/api/assets#bitmap-fonts
  - Rendering: https://blit386.dev/docs/api/rendering#bitmap-fonts
  - Core Types: https://blit386.dev/docs/api/core-types#color32

---

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

A dark screen with a column of text down the left side. The first two lines are the same
title drawn twice: "A:" marks the loaded .btfont (PragmataPro at 14 pt), "B:" marks the
built-in 6x14 system font, so you can compare the two shapes directly. Below them come
four lines in red, green, blue, and yellow, then "Rainbow Animation!" with every letter in
its own color and the colors sliding left over time, then "Pulsing Text" fading in and out
three times a second, then "Special: 3 × 4 = 12" using a real multiplication sign, and
finally "Measured Width" in light gray with an orange underline exactly as wide as the
text.

A small "Font Info" panel in the bottom-right corner lists the font's name, point size,
and glyph count, read straight from the loaded font object.

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

- BitmapFont.load(url) downloads a .btfont file - a JSON glyph table plus a PNG atlas -
  and init() awaits it before the demo loop starts.
- font.getSpriteSheet().indexize(palette) must run before the first draw: the atlas holds
  white pixels, and indexize swaps each one for the palette slot that holds white (slot 1
  here).
- BT.printFont(font, pos, text, paletteOffset) adds the offset to every glyph pixel's
  slot, so offset 0 draws slot 1, offset 2 draws slot 3, and so on. BT.systemPrint(pos,
  slot, text) takes the slot number directly instead.
- font.getGlyph(char).advance says how far to step right after a character. PragmataPro is
  monospaced, so every glyph here advances 7 pixels; a proportional font would return a
  different advance per letter, and the same loop would still work.
- font.measureText(text) returns the pixel width of a string before you draw it. The
  system font has the same idea in BT.systemPrintMeasure(text).
- font.name, font.size, font.lineHeight, and font.glyphCount describe the loaded font.
- Text color animates by rewriting palette slots in update() - Color32.fromHSL() for the
  rainbow, an alpha value for the pulse - while render() keeps passing the same offsets.

WHY LOAD A FONT AT ALL?
-----------------------

A bitmap font is a font where every letter is a small pre-drawn picture, not a set of
curves. That is what gives pixel-art text its crisp look. The built-in system font is one
too, and BT.systemPrint() needs no file, which makes it the right pick for quick labels
and debug readouts.

Load a .btfont instead when you want a different size or style, a glyph set you choose
yourself, or proportional spacing. The loading step is the only extra cost: one await in
init(), and a short wait before the first frame.

*/

import { 
type BitmapFont = BitmapFont
class BitmapFont
Bitmap font backed by a sprite-sheet texture atlas. The class is responsible for: - loading `.btfont` metadata and its referenced texture - exposing glyph lookup by character or character code - measuring string widths with a small reusable cache - providing the underlying {@link SpriteSheet } used for rendering glyph quads
@since0.1.0@changed1.5.0 `getGlyph` / `getGlyphByCode` (and `measureText`, which now shares their lookup) substitute a font-defined fallback glyph for a missing character instead of returning `null`, when the font's glyph map has an entry keyed by `U+FFFD`.@changed1.7.0 Added the `codePoints` getter, returning every Unicode code point the font defines a glyph for (ascending, derived live from the same glyph map `getGlyph()` and `hasGlyph()` read).
BitmapFont
, function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>
One-liner bootstrap function for BLIT386 demos. Handles canvas retrieval and engine initialization. Backend selection (WebGPU or software fallback) is managed internally by BTAPI. This function provides a streamlined way to start a demo with sensible defaults while allowing customization through options.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
,
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
, class 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').Palette} Palette */ /** @typedef {import('blit386').BitmapFont} BitmapFont */ // The x position where the rainbow text row starts. update() (hue calculation) and // renderRainbowText() (glyph drawing) both use it so the two stay in sync. const const RAINBOW_ORIGIN_X: 10RAINBOW_ORIGIN_X = 10; // Every color used for drawing lives in a numbered palette slot. Slot 0 is always // transparent, so custom colors start at 1. The screen background and the Font Info panel // use the shared UI theme instead (installed by applyTheme() in init()), so there are no // background slots here. Slot 2 is simply left unused. const const C_WHITE: 1C_WHITE = 1; // pure white: title, special characters, 'A' / 'B' labels const const C_RED_TEXT: 3C_RED_TEXT = 3; // soft red: "Red Text" sample line const const C_GREEN_TEXT: 4C_GREEN_TEXT = 4; // soft green: "Green Text" sample line const const C_BLUE_TEXT: 5C_BLUE_TEXT = 5; // soft blue: "Blue Text" sample line const const C_YELLOW_TEXT: 6C_YELLOW_TEXT = 6; // yellow: "Yellow Text" sample line const const C_GRAY_TEXT: 7C_GRAY_TEXT = 7; // light gray: "Measured Width" text const const C_ORANGE_LINE: 8C_ORANGE_LINE = 8; // orange: underline below the measured-width text // The rainbow text string comes before the slot constants that depend on it, so C_PULSE // can be derived from its length. Change the string and update() computes the right // number of palette colors automatically. const const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT = 'Rainbow Animation!'; // Dynamic slots: each character in RAINBOW_TEXT gets its own animated color slot, // starting at C_RAINBOW_BASE. update() computes each character's current hue and stores // it there; render() only passes the slot offset, so no Color32 math happens while // drawing. const const C_RAINBOW_BASE: 20C_RAINBOW_BASE = 20; // first slot for the rainbow characters // Dynamic slot for the pulsing-text color. It sits right after the rainbow slots, so it // can never overlap them even if RAINBOW_TEXT changes length (20 + 18 = slot 38 today). const const C_PULSE: anyC_PULSE = const C_RAINBOW_BASE: 20C_RAINBOW_BASE + const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT.length; // Left margin for the "A: " / "B: " labels and the sample text below them. const const LABEL_X: 10LABEL_X = 10; // Loads a bitmap font and draws text with it in several ways: static colors, an animated // rainbow, alpha pulsing, text measurement, and a font metadata panel. Compare it with // BT.systemPrint() in the Fonts demo. class class DemoDemo { // The loaded bitmap font. Starts as null because nothing is loaded yet. /** @type {BitmapFont | null} */ Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
= null;
// All the colors this demo uses. /** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
// Palette slot numbers of the shared UI kit colors, filled in by applyTheme() in // init(). theme.bg clears the screen so this demo's background matches the rest of // the series. Demo.theme: nulltheme = null; // A timer that counts up in seconds. It drives the speed of the color animations. Demo.animTime: numberanimTime = 0; // Size of one system-font glyph, measured in init() with BT.systemPrintMeasure('M'). // The built-in font is 6x14, but measuring keeps the demo honest if that ever // changes. Demo.systemCharWidth: numbersystemCharWidth = 6; Demo.systemLineHeight: numbersystemLineHeight = 14; // Pixel width of the "A: " prefix, so the title text lines up after the label. Demo.labelPrefixWidth: numberlabelPrefixWidth = 18; // Sets up the palette and downloads the bitmap font. Screen size and FPS come from // the engine's defaultConfig(), since this demo has no configure(). Returns true when // the font loaded and false when it did not - the engine only starts the demo loop on // true. async Demo.init(): unknowninit() { console.log('[BitmapFontDemo] Initializing...'); // Set up the color palette. Every color is picked before anything is drawn, like // an artist mixing paint first. this.Demo.palette: Palette | null
@type{Palette | null}
palette
=
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteCreate: (size?: number) => Palette
Creates a standalone palette instance.
@since1.0.3@paramsize - Palette size. Defaults to 256 colors.@returnsNew mutable palette.
paletteCreate
(256);
// Static colors that never change from frame to frame. this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_WHITE: 1C_WHITE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(255, 255, 255)); // pure white
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_RED_TEXT: 3C_RED_TEXT, 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, 100, 100)); // soft red
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_GREEN_TEXT: 4C_GREEN_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(100, 255, 100)); // soft green
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_BLUE_TEXT: 5C_BLUE_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(100, 100, 255)); // soft blue
this.Demo.palette: Palette
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_YELLOW_TEXT: 6C_YELLOW_TEXT, 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, 100)); // yellow
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_GRAY_TEXT: 7C_GRAY_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(200, 200, 200)); // light gray
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_ORANGE_LINE: 8C_ORANGE_LINE, 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, 200, 100)); // orange underline
// Pre-fill the dynamic rainbow slots with gray so they are not empty on the first // frame. for (let let i: numberi = 0; let i: numberi < const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT.length; let i: numberi++) { 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_RAINBOW_BASE: 20C_RAINBOW_BASE + let i: numberi, 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
(128, 128, 128));
} // Pre-fill the pulse slot too. 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_PULSE: anyC_PULSE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(100, 100, 255));
// Install the shared UI kit colors. They land in slots 240-251, well above this // demo's highest slot (C_PULSE = 38), so the two can never collide. The returned // map remembers which slot each UI color went to (theme.bg, theme.text, ...). this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Tell the engine to use this palette for all drawing.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.paletteSet: (palette: Palette) => void
Stores the active engine palette. Use this to swap the **entire palette** (e.g. switch between a day and night theme). After this call the renderer uploads the new palette uniform on the next frame. **Palette-value swap (change what a slot looks like):** mutate the live {@link BT.palette } in place with `palette.set(slot, newColor)`. The renderer uploads dirty slots on the next frame; no `paletteSet()` or {@link BT.spritesRefresh } needed. **Palette-layout swap (same colors, different slot positions):** build a new palette with the same colors at new indices, call `paletteSet()`, then call {@link BT.spritesRefresh } so every sprite sheet re-maps its original RGBA pixels against the new slot layout.
@since1.0.3@parampalette - Palette to make active.
paletteSet
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
// Measure the built-in system font once, the same way the Fonts demo does. const const glyphSize: Vector2iglyphSize =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.systemPrintMeasure: (text: string) => Vector2i
Measures the pixel dimensions of a string rendered with the built-in system font.
@since1.0.3@paramtext - Text string to measure.@returnsWidth and height in pixels, or `Vector2i.zero()` before engine initialization.
systemPrintMeasure
('M');
this.Demo.systemCharWidth: numbersystemCharWidth = const glyphSize: Vector2iglyphSize.Vector2i.x: number
Horizontal component (defaults to 0).
x
;
this.Demo.systemLineHeight: numbersystemLineHeight = const glyphSize: Vector2iglyphSize.Vector2i.y: number
Vertical component (defaults to 0).
y
;
this.Demo.labelPrefixWidth: numberlabelPrefixWidth =
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.systemPrintMeasure: (text: string) => Vector2i
Measures the pixel dimensions of a string rendered with the built-in system font.
@since1.0.3@paramtext - Text string to measure.@returnsWidth and height in pixels, or `Vector2i.zero()` before engine initialization.
systemPrintMeasure
('A: ').Vector2i.x: number
Horizontal component (defaults to 0).
x
;
// Load the font file from the server. A .btfont is a JSON glyph table next to a // PNG atlas of the glyph images. This is the step BT.systemPrint() skips - the // system font is built in. `await` pauses here until the download finishes. try { this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
= await class BitmapFont
Bitmap font backed by a sprite-sheet texture atlas. The class is responsible for: - loading `.btfont` metadata and its referenced texture - exposing glyph lookup by character or character code - measuring string widths with a small reusable cache - providing the underlying {@link SpriteSheet } used for rendering glyph quads
@since0.1.0@changed1.5.0 `getGlyph` / `getGlyphByCode` (and `measureText`, which now shares their lookup) substitute a font-defined fallback glyph for a missing character instead of returning `null`, when the font's glyph map has an entry keyed by `U+FFFD`.@changed1.7.0 Added the `codePoints` getter, returning every Unicode code point the font defines a glyph for (ascending, derived live from the same glyph map `getGlyph()` and `hasGlyph()` read).
BitmapFont
.BitmapFont.load(url: string): Promise<BitmapFont>
Loads a bitmap font from a `.btfont` JSON file. The font descriptor can reference either an embedded PNG data URI (`data:image/png;base64,...`) or a texture file path relative to the font JSON file.
@paramurl - Path to the .btfont file.@returnsLoaded bitmap font instance.@throwsError if the font descriptor or texture cannot be loaded.
load
('/fonts/PragmataPro14.btfont');
// The font object exposes metadata you can read and display. console.log(`[BitmapFontDemo] Loaded font: ${this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.name: string
Font display name.
name
}`);
console.log(` Size: ${this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.size: number
Original font size in points.
size
}pt`);
console.log(` Line height: ${this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.lineHeight: number
Pixels between baselines for multi-line text.
lineHeight
}px`);
console.log(` Glyphs: ${this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.glyphCount: number
Returns the total number of glyphs loaded into the font.
@returnsTotal glyph count.
glyphCount
}`);
} catch (function (local var) error: unknownerror) { console.error('[BitmapFontDemo] Failed to load font:', function (local var) error: unknownerror); return false; } // Tell the font about the palette. Glyphs are stored as white pixels in the // font's sprite sheet; indexize() replaces each one with the slot that holds // white, C_WHITE (1). After this call BT.printFont() can recolor the glyphs by // shifting that index. this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.getSpriteSheet(): SpriteSheet
Returns the sprite sheet that owns the font texture atlas.
@returnsSprite sheet used when rendering glyph quads.
getSpriteSheet
().SpriteSheet.indexize(palette: Palette): void
Converts the sprite sheet's RGBA pixels to palette indices. Each non-transparent pixel is looked up in the provided palette via exact color matching. Index 0 is always transparent. The resulting indices are stored internally; an `r8uint` GPU texture is created lazily on the next `getTexture()` call. The original RGBA data is retained so `reindexize()` can re-convert after a palette swap without reloading the image.
@parampalette - Active palette used for color-to-index mapping.@throwsIf any opaque pixel's color is not present in the palette.
indexize
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
console.log('[BitmapFontDemo] Font loaded successfully!'); return true; } // Runs at a fixed rate (60 times per second, as the Basics demo explains). Advances // the animation timer and rewrites the dynamic palette colors. Demo.update(): voidupdate() { // Move the animation clock forward by one fixed update step, in seconds. this.Demo.animTime: numberanimTime +=
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.deltaSeconds: number
Fixed-step seconds per update tick. Equivalent to `1 / BT.targetFPS` when `BT.targetFPS` is finite and positive. Falls back to `1 / 60` when target FPS is non-finite or non-positive.
@since1.0.4@returnsSeconds advanced by one fixed update tick.
deltaSeconds
;
// The pulse: Math.sin returns a wave that swings smoothly between -1 and +1. The // "2 * Math.PI * frequency" part converts seconds into radians, which is what // Math.sin expects; with frequency 3 the wave completes three full cycles per // second. Multiplying by 0.5 and adding 0.5 moves the output from [-1, 1] to [0, // 1]. const const pulse: numberpulse = Math.sin(2 * Math.PI * 3 * this.Demo.animTime: numberanimTime) * 0.5 + 0.5; // The alpha channel controls how opaque the text is. At pulse 0 the text // disappears; at pulse 1 it is solid. RGB stays fixed at (100, 100, 255), a // medium blue, so only the opacity changes. this.Demo.palette: Palette | null
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_PULSE: anyC_PULSE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32
Creates a clamped 8-bit RGBA color.
@paramr - Red channel (0-255, defaults to 255).@paramg - Green channel (0-255, defaults to 255).@paramb - Blue channel (0-255, defaults to 255).@parama - Alpha channel (0-255, defaults to 255 = opaque).
Color32
(100, 100, 255, Math.floor(const pulse: numberpulse * 255)));
// The rainbow: compute a hue (a position on the color wheel) for each character // from its x position and animTime. The font is always loaded here, because the // demo loop only starts after init() returned true. HSL colors were introduced in // the Colors demo: https://demos.blit386.dev/colors let let charX: numbercharX = const RAINBOW_ORIGIN_X: 10RAINBOW_ORIGIN_X; // same x where render() draws the rainbow text for (let let i: numberi = 0; let i: numberi < const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT.length; let i: numberi++) { // hue is a position on the color wheel: 0 is red, 120 green, 240 blue, 360 // back to red. Using the character's real x position gives the rainbow its // spacing; adding animTime * 100 scrolls it left over time. `%` is the // remainder after division, so `% 360` keeps hue in 0-359 and the wheel // cycles instead of growing forever. const const hue: numberhue = (let charX: numbercharX * 3 + this.Demo.animTime: numberanimTime * 100) % 360; this.Demo.palette: Palette | null
@type{Palette | null}
palette
.Palette.set(index: number, color: Color32): void
Writes a color into a palette slot.
@paramindex - Palette index to overwrite.@paramcolor - Color to store.@throwsError if the index is invalid or if index `0` is set opaque.
set
(const C_RAINBOW_BASE: 20C_RAINBOW_BASE + let i: numberi, class Color32
Mutable 32-bit RGBA color value with 8-bit channels.
@since0.1.0
Color32
.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32
Creates a color from HSL values.
@paramh - Hue in degrees (0-360).@params - Saturation as percentage (0-100).@paraml - Lightness as percentage (0-100).@parama - Alpha channel (0-255, defaults to 255).@returnsNew color converted from HSL values.
fromHSL
(const hue: numberhue, 100, 60));
// Step charX by this character's advance from the font. PragmataPro is // monospaced, so this is always 7 here; a proportional font would vary. const const glyph: Glyph | nullglyph = this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.getGlyph(char: string): Glyph | null
Returns glyph data for a character. Uses the ASCII lookup table for single-byte characters and falls back to the Unicode glyph map for everything else, then to the font's fallback glyph (see {@link FALLBACK_GLYPH_CHAR } ) when neither has an entry for the character.
@paramchar - Single character to look up (supports Unicode).@returnsGlyph metadata; the font's fallback glyph when the character is missing and a fallback is defined; otherwise `null`.
getGlyph
(const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT[let i: numberi]);
let charX: numbercharX += const glyph: Glyph | nullglyph ? const glyph: Glyphglyph.Glyph.advance: number
Horizontal advance after drawing (distance to next character).
advance
: 7;
} } // Runs once per screen refresh and draws every text sample. Demo.render(): voidrender() { // Fill the screen with the shared UI theme's deep navy background.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.clear: (paletteIndex: number) => void
Sets the frame clear color using a palette index. The renderer uses this color when clearing the full display at the start of the next frame.
@since0.1.0@parampaletteIndex - Palette index for the full-screen clear pass.
clear
(this.Demo.theme: nulltheme.bg);
// Start drawing near the top of the screen. let let y: numbery = 10; // Where the title text starts after the "A: " / "B: " labels (measured in // init()). const const textX: numbertextX = const LABEL_X: 10LABEL_X + this.Demo.labelPrefixWidth: numberlabelPrefixWidth; // How many pixels tall one line of text is, plus a little breathing room. The // bitmap font's line height comes from the .btfont file; the system font's was // measured. const const bitmapLineHeight: numberbitmapLineHeight = this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.lineHeight: number
Pixels between baselines for multi-line text.
lineHeight
+ 2;
const const systemLineHeight: numbersystemLineHeight = this.Demo.systemLineHeight: numbersystemLineHeight + 2; // BT.printFont() takes (font, position, text, paletteOffset). The offset is added // to the slot the glyph pixels were indexized to (slot 1), so offset 0 draws slot // 1 (C_WHITE), offset 2 draws slot 3 (C_RED_TEXT), and so on. BT.systemPrint() // takes the palette slot number directly instead. // Draw the title in both fonts, one below the other. "A:" marks the bitmap font // (7 pixels per character at 14 pt), "B:" the built-in system font (a fixed 6x14 // block per character).
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.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
(const LABEL_X: 10LABEL_X, let y: numbery), const C_WHITE: 1C_WHITE, 'A:');
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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 textX: numbertextX, let y: numbery), 'BLIT386 Bitmap Font Demo', 0);
let y: numbery += const bitmapLineHeight: numberbitmapLineHeight; // The same title in the system font, so the difference is easy to see.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.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
(const LABEL_X: 10LABEL_X, let y: numbery), const C_WHITE: 1C_WHITE, 'B:');
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.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
(const textX: numbertextX, let y: numbery), const C_WHITE: 1C_WHITE, 'BLIT386 Bitmap Font Demo');
// Move down past both title lines, with a little extra gap before the next // section. let y: numbery += const systemLineHeight: numbersystemLineHeight + 4; // Draw each section in order, updating y as we go so nothing overlaps. let y: numbery = this.Demo.renderColoredText(y: any, lineHeight: any): anyrenderColoredText(let y: numbery, const bitmapLineHeight: numberbitmapLineHeight); let y: numbery = this.Demo.renderRainbowText(y: any, lineHeight: any): anyrenderRainbowText(let y: numbery, const bitmapLineHeight: numberbitmapLineHeight); let y: numbery = this.Demo.renderPulsingText(y: any, lineHeight: any): anyrenderPulsingText(let y: numbery, const bitmapLineHeight: numberbitmapLineHeight); let y: numbery = this.Demo.renderSpecialCharacters(y: any, lineHeight: any): anyrenderSpecialCharacters(let y: numbery, const bitmapLineHeight: numberbitmapLineHeight); this.Demo.renderTextMeasurement(y: any, lineHeight: any): anyrenderTextMeasurement(let y: numbery, const bitmapLineHeight: numberbitmapLineHeight); // The font metadata panel in the bottom-right corner. FPS and the demo title are // drawn by the engine overlay, not here. this.Demo.renderFontInfo(): voidrenderFontInfo(); } // Draws four sample lines, each in a different color, to show how the palette offset // picks the color. `y` is where the first line starts and `lineHeight` how far to // move down between lines. Returns the y position after the last line. Demo.renderColoredText(y: any, lineHeight: any): anyrenderColoredText(y: anyy, lineHeight: anylineHeight) { // A local copy, so the parameter itself is never modified - readers expect a // parameter to keep its value throughout the function. let let currentY: anycurrentY = y: anyy; // Each color is reached by offset: slot = 1 + offset, so offset = slot - 1. For // C_RED_TEXT (slot 3) that is offset 2. With BT.systemPrint() you would simply // pass C_RED_TEXT.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, let currentY: anycurrentY), 'Red Text', const C_RED_TEXT: 3C_RED_TEXT - 1);
let currentY: anycurrentY += lineHeight: anylineHeight;
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, let currentY: anycurrentY), 'Green Text', const C_GREEN_TEXT: 4C_GREEN_TEXT - 1);
let currentY: anycurrentY += lineHeight: anylineHeight;
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, let currentY: anycurrentY), 'Blue Text', const C_BLUE_TEXT: 5C_BLUE_TEXT - 1);
let currentY: anycurrentY += lineHeight: anylineHeight;
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, let currentY: anycurrentY), 'Yellow Text', const C_YELLOW_TEXT: 6C_YELLOW_TEXT - 1);
// Extra space after this section. let currentY: anycurrentY += lineHeight: anylineHeight + 4; return let currentY: anycurrentY; } // Draws text where every character has its own color, pre-computed in update() and // stored in slots C_RAINBOW_BASE + i. Drawing one character per BT.printFont() call // lets each glyph take a different palette offset. Returns the y position after the // text. Demo.renderRainbowText(y: any, lineHeight: any): anyrenderRainbowText(y: anyy, lineHeight: anylineHeight) { // Start at the left margin (must match RAINBOW_ORIGIN_X used in update()). let let x: numberx = const RAINBOW_ORIGIN_X: 10RAINBOW_ORIGIN_X; let let slotIndex: numberslotIndex = 0; // Loop through the string one character at a time. for (const const char: anychar of const RAINBOW_TEXT: "Rainbow Animation!"RAINBOW_TEXT) { // The offset for character i is C_RAINBOW_BASE + i - 1, because offset N // draws slot 1 + N and we want slot C_RAINBOW_BASE + i.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(let x: numberx, y: anyy), const char: anychar, const C_RAINBOW_BASE: 20C_RAINBOW_BASE - 1 + let slotIndex: numberslotIndex);
// Look up how wide this character is. "advance" is how many pixels to move // right before drawing the next one - 7 for every glyph in this monospaced // font, but a proportional font would give each letter its own value. The // system font always advances systemCharWidth (6). const const glyph: Glyph | nullglyph = this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.getGlyph(char: string): Glyph | null
Returns glyph data for a character. Uses the ASCII lookup table for single-byte characters and falls back to the Unicode glyph map for everything else, then to the font's fallback glyph (see {@link FALLBACK_GLYPH_CHAR } ) when neither has an entry for the character.
@paramchar - Single character to look up (supports Unicode).@returnsGlyph metadata; the font's fallback glyph when the character is missing and a fallback is defined; otherwise `null`.
getGlyph
(const char: anychar);
// If the glyph exists use its advance, otherwise fall back to 7 pixels. let x: numberx += const glyph: Glyph | nullglyph ? const glyph: Glyphglyph.Glyph.advance: number
Horizontal advance after drawing (distance to next character).
advance
: 7;
let slotIndex: numberslotIndex++; } return y: anyy + lineHeight: anylineHeight + 4; } // Draws text that fades in and out. The alpha was pre-computed in update() with // Math.sin and stored in slot C_PULSE; the same palette trick works with // BT.systemPrint(). Returns the y position after the text. Demo.renderPulsingText(y: any, lineHeight: any): anyrenderPulsingText(y: anyy, lineHeight: anylineHeight) { // C_PULSE - 1 = 37, so the glyphs draw slot 1 + 37 = 38, the animated 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;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, y: anyy), 'Pulsing Text', const C_PULSE: anyC_PULSE - 1);
return y: anyy + lineHeight: anylineHeight + 4; } // Shows that the font can draw characters outside plain ASCII. Returns the y position // after the text. Demo.renderSpecialCharacters(y: any, lineHeight: any): anyrenderSpecialCharacters(y: anyy, lineHeight: anylineHeight) { // Offset 0 draws slot 1 (C_WHITE). '\u00D7' is the Unicode multiplication sign // (×), a non-ASCII character, so this line only shows the sign if the // .btfont includes a glyph for it.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, y: anyy), 'Special: 3 \u00D7 4 = 12', 0);
return y: anyy + lineHeight: anylineHeight; } // Shows font.measureText(): the exact pixel width of a string before you draw it. The // width is used for an underline that ends exactly under the last letter. The system // font has the same idea in BT.systemPrintMeasure(). Returns the y position after the // text and underline. Demo.renderTextMeasurement(y: any, lineHeight: any): anyrenderTextMeasurement(y: anyy, lineHeight: anylineHeight) { const const measureText: "Measured Width"measureText = 'Measured Width'; // Ask the font how many pixels wide this string will be. const const textWidth: numbertextWidth = this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.measureText(text: string): number
Measures the horizontal pixel width of a text string. Results are cached for repeated measurements. Iterates by Unicode code point (`for...of`), not by UTF-16 code unit, so an astral character (a surrogate pair) is measured as the single glyph it is instead of two lone-surrogate lookups. Glyph resolution (including the ASCII fast path and fallback-glyph substitution) goes through {@link getGlyph } , so a measured width always matches what actually renders.
@paramtext - String to measure.@returnsTotal width in pixels.
measureText
(const measureText: "Measured Width"measureText);
// Draw the text in light gray: C_GRAY_TEXT - 1 = 6, so the glyphs draw slot 7.
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.printFont: (font: BitmapFont, pos: Vector2i, text: string, paletteOffset?: number) => void
Draws text with a bitmap font through the indexed sprite pipeline. Supports proportional glyph widths and glyph-level offsets defined by the supplied {@link BitmapFont } . The font's underlying sprite sheet must have been indexized before calling this. Palette offset semantics and out-of-range behavior are identical to {@link BT.drawSprite } .
@since0.1.0@paramfont - Font asset used for rendering.@parampos - Text origin in display coordinates.@paramtext - String to render.@parampaletteOffset - Shift added to every stored glyph index before palette lookup (default 0).
printFont
(this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
, 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
(10, y: anyy), const measureText: "Measured Width"measureText, const C_GRAY_TEXT: 7C_GRAY_TEXT - 1);
// Draw an orange underline exactly as wide as the measured text, 2 pixels above // the bottom of the line. BT.drawLine() takes a start point, an end point, and a // palette slot number (not an offset).
const BT: {
    FLIP_H: number;
    FLIP_V: number;
    ROT_90_CW: number;
    ROT_180_CW: number;
    ROT_270_CW: number;
    BTN_UP: number;
    BTN_DOWN: number;
    BTN_LEFT: number;
    BTN_RIGHT: number;
    BTN_A: number;
    BTN_B: number;
    BTN_X: number;
    BTN_Y: number;
    BTN_L: number;
    BTN_R: number;
    BTN_START: number;
    BTN_SELECT: number;
    BTN_POINTER_A: number;
    BTN_POINTER_B: number;
    BTN_POINTER_C: number;
    BTN_POINTER_D: number;
    PLAYER_ONE: number;
    PLAYER_TWO: number;
    PLAYER_THREE: number;
    PLAYER_FOUR: number;
    AXIS_LEFT_X: number;
    AXIS_LEFT_Y: number;
    AXIS_RIGHT_X: number;
    AXIS_RIGHT_Y: number;
    AXIS_TRIGGER_L: number;
    ... 124 more ...;
    spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.
BT
.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => void
Draws a pixel-perfect line between two points. Uses rasterized line drawing without antialiasing.
@since0.1.0@paramp0 - Start position in display coordinates.@paramp1 - End position in display coordinates.@parampaletteIndex - Palette color index.
drawLine
(
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
(10, y: anyy + lineHeight: anylineHeight - 2),
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
(10 + const textWidth: numbertextWidth, y: anyy + lineHeight: anylineHeight - 2),
const C_ORANGE_LINE: 8C_ORANGE_LINE, ); return y: anyy + lineHeight: anylineHeight + 4; } // Draws a small panel of font metadata: name, point size, and glyph count, all read // from the loaded BitmapFont. (The built-in font is a BitmapFont too, reachable as // BT.systemFont, so the same fields exist there.) The panel uses the shared UI kit: // everything between ui.begin() and ui.end() stacks into one bordered group that the // kit sizes and anchors. Demo.renderFontInfo(): voidrenderFontInfo() { // Anchor the group to the bottom-right corner, away from the sample text on the // left and the engine overlay's toggle hint in the bottom-left corner. import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_RIGHT); // Give the group a background, a border, and an amber title. import uiui.panel('Font Info'); // ui.kv() draws an aligned "KEY: value" row - the key dim, the value bright. import uiui.kv('FONT', this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.name: string
Font display name.
name
);
import uiui.kv('SIZE', `${this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.size: number
Original font size in points.
size
}pt`);
import uiui.kv('GLYPHS', this.Demo.font: BitmapFont | null
@type{BitmapFont | null}
font
.BitmapFont.glyphCount: number
Returns the total number of glyphs loaded into the font.
@returnsTotal glyph count.
glyphCount
);
// end() closes the group: the kit measures the rows, places the panel, and draws // it. import uiui.end(); } } // Hand the Demo class to BLIT386 to start the demo loop. function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>
One-liner bootstrap function for BLIT386 demos. Handles canvas retrieval and engine initialization. Backend selection (WebGPU or software fallback) is managed internally by BTAPI. This function provides a streamlined way to start a demo with sensible defaults while allowing customization through options.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
(class DemoDemo);