/**
* Fonts Demo - 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
* Live version: https://demos.blit386.dev/fonts
*
* BT.systemPrint() draws text with the engine's built-in system font (6 pixels wide,
* 14 pixels tall per character). No file loading, no await, no font object.
*
* This demo shows:
* - Colored lines via palette indices passed to BT.systemPrint()
* - Measuring text with BT.systemPrintMeasure() before placing it
* - Rainbow text: one systemPrint call per character with its own palette slot
* - Pulsing text: animating alpha in update() on a single palette slot
*
* The small pointer to Bitmap Font demo at the bottom is chrome drawn by the shared UI kit
* (src/shared/ui.js). The showcase lines themselves stay hand-rolled on purpose - drawing
* text with BT.systemPrint() is the whole lesson of this demo.
*
* For custom bitmap fonts loaded from disk, variable glyph widths, and BT.printFont(),
* see the Bitmap Font demo: https://demos.blit386.dev/bitmap-font
*/
import { function bootstrap(DemoClass: DemoConstructor, options?: BootstrapOptions): Promise<boolean>One-liner bootstrap function for BLIT386 demos.
Handles canvas retrieval and engine initialization. Backend selection
(WebGPU or software fallback) is managed internally by BTAPI.
This function provides a streamlined way to start a demo with sensible defaults
while allowing customization through options.bootstrap, const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT, class 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').IBTDemo} IBTDemo */
/** @typedef {import('blit386').HardwareSettings} HardwareSettings */
/** @typedef {import('blit386').Palette} Palette */
// Every color used for drawing is stored in a numbered palette slot.
// Index 0 is always transparent. Custom colors start at 1.
const const C_WHITE: 1C_WHITE = 1; // Pure white: the overlay bar style 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: secondary info lines
// Dynamic slots: one animated color per character in RAINBOW_TEXT.
// update() computes each character's current hue and stores it here.
// render() then reads the slot index - no Color32 math happens during drawing!
const const C_RAINBOW_BASE: 20C_RAINBOW_BASE = 20; // first rainbow character; next slots follow contiguously
// We define the rainbow text string here so both update() and render() use the exact same letters.
// If you change this string, keep the printed end slot equal to C_RAINBOW_BASE + RAINBOW_TEXT.length
// - 1 (the last rainbow slot) so the label stays honest about the range it names.
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: pulsing text changes alpha every frame (fades in and out in a smooth wave).
// Always sits immediately 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;
// Filled in init() from BT.systemPrintMeasure - width of one monospace system glyph.
let let systemCharWidth: numbersystemCharWidth = 6;
/**
* Demonstrates BT.systemPrint() with various text effects powered by palette animation.
* Shows static colors, per-character rainbow animation, and pulsing brightness.
* Compare with the Bitmap Font demo for BitmapFont.load() and BT.printFont().
*
* @implements {IBTDemo}
*/
class class DemoDemonstrates BT.systemPrint() with various text effects powered by palette animation.
Shows static colors, per-character rainbow animation, and pulsing brightness.
Compare with the Bitmap Font demo for BitmapFont.load() and BT.printFont().Demo {
// palette holds all the colors 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 captions with these slots.
Demo.theme: nulltheme = null;
// animTime is a timer that counts up in seconds.
// We use it to control the speed of color animations.
Demo.animTime: numberanimTime = 0;
/**
* Optional engine settings. We keep the default 320x240 screen and show the
* palette grid in the overlay with 32 swatches per row and 2 visible rows.
*
* @returns {Partial<HardwareSettings>}
*/
Demo.configure(): Partial<HardwareSettings>Optional engine settings. We keep the default 320x240 screen and show the
palette grid in the overlay with 32 swatches per row and 2 visible rows.configure() {
return {
isOverlayPaletteEnabled: booleanisOverlayPaletteEnabled: true,
overlayPaletteColumns: numberoverlayPaletteColumns: 32,
overlayPaletteRowsVisible: numberoverlayPaletteRowsVisible: 2,
isOverlayVisibleAtStart: booleanisOverlayVisibleAtStart: true,
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 color palette.
* Unlike Bitmap Font demo, there is no font to load - BT.systemPrint() needs nothing.
*
* @returns {Promise<boolean>} Returns true when ready.
*/
async Demo.init(): Promise<boolean>Sets up the color palette.
Unlike Bitmap Font demo, there is no font to load - BT.systemPrint() needs nothing.init() {
// Set up the color palette
// We pick every color before drawing anything, like an artist mixing paint.
this.Demo.palette: Palette | nullpalette = const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.paletteCreate: (size?: number) => PaletteCreates a standalone palette instance.paletteCreate(256);
// 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 Vector2i(width, height).
// The system font is monospace: every character is the same width (6) and height (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;
... 106 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 dynamic rainbow slots with gray so they're 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 pulse slot.
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 captions draw with.
// It writes 12 colors into slots 240-251, far above everything this demo uses
// (static colors in 1-7, animated rainbow and pulse in 20-38), 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;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.paletteSet: (palette: Palette) => voidStores the active engine palette.
Use this to swap the **entire palette** (e.g. switch between a day and night
theme). After this call the renderer uploads the new palette uniform on the
next frame.
**Palette-value swap (change what a slot looks like):** mutate the live
{@link
BT.palette
}
in place with `palette.set(slot, newColor)`. The renderer
uploads dirty slots on the next frame; no `paletteSet()` or
{@link
BT.spritesRefresh
}
needed.
**Palette-layout swap (same colors, different slot positions):** build a new
palette with the same colors at new indices, call `paletteSet()`, then call
{@link
BT.spritesRefresh
}
so every sprite sheet re-maps its original RGBA
pixels against the new slot layout.paletteSet(this.Demo.palette: Palettepalette);
return true;
}
/**
* Runs at a fixed rate (60 times per second). See the Basics demo for the full explanation:
* https://demos.blit386.dev/basics
* We advance the animation timer AND update dynamic palette colors here.
*/
Demo.update(): voidRuns at a fixed rate (60 times per second). See the Basics demo for the full explanation:
https://demos.blit386.dev/basics
We advance the animation timer AND update dynamic palette colors here.update() {
// Move the animation clock forward using deltaSeconds (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;
... 106 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;
// Update the pulsing text color
// Math.sin returns a wave between -1 and +1 that oscillates smoothly.
// Multiplying by 2 * Math.PI * 3 makes it complete 3 full cycles per second.
// Adding 0.5 and multiplying by 0.5 shifts 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;
// We drive the alpha (opacity) channel so the text fades in and out in a smooth wave.
// 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)));
// Update the rainbow text character colors
// Each character gets a hue based on its horizontal position and the current time.
// systemCharWidth comes from systemPrintMeasure in init() (6 pixels for this font).
let let charX: numbercharX = 10; // Starting x position - same as where render() draws the rainbow text.
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=red, 120=green, 240=blue, 360=back to red).
// Using charX (actual x position) matches the visual rhythm of the rainbow.
// 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 to draw all the text demonstrations on screen.
*/
Demo.render(): voidRuns once per screen refresh to draw all the text demonstrations on screen.render() {
// 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;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.clear: (paletteIndex: number) => voidSets the frame clear color using a palette index.
The renderer uses this color when clearing the full display at the start
of the next frame.clear(const C_BG: 2C_BG);
// Start drawing a bit down from the top edge.
let let y: numbery = 50;
// Draw each section in order, updating y as we go so nothing overlaps.
let y: numbery = this.Demo.renderColoredText(y: number): numberDraws the same four words, each in a different color.
Pass the palette slot number directly to BT.systemPrint() to change the text color.renderColoredText(let y: numbery);
let y: numbery = this.Demo.renderRainbowText(y: number): numberDraws text where each character has a different animated color.
The system font is monospace, so we step systemCharWidth pixels per character.
Colors were pre-computed in update().renderRainbowText(let y: numbery);
let y: numbery = this.Demo.renderPulsingText(y: number): numberDraws the pulsing-text line. The text fades in and out in a smooth rhythm (alpha pulsing).
The alpha value is pre-computed in update() using Math.sin and stored in palette slot C_PULSE.renderPulsingText(let y: numbery);
this.Demo.renderSpecialCharacters(y: number): voidShows that the system font can draw special characters.
Last section before the overlay bars, so this helper does not return an updated y.renderSpecialCharacters(let y: numbery);
// A small dim caption in the bottom-left corner pointing to the next font lesson.
// No ui.panel() call inside the group means it is just floating text - no box.
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_LEFT, { y: numbery: 160 });
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 the same four words, each in a different color.
* Pass the palette slot number directly to BT.systemPrint() to change the text color.
*
* @param {number} y - The Y position to start drawing at.
* @returns {number} The Y position after the last line drawn.
*/
Demo.renderColoredText(y: number): numberDraws the same four words, each in a different color.
Pass the palette slot number directly to BT.systemPrint() to change the text color.renderColoredText(y: number- The Y position to start drawing at.y) {
// Use a local variable so we don't modify the original parameter.
// In JavaScript, changing a parameter's value inside a function can confuse readers
// because they expect the original value to stay the same throughout the function.
let let currentY: numbercurrentY = y: number- The Y position to start drawing at.y;
// BT.systemPrint(position, paletteSlot, text) - the slot number IS the color directly.
// Compare to BT.printFont() in Bitmap Font demo which uses a 0-based palette offset per glyph.
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.systemPrint: (pos: Vector2i, paletteIndex: number, text: string) => 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(10, let currentY: numbercurrentY), const C_RED_TEXT: 3C_RED_TEXT, `Red Text (#${const C_RED_TEXT: 3C_RED_TEXT})`);
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;
... 106 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: numbercurrentY += 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;
... 106 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(12, let currentY: numbercurrentY), const C_GREEN_TEXT: 4C_GREEN_TEXT, `Green Text (#${const C_GREEN_TEXT: 4C_GREEN_TEXT})`);
let currentY: numbercurrentY += 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;
... 106 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(12, let currentY: numbercurrentY), const C_BLUE_TEXT: 5C_BLUE_TEXT, `Blue Text (#${const C_BLUE_TEXT: 5C_BLUE_TEXT})`);
let currentY: numbercurrentY += 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;
... 106 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(12, let currentY: numbercurrentY), const C_YELLOW_TEXT: 6C_YELLOW_TEXT, `Yellow Text (#${const C_YELLOW_TEXT: 6C_YELLOW_TEXT})`);
// Move down one line height after the last word, just like the rows above.
let currentY: numbercurrentY += const lineAdvance: numberlineAdvance;
return let currentY: numbercurrentY;
}
/**
* Draws text where each character has a different animated color.
* The system font is monospace, so we step systemCharWidth pixels per character.
* Colors were pre-computed in update().
*
* @param {number} y - The Y position to start drawing at.
* @returns {number} The Y position after the text.
*/
Demo.renderRainbowText(y: number): numberDraws text where each character has a different animated color.
The system font is monospace, so we step systemCharWidth pixels per character.
Colors were pre-computed in update().renderRainbowText(y: number- The Y position to start drawing at.y) {
// Start drawing from the left margin.
let let x: numberx = 12;
let let slotIndex: numberslotIndex = 0;
// Loop through each character in the string one at a time.
// We 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 gives the palette slot for this character.
// That slot was updated with a fresh color in 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;
... 106 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: number- The Y position to start drawing at.y), const C_RAINBOW_BASE: 20C_RAINBOW_BASE + let slotIndex: numberslotIndex, const char: anychar);
// Step right by the measured glyph width (6 px for the built-in system font).
// Bitmap Font demo uses BitmapFont metrics per character instead of a fixed step.
let x: numberx += let systemCharWidth: numbersystemCharWidth;
let slotIndex: numberslotIndex++;
}
return y: number- The Y position to start drawing at.y + const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.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-text line. The text fades in and out in a smooth rhythm (alpha pulsing).
* The alpha value is pre-computed in update() using Math.sin and stored in palette slot C_PULSE.
*
* @param {number} y - The Y position to start drawing at.
* @returns {number} The Y position after the text.
*/
Demo.renderPulsingText(y: number): numberDraws the pulsing-text line. The text fades in and out in a smooth rhythm (alpha pulsing).
The alpha value is pre-computed in update() using Math.sin and stored in palette slot C_PULSE.renderPulsingText(y: number- The Y position to start drawing at.y) {
// C_PULSE holds an alpha (transparency) pulse precomputed in update():
// RGB stays fixed at (100, 100, 255) - a soft blue - and the alpha channel is
// animated from 0 to 255 with Math.sin(), so the text fades in and out smoothly
// rather than shifting hue. The engine blends the palette color against the
// background at draw time, which is what gives the pulse its smooth look.
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.systemPrint: (pos: Vector2i, paletteIndex: number, text: string) => 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(12, y: number- The Y position to start drawing at.y), const C_PULSE: anyC_PULSE, `Pulsing Text (#${const C_PULSE: anyC_PULSE})`);
return y: number- The Y position to start drawing at.y + const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.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 can draw special characters.
* Last section before the overlay bars, so this helper does not return an updated y.
*
* @param {number} y - The Y position to start drawing at.
*/
Demo.renderSpecialCharacters(y: number): voidShows that the system font can draw special characters.
Last section before the overlay bars, so this helper does not return an updated y.renderSpecialCharacters(y: number- The Y position to start drawing at.y) {
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.systemPrint: (pos: Vector2i, paletteIndex: number, text: string) => 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(12, y: number- The Y position to start drawing at.y), 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 DemoDemonstrates BT.systemPrint() with various text effects powered by palette animation.
Shows static colors, per-character rainbow animation, and pulsing brightness.
Compare with the Bitmap Font demo for BitmapFont.load() and BT.printFont().Demo);