/*
Fonts: the built-in system font and palette-animated text.
@description Draw text with the built-in system font, measure it before drawing, and animate its palette colors.
Part of the BLIT386 demo series.
Prerequisites:
- Basics: https://demos.blit386.dev/basics
- Colors: https://demos.blit386.dev/colors
Live version: https://demos.blit386.dev/fonts
Guides:
- Bitmap Fonts: https://blit386.dev/docs/guides/bitmap-fonts#built-in-system-font
- Palette: https://blit386.dev/docs/guides/palette#draw-using-absolute-palette-indices
- Overlay: https://blit386.dev/docs/guides/overlay#colors-and-hud-palette-slots
Reference:
- Rendering: https://blit386.dev/docs/api/rendering#system-font
- Core Types: https://blit386.dev/docs/api/core-types#color32
---
WHAT YOU WILL SEE
-----------------
A dark navy screen with a column of text starting 12 pixels from the left edge and 50
pixels from the top. From top to bottom:
- Four lines in fixed colors: "Red Text (#3)", "Green Text (#4)", "Blue Text (#5)", and
"Yellow Text (#6)". The number in brackets is the palette slot the line is drawn with.
- "Rainbow Animation (#20 to #49)": every character has its own color, and the colors
slide to the left over time.
- "Pulsing Text (#50)": soft blue text that fades out and back in three times a second.
- A light gray "Special (#7): 3 x 4 = 12" line, showing digits and symbols.
- Two dim lines near the bottom pointing at the Bitmap Font demo.
The engine overlay is open from the start with its palette grid showing 32 swatches per
row and two rows, so slots 20-50 are visible while update() repaints them every tick.
WHAT YOU WILL LEARN
-------------------
- BT.systemPrint(position, paletteIndex, text) draws text with the engine's built-in
system font: 6 pixels wide and 14 pixels tall per character, no file to load, no await,
no font object.
- The palette index you pass is the text color. Change the number, change the color.
- BT.systemPrintMeasure(text) returns a Vector2i with the width and height of that text,
used here for line spacing and for the width of one character.
- Rainbow text: one BT.systemPrint() call per character, each with its own palette slot.
update() computes the colors with Color32.fromHSL(); render() only passes slot numbers.
- Pulsing text: animating just the alpha channel of a single slot with Math.sin().
- Keeping all color math in update() and only palette indices in render().
For custom bitmap fonts loaded from disk, variable glyph widths, and BT.printFont(), see
the Bitmap Font demo: https://demos.blit386.dev/bitmap-font
TRY THIS
--------
- Watch the overlay's palette grid: slots 20-49 cycle through the rainbow and slot 50
fades in and out in step with the text below.
- Press the backquote key (`) to hide the overlay and see the text alone, then again to
bring it back.
*/
import { function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>One-liner bootstrap function for BLIT386 demos.
Handles canvas retrieval and engine initialization. Backend selection
(WebGPU or software fallback) is managed internally by BTAPI.
This function provides a streamlined way to start a demo with sensible defaults
while allowing customization through options.bootstrap, const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT, class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32, class Vector2iInteger 2D vector for pixel-perfect positioning.
Used for points, sizes, directions, and camera offsets throughout the engine.
The API includes both allocation-free `*To()` / `*InPlace()` variants and
convenience methods that return new vectors.Vector2i } from 'blit386';
import { import applyThemeapplyTheme, import uiui, import UI_ANCHORSUI_ANCHORS } from './shared/ui.js';
/** @typedef {import('blit386').Palette} Palette */
// Every color used for drawing lives in a numbered palette slot. Slot 0 is always
// transparent, so our own colors start at 1.
const const C_WHITE: 1C_WHITE = 1; // pure white: the overlay bar color (see configure())
const const C_BG: 2C_BG = 2; // dark blue-navy: fills the screen each frame
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: the "Special" line
// Dynamic slots: one animated color per character in RAINBOW_TEXT. update() computes each
// character's current hue and stores it in its slot; render() then only passes the slot
// number, so no color math happens while drawing.
const const C_RAINBOW_BASE: 20C_RAINBOW_BASE = 20; // first rainbow character; the next slots follow in order
// The rainbow string is defined once so update() and render() use exactly the same
// letters. If you change it, keep the printed end slot equal to C_RAINBOW_BASE +
// RAINBOW_TEXT.length - 1 (the last rainbow slot) so the label stays honest.
const const RAINBOW_TEXT: "Rainbow Animation (#20 to #49)"RAINBOW_TEXT = `Rainbow Animation (#${const C_RAINBOW_BASE: 20C_RAINBOW_BASE} to #${const C_RAINBOW_BASE: 20C_RAINBOW_BASE + 29})`;
// Dynamic slot for the pulsing text: its alpha changes every tick, fading in and out in a
// smooth wave. It always sits right after the last rainbow character slot.
const const C_PULSE: anyC_PULSE = const C_RAINBOW_BASE: 20C_RAINBOW_BASE + const RAINBOW_TEXT: "Rainbow Animation (#20 to #49)"RAINBOW_TEXT.length;
// Width of one system font character in pixels. Filled in init() from
// BT.systemPrintMeasure(); the font is monospace, so every character is this wide.
let let systemCharWidth: numbersystemCharWidth = 6;
// Shared left edge for every showcase line drawn with BT.systemPrint().
const const TEXT_LEFT_X: 12TEXT_LEFT_X = 12;
// Shows BT.systemPrint() with text effects powered by palette animation: fixed colors, a
// per-character rainbow, and pulsing brightness. Compare with the Bitmap Font demo, which
// uses BitmapFont.load() and BT.printFont().
class class DemoDemo {
// The palette holds every color this demo uses.
/** @type {Palette | null} */
Demo.palette: Palette | nullpalette = null;
// Where the shared UI theme colors landed in the palette, filled by applyTheme() in
// init(). The UI kit draws the dim note at the bottom with these slots.
Demo.theme: nulltheme = null;
// A clock that counts up in seconds. It drives the speed of the color animations.
Demo.animTime: numberanimTime = 0;
// Optional engine settings. We keep the default 320x240 screen, open the overlay from
// the start, and show its palette grid with 32 swatches per row and two visible rows.
Demo.configure(): {
isOverlayPaletteEnabled: boolean;
overlayPaletteColumns: number;
overlayPaletteRowsVisible: number;
isOverlayVisibleAtStart: boolean;
overlayStyle: {
barPaletteIndex: number;
textPaletteIndex: number;
gapPaletteIndex: number;
};
}
configure() {
return {
isOverlayPaletteEnabled: booleanisOverlayPaletteEnabled: true,
overlayPaletteColumns: numberoverlayPaletteColumns: 32,
overlayPaletteRowsVisible: numberoverlayPaletteRowsVisible: 2,
isOverlayVisibleAtStart: booleanisOverlayVisibleAtStart: true,
// The overlay bar is drawn in white with navy text, matching the screen.
overlayStyle: {
barPaletteIndex: number;
textPaletteIndex: number;
gapPaletteIndex: number;
}
overlayStyle: {
barPaletteIndex: numberbarPaletteIndex: const C_WHITE: 1C_WHITE,
textPaletteIndex: numbertextPaletteIndex: const C_BG: 2C_BG,
gapPaletteIndex: numbergapPaletteIndex: const C_BG: 2C_BG,
},
};
}
// Sets up the palette. Unlike the Bitmap Font demo there is no font to load:
// BT.systemPrint() needs nothing. Returns true when ready.
async Demo.init(): unknowninit() {
// Create the palette first. We pick every color before drawing anything, like an
// artist mixing paint before touching the canvas.
this.Demo.palette: Palette | nullpalette = const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.paletteCreate: (size?: number) => PaletteCreates a standalone palette instance.paletteCreate(256);
// Static colors that never change from frame to frame.
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_WHITE: 1C_WHITE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 255, 255)); // pure white
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_BG: 2C_BG, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(20, 30, 50)); // dark blue-navy background
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_RED_TEXT: 3C_RED_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 100, 100)); // soft red
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_GREEN_TEXT: 4C_GREEN_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 255, 100)); // soft green
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_BLUE_TEXT: 5C_BLUE_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 100, 255)); // soft blue
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_YELLOW_TEXT: 6C_YELLOW_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 255, 100)); // yellow
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_GRAY_TEXT: 7C_GRAY_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(200, 200, 200)); // light gray
// Measure the built-in system font once. systemPrintMeasure() returns a Vector2i
// (width, height); the font is monospace, so one 'M' tells us the width of every
// character (6 pixels; the height is 14).
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) => Vector2iMeasures the pixel dimensions of a string rendered with the built-in
system font.systemPrintMeasure('M');
let systemCharWidth: numbersystemCharWidth = const glyphSize: Vector2iglyphSize.Vector2i.x: numberHorizontal component (defaults to 0).x;
// Pre-fill the 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 (#20 to #49)"RAINBOW_TEXT.length; let i: numberi++) {
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_RAINBOW_BASE: 20C_RAINBOW_BASE + let i: numberi, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(128, 128, 128));
}
// Pre-fill the pulse slot with the soft blue it keeps all along.
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_PULSE: anyC_PULSE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 100, 255));
// Install the shared UI theme the kit's labels draw with. It writes 12 colors
// into slots 240-251, far above everything this demo uses (static colors in 1-7,
// rainbow and pulse in 20-50), so the palette animation never collides with the
// UI colors. Must happen before BT.paletteSet().
this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palettepalette);
// 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) => voidStores the active engine palette.
Use this to swap the **entire palette** (e.g. switch between a day and night
theme). After this call the renderer uploads the new palette uniform on the
next frame.
**Palette-value swap (change what a slot looks like):** mutate the live
{@link
BT.palette
}
in place with `palette.set(slot, newColor)`. The renderer
uploads dirty slots on the next frame; no `paletteSet()` or
{@link
BT.spritesRefresh
}
needed.
**Palette-layout swap (same colors, different slot positions):** build a new
palette with the same colors at new indices, call `paletteSet()`, then call
{@link
BT.spritesRefresh
}
so every sprite sheet re-maps its original RGBA
pixels against the new slot layout.paletteSet(this.Demo.palette: Palettepalette);
return true;
}
// Runs at a fixed rate (60 times per second by default). Advances the animation clock
// and repaints the dynamic palette slots. See the Basics demo for why update() and
// render() are separate steps: https://demos.blit386.dev/basics
Demo.update(): voidupdate() {
// Move the clock forward by one tick's worth of seconds. deltaSeconds is the
// length of one fixed update step, so this works at any targetFPS.
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: numberFixed-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.deltaSeconds;
// The pulse: Math.sin() returns a wave between -1 and +1. Multiplying the time by
// 2 * Math.PI * 3 makes the wave complete 3 full cycles per second. Multiplying
// by 0.5 and adding 0.5 moves the range from -1..1 to 0..1.
const const pulse: numberpulse = Math.sin(2 * Math.PI * 3 * this.Demo.animTime: numberanimTime) * 0.5 + 0.5;
// Drive the alpha (opacity) channel so the text fades in and out. RGB stays fixed
// at (100, 100, 255), a soft blue, while alpha goes from 0 to 255.
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_PULSE: anyC_PULSE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 100, 255, Math.floor(const pulse: numberpulse * 255)));
// The rainbow: each character gets a hue based on its x position and the current
// time. We walk the same x positions renderRainbowText() uses, so the hue scroll
// lines up with the pixels on screen.
let let charX: numbercharX = const TEXT_LEFT_X: 12TEXT_LEFT_X;
for (let let i: numberi = 0; let i: numberi < const RAINBOW_TEXT: "Rainbow Animation (#20 to #49)"RAINBOW_TEXT.length; let i: numberi++) {
// hue is a position on the color wheel: 0 is red, 120 green, 240 blue, and
// 360 is back to red. `% 360` keeps the value on the wheel as it grows.
// Adding animTime * 100 scrolls the rainbow to the left over time.
const const hue: numberhue = (let charX: numbercharX * 3 + this.Demo.animTime: numberanimTime * 100) % 360;
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_RAINBOW_BASE: 20C_RAINBOW_BASE + let i: numberi, class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.fromHSL(h: number, s: number, l: number, a?: number): Color32Creates a color from HSL values.fromHSL(const hue: numberhue, 100, 60));
let charX: numbercharX += let systemCharWidth: numbersystemCharWidth;
}
}
// Runs once per screen refresh and draws every text showcase.
Demo.render(): voidrender() {
// Fill the screen with the dark blue-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) => voidSets the frame clear color using a palette index.
The renderer uses this color when clearing the full display at the start
of the next frame.clear(const C_BG: 2C_BG);
// Start drawing a bit down from the top edge.
let let y: numbery = 50;
// Draw each section in order. Every helper returns the y below what it drew, so
// nothing overlaps.
let y: numbery = this.Demo.renderColoredText(y: any): anyrenderColoredText(let y: numbery);
let y: numbery = this.Demo.renderRainbowText(y: any): anyrenderRainbowText(let y: numbery);
let y: numbery = this.Demo.renderPulsingText(y: any): anyrenderPulsingText(let y: numbery);
this.Demo.renderSpecialCharacters(y: any): voidrenderSpecialCharacters(let y: numbery);
// A dim two-line note pointing to the next font lesson, drawn with the shared UI
// kit at the same left edge as the showcase lines. pad: 0 removes the group's
// inner padding so x and y place the first line directly.
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { x: numberx: const TEXT_LEFT_X: 12TEXT_LEFT_X, y: numbery: 174, pad: numberpad: 0 });
import uiui.label('To see how to load bitmap fonts from disk,', { color: stringcolor: 'dim' });
import uiui.label('go to Bitmap Font demo', { color: stringcolor: 'dim' });
import uiui.end();
}
// Draws four sample lines, each in a different color, starting at `y`. Returns the y
// just below the last line.
Demo.renderColoredText(y: any): anyrenderColoredText(y: anyy) {
// Work on a copy so the parameter itself is never changed. Readers of a function
// expect its parameters to keep their original values all the way through.
let let currentY: anycurrentY = y: anyy;
// BT.systemPrint(position, paletteSlot, text): the slot number IS the color.
// Compare with BT.printFont() in the Bitmap Font demo, which draws a loaded
// BitmapFont instead.
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, let currentY: anycurrentY), const C_RED_TEXT: 3C_RED_TEXT, `Red Text (#${const C_RED_TEXT: 3C_RED_TEXT})`);
// Line spacing: the measured text height plus a 2-pixel gap.
const const lineAdvance: numberlineAdvance = 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) => Vector2iMeasures the pixel dimensions of a string rendered with the built-in
system font.systemPrintMeasure('Red Text').Vector2i.y: numberVertical component (defaults to 0).y + 2;
let currentY: anycurrentY += const lineAdvance: numberlineAdvance;
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, let currentY: anycurrentY), const C_GREEN_TEXT: 4C_GREEN_TEXT, `Green Text (#${const C_GREEN_TEXT: 4C_GREEN_TEXT})`);
let currentY: anycurrentY += const lineAdvance: numberlineAdvance;
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, let currentY: anycurrentY), const C_BLUE_TEXT: 5C_BLUE_TEXT, `Blue Text (#${const C_BLUE_TEXT: 5C_BLUE_TEXT})`);
let currentY: anycurrentY += const lineAdvance: numberlineAdvance;
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, let currentY: anycurrentY), const C_YELLOW_TEXT: 6C_YELLOW_TEXT, `Yellow Text (#${const C_YELLOW_TEXT: 6C_YELLOW_TEXT})`);
// Move down one line after the last word too, just like the rows above.
let currentY: anycurrentY += const lineAdvance: numberlineAdvance;
return let currentY: anycurrentY;
}
// Draws text where every character has its own animated color. The system font is
// monospace, so we step systemCharWidth pixels per character. The colors were already
// computed in update(). Returns the y just below the text.
Demo.renderRainbowText(y: any): anyrenderRainbowText(y: anyy) {
// Start from the shared left margin, with the first rainbow slot.
let let x: numberx = const TEXT_LEFT_X: 12TEXT_LEFT_X;
let let slotIndex: numberslotIndex = 0;
// Walk the string one character at a time and call BT.systemPrint() once per
// character, each with its own palette slot.
for (const const char: anychar of const RAINBOW_TEXT: "Rainbow Animation (#20 to #49)"RAINBOW_TEXT) {
// C_RAINBOW_BASE + slotIndex is this character's slot, freshly repainted by
// update() this tick.
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(let x: numberx, y: anyy), const C_RAINBOW_BASE: 20C_RAINBOW_BASE + let slotIndex: numberslotIndex, const char: anychar);
// Step right by the measured glyph width (6 pixels for the system font). The
// Bitmap Font demo uses each glyph's own width instead of a fixed step.
let x: numberx += let systemCharWidth: numbersystemCharWidth;
let slotIndex: numberslotIndex++;
}
return y: anyy + 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) => Vector2iMeasures the pixel dimensions of a string rendered with the built-in
system font.systemPrintMeasure('M').Vector2i.y: numberVertical component (defaults to 0).y + 4;
}
// Draws the pulsing line. Slot C_PULSE holds the alpha pulse computed in update():
// RGB stays a soft blue while alpha swings from 0 to 255, so the text fades in and
// out instead of changing hue. The slot's alpha is applied when the pixels are drawn,
// which is what makes the fade look smooth. Returns the y just below the text.
Demo.renderPulsingText(y: any): anyrenderPulsingText(y: anyy) {
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, y: anyy), const C_PULSE: anyC_PULSE, `Pulsing Text (#${const C_PULSE: anyC_PULSE})`);
return y: anyy + 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) => Vector2iMeasures the pixel dimensions of a string rendered with the built-in
system font.systemPrintMeasure('M').Vector2i.y: numberVertical component (defaults to 0).y + 4;
}
// Shows that the system font also has digits and symbols. This is the last text
// section, so the helper does not return a new y.
Demo.renderSpecialCharacters(y: any): voidrenderSpecialCharacters(y: anyy) {
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) => voidDraws 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.systemPrint(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(const TEXT_LEFT_X: 12TEXT_LEFT_X, y: anyy), const C_GRAY_TEXT: 7C_GRAY_TEXT, `Special (#${const C_GRAY_TEXT: 7C_GRAY_TEXT}): 3 x 4 = 12`);
}
}
// 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.bootstrap(class DemoDemo);