/**
* Named Colors Demo - Color32 named lookup table and custom registration APIs.
* @description The Color32 named color registry: resolve a name to a color, register your own, and update it.
*
* Part of the BLIT386 demo series.
* Prerequisites: Basics (https://demos.blit386.dev/basics),
* Colors (https://demos.blit386.dev/colors).
*
* What this demo teaches:
* - How to read built-in named colors with Color32.resolveNamedColor('tomato')
* - How to add your own name with Color32.registerColor(...)
* - How to change a custom name over time with Color32.updateColor(...)
* - How to remove and re-add a custom name with Color32.unregisterColor(...)
*
* Think of the named-color table as a dictionary:
* - The "word" is a name like "cornflowerblue".
* - The "definition" is a Color32 value (r, g, b, a).
* - resolveNamedColor(name) asks the dictionary: "Do you know this word?"
*
* The title strip, captions, and tips panel draw with the shared demo UI kit
* (src/shared/ui.js), so this demo's chrome matches every other demo. The color
* swatches themselves stay hand-drawn - their palette slots ARE the lesson.
*
* Live version: https://demos.blit386.dev/named-colors
*/
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 Rect2iInteger rectangle for pixel-perfect bounds and regions.
Used throughout the engine for sprite regions, display-space bounds, and
zero-allocation geometry helpers. Both convenience getters and allocation-free
`*To()` helpers are provided so callers can choose between readability and
hot-path efficiency.Rect2i, 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';
// The shared demo UI kit. applyTheme() installs the kit's twelve UI colors high in the
// palette (slots 240-251, far above this demo's slots 1-9), and ui.* draws the title
// strip, the caption text, and the Tips panel.
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 */
// Palette indices for this demo's own colors. Slot 0 stays transparent.
// Panels, captions, and status text draw with the shared UI theme instead (installed by
// applyTheme() in init()), so only two kinds of slots live down here: the overlay timing
// chart's bar colors, and the lesson's swatch slots.
//
// The chart slots exist because configure() runs BEFORE init() installs the theme, so the
// chart style cannot point at theme slots - init() copies the matching theme colors here.
const const C_CHART_UPDATE: 1C_CHART_UPDATE = 1; // Timing chart: update() bar (matches the theme's blue-gray border).
const const C_CHART_RENDER: 2C_CHART_RENDER = 2; // Timing chart: render() bar (matches the theme's off-white text).
const const C_CHART_TAG: 3C_CHART_TAG = 3; // Timing chart: milestone tag labels (matches the theme's green accent).
const const C_TOMATO: 5C_TOMATO = 5; // Swatch slot for built-in name "tomato".
const const C_CORNFLOWER: 6C_CORNFLOWER = 6; // Swatch slot for built-in name "cornflowerblue".
const const C_CUSTOM_DYNAMIC: 7C_CUSTOM_DYNAMIC = 7; // Swatch slot for animated custom name "demo-dynamic".
const const C_OPTIONAL: 8C_OPTIONAL = 8; // Swatch slot for toggled custom name "demo-optional".
const const C_OPTIONAL_FALLBACK: 9C_OPTIONAL_FALLBACK = 9; // Gray shown when demo-optional is unregistered.
const const CUSTOM_DYNAMIC_NAME: "demo-dynamic"CUSTOM_DYNAMIC_NAME = 'demo-dynamic';
const const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME = 'demo-optional';
const const SWATCH_W: 64SWATCH_W = 64;
const const SWATCH_H: 26SWATCH_H = 26;
/**
* Demonstrates built-in and custom named colors.
*
* @implements {IBTDemo}
*/
class class DemoDemonstrates built-in and custom named colors.Demo {
/** @type {Palette | null} */
Demo.palette: Palette | nullpalette = null;
// theme holds the palette slot numbers of the shared UI kit colors, filled in by
// applyTheme() in init(). We use them for the background, the swatch panel frame,
// and the swatch outlines and labels.
Demo.theme: nulltheme = null;
Demo.optionalRegistered: booleanoptionalRegistered = true;
Demo.elapsed: numberelapsed = 0;
/**
* Opt in to the overlay timing chart with palette-matched bar colors.
*
* @returns {Partial<HardwareSettings>}
*/
Demo.configure(): Partial<HardwareSettings>Opt in to the overlay timing chart with palette-matched bar colors.configure() {
return {
isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true,
overlayTimingChartStyle: {
updateBarPaletteIndex: number;
renderBarPaletteIndex: number;
tagPaletteIndex: number;
}
overlayTimingChartStyle: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const C_CHART_UPDATE: 1C_CHART_UPDATE,
renderBarPaletteIndex: numberrenderBarPaletteIndex: const C_CHART_RENDER: 2C_CHART_RENDER,
tagPaletteIndex: numbertagPaletteIndex: const C_CHART_TAG: 3C_CHART_TAG,
},
};
}
/**
* Build palette and register custom named colors.
*
* @returns {Promise<boolean>}
*/
async Demo.init(): Promise<boolean>Build palette and register custom named colors.init() {
this.Demo.palette: Palette | nullpalette = const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.paletteCreate: (size?: number) => PaletteCreates a standalone palette instance.paletteCreate(256);
// Overlay timing chart colors. These copy the shared theme's hex values into the
// low slots that configure() pointed the chart style at (see the note on the
// C_CHART_* constants above for why the chart cannot use theme slots directly).
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_CHART_UPDATE: 1C_CHART_UPDATE, class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.fromHex(hex: string): Color32Parses a CSS-style hex color string.
Supports `#RGB`, `#RGBA`, `#RRGGBB`, and `#RRGGBBAA`.fromHex('#5a6480')); // theme border blue-gray
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_CHART_RENDER: 2C_CHART_RENDER, class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.fromHex(hex: string): Color32Parses a CSS-style hex color string.
Supports `#RGB`, `#RGBA`, `#RRGGBB`, and `#RRGGBBAA`.fromHex('#e6ecf5')); // theme text off-white
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_CHART_TAG: 3C_CHART_TAG, class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.fromHex(hex: string): Color32Parses a CSS-style hex color string.
Supports `#RGB`, `#RGBA`, `#RRGGBB`, and `#RRGGBBAA`.fromHex('#7dffa5')); // theme accent green
// Fallback gray for the moments when demo-optional is unregistered.
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OPTIONAL_FALLBACK: 9C_OPTIONAL_FALLBACK, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(80, 80, 80));
// Install the shared UI kit colors. They land in palette slots 240-251, far above
// the swatch slots this demo animates (5-9), 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: Palettepalette);
// Remove old custom names before registering fresh ones.
// Hot reload can leave names in memory from a previous run; unregister first
// so registerColor does not throw "name already exists".
this.Demo.removeIfExists(name: string): voidIf a custom name exists, remove it first so init() can register cleanly.
This makes hot-reload safer during development.removeIfExists(const CUSTOM_DYNAMIC_NAME: "demo-dynamic"CUSTOM_DYNAMIC_NAME);
this.Demo.removeIfExists(name: string): voidIf a custom name exists, remove it first so init() can register cleanly.
This makes hot-reload safer during development.removeIfExists(const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME);
// registerColor adds a NEW entry to the global name table.
// It throws if the name is already taken - that is why we cleared above.
// 'demo-dynamic' will be rewritten every tick with updateColor in update().
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.registerColor(name: string, color: Color32): voidRegisters a named color in the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.registerColor(const CUSTOM_DYNAMIC_NAME: "demo-dynamic"CUSTOM_DYNAMIC_NAME, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(90, 170, 255));
// 'demo-optional' starts registered; update() will unregister and re-register
// it on a timer so you can watch resolveNamedColor fall back to gray.
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.registerColor(name: string, color: Color32): voidRegisters a named color in the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.registerColor(const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 90, 150));
this.Demo.optionalRegistered: booleanoptionalRegistered = true;
this.Demo.elapsed: numberelapsed = 0;
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.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;
}
/**
* Animate custom named colors every tick.
*/
Demo.update(): voidAnimate custom named colors every tick.update() {
this.Demo.elapsed: numberelapsed += 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;
// Read two built-in names from the registry.
const const tomato: Color32tomato = this.Demo.resolveOr(name: string, fallback: Color32): Color32Resolve a named color and fall back if the name is missing.resolveOr('tomato', new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 99, 71));
const const cornflower: Color32cornflower = this.Demo.resolveOr(name: string, fallback: Color32): Color32Resolve a named color and fall back if the name is missing.resolveOr('cornflowerblue', new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 149, 237));
// Blend between the two built-ins to create a moving custom color.
// Math.sin() returns -1..1, so (sin+1)/2 converts it to 0..1.
const const t: numbert = (Math.sin(this.Demo.elapsed: numberelapsed * 2) + 1) / 2;
const const dynamicColor: Color32dynamicColor = const tomato: Color32tomato.Color32.lerp(other: Color32, t: number): Color32Linearly interpolates between this color and another.
Useful for color transitions and gradients.lerp(const cornflower: Color32cornflower, const t: numbert);
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.updateColor(name: string, color: Color32): voidUpdates an existing named color in the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.
All alias keys that share the same object reference are updated in sync.updateColor(const CUSTOM_DYNAMIC_NAME: "demo-dynamic"CUSTOM_DYNAMIC_NAME, const dynamicColor: Color32dynamicColor);
// Every 3 seconds toggle demo-optional:
// registered -> unregistered -> registered -> ...
const const cycle: numbercycle = Math.floor(this.Demo.elapsed: numberelapsed / 3) % 2;
const const shouldBeRegistered: booleanshouldBeRegistered = const cycle: numbercycle === 0;
if (const shouldBeRegistered: booleanshouldBeRegistered && !this.Demo.optionalRegistered: booleanoptionalRegistered) {
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.registerColor(name: string, color: Color32): voidRegisters a named color in the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.registerColor(const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 90, 150));
this.Demo.optionalRegistered: booleanoptionalRegistered = true;
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.assignTag: (label?: string) => voidPlaces a labeled marker on the overlay timing chart at the current tick.
Requires `isOverlayTimingChartEnabled: true` in `configure()`. Tags scroll with the chart
history and are pruned when they leave the visible window. Empty labels become
`"Untitled"`. Chart width resets add an automatic `"Start"` tag.assignTag('Optional registered');
} else if (!const shouldBeRegistered: booleanshouldBeRegistered && this.Demo.optionalRegistered: booleanoptionalRegistered) {
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.unregisterColor(name: string): voidRemoves a named color from the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.
All alias keys that share the same object reference are removed in sync.unregisterColor(const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME);
this.Demo.optionalRegistered: booleanoptionalRegistered = false;
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.assignTag: (label?: string) => voidPlaces a labeled marker on the overlay timing chart at the current tick.
Requires `isOverlayTimingChartEnabled: true` in `configure()`. Tags scroll with the chart
history and are pruned when they leave the visible window. Empty labels become
`"Untitled"`. Chart width resets add an automatic `"Start"` tag.assignTag('Optional removed');
}
// Copy current named colors into palette slots used by draw calls.
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_TOMATO: 5C_TOMATO, const tomato: Color32tomato);
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_CORNFLOWER: 6C_CORNFLOWER, const cornflower: Color32cornflower);
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_CUSTOM_DYNAMIC: 7C_CUSTOM_DYNAMIC, this.Demo.resolveOr(name: string, fallback: Color32): Color32Resolve a named color and fall back if the name is missing.resolveOr(const CUSTOM_DYNAMIC_NAME: "demo-dynamic"CUSTOM_DYNAMIC_NAME, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 255, 255)));
// When demo-optional is unregistered, show the reserved C_OPTIONAL_FALLBACK slot
// (set in init()) instead of looking up the built-in name "gray".
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OPTIONAL: 8C_OPTIONAL, this.Demo.resolveOr(name: string, fallback: Color32): Color32Resolve a named color and fall back if the name is missing.resolveOr(const CUSTOM_OPTIONAL_NAME: "demo-optional"CUSTOM_OPTIONAL_NAME, this.Demo.palette: Palette | nullpalette.Palette.get(index: number): Color32Returns a copy of the color stored at a palette index.
Returns a clone so callers cannot mutate internal state without going
through
{@link
set
}
, which keeps the dirty flag accurate.get(const C_OPTIONAL_FALLBACK: 9C_OPTIONAL_FALLBACK)));
}
/**
* Draw color swatches and live registry status.
*
* The chrome (title strip, captions, Tips panel) draws with the shared UI kit;
* the swatch panel and swatches stay hand-drawn because their palette slots
* are what this demo teaches.
*/
Demo.render(): voidDraw color swatches and live registry status.
The chrome (title strip, captions, Tips panel) draws with the shared UI kit;
the swatch panel and swatches stay hand-drawn because their palette slots
are what this demo teaches.render() {
// 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;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.clear: (paletteIndex: number) => voidSets the frame clear color using a palette index.
The renderer uses this color when clearing the full display at the start
of the next frame.clear(this.Demo.theme: nulltheme.bg);
// Full-width title strip across the top of the screen, drawn by the shared UI kit.
// 'topBar' is the classic 22-pixel strip; panel() gives it a background and title.
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_BAR);
import uiui.panel('Built-in lookups + register / update / unregister');
import uiui.end();
// Upper panel: hand-drawn background for the four color swatches. Kit panels size
// themselves around kit rows only, so a frame around hand-drawn artwork keeps using
// BT.drawRectFill / BT.drawRect - but with the shared theme's panel colors.
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(6, 32, 308, 126), this.Demo.theme: nulltheme.panel);
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(6, 32, 308, 126), this.Demo.theme: nulltheme.border);
// Four labeled swatches in one row (tomato, cornflower, animated custom, optional custom).
this.Demo.drawSwatch(x: number, y: number, colorIndex: number, label: string): voidDraw one labeled color swatch.drawSwatch(16, 44, const C_TOMATO: 5C_TOMATO, 'tomato');
this.Demo.drawSwatch(x: number, y: number, colorIndex: number, label: string): voidDraw one labeled color swatch.drawSwatch(96, 44, const C_CORNFLOWER: 6C_CORNFLOWER, 'cornflower');
this.Demo.drawSwatch(x: number, y: number, colorIndex: number, label: string): voidDraw one labeled color swatch.drawSwatch(176, 44, const C_CUSTOM_DYNAMIC: 7C_CUSTOM_DYNAMIC, 'dynamic');
this.Demo.drawSwatch(x: number, y: number, colorIndex: number, label: string): voidDraw one labeled color swatch.drawSwatch(256, 44, const C_OPTIONAL: 8C_OPTIONAL, 'optional');
// Captions under the swatches: a borderless kit group pinned inside the panel.
// Passing x and y pins the group's top-left corner; pad: 0 removes the group's
// inner padding so the first row starts exactly at (16, 100).
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { x: numberx: 16, y: numbery: 100, pad: numberpad: 0 });
import uiui.label("Custom dynamic name: 'demo-dynamic'");
import uiui.label("Custom optional name: 'demo-optional'");
// The status line flips between the theme's green 'accent' and orange 'warm' roles,
// so you can watch Color32.registerColor / Color32.unregisterColor take effect
// every 3 seconds (update() drives the toggle).
if (this.Demo.optionalRegistered: booleanoptionalRegistered) {
import uiui.label('demo-optional is registered (registerColor)', { color: stringcolor: 'accent' });
} else {
import uiui.label('demo-optional is missing (unregisterColor)', { color: stringcolor: 'warm' });
}
import uiui.end();
// Lower panel: API tips as a kit panel anchored to the bottom-left corner.
// The kit sizes the panel to its widest row and keeps a small screen margin.
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_LEFT);
import uiui.panel('Tips');
import uiui.label('Names are trim + lowercase normalized.', { color: stringcolor: 'dim' });
import uiui.label('registerColor throws if the name exists.', { color: stringcolor: 'dim' });
import uiui.label('updateColor / unregisterColor throw if missing.', { color: stringcolor: 'dim' });
import uiui.end();
}
/**
* Resolve a named color and fall back if the name is missing.
*
* @param {string} name
* @param {Color32} fallback
* @returns {Color32}
*/
Demo.resolveOr(name: string, fallback: Color32): Color32Resolve a named color and fall back if the name is missing.resolveOr(name: stringname, fallback: Color32fallback) {
const const resolved: Color32 | undefinedresolved = class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.resolveNamedColor(name: string): Color32 | undefinedLooks up a named color from the global registry.
Name matching is case-insensitive and trims surrounding whitespace.resolveNamedColor(name: stringname);
if (const resolved: Color32 | undefinedresolved === var undefinedundefined) {
return fallback: Color32fallback;
}
return const resolved: Color32resolved;
}
/**
* If a custom name exists, remove it first so init() can register cleanly.
*
* This makes hot-reload safer during development.
*
* @param {string} name
*/
Demo.removeIfExists(name: string): voidIf a custom name exists, remove it first so init() can register cleanly.
This makes hot-reload safer during development.removeIfExists(name: stringname) {
if (class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.resolveNamedColor(name: string): Color32 | undefinedLooks up a named color from the global registry.
Name matching is case-insensitive and trims surrounding whitespace.resolveNamedColor(name: stringname) !== var undefinedundefined) {
class Color32Mutable 32-bit RGBA color value with 8-bit channels.Color32.Color32.unregisterColor(name: string): voidRemoves a named color from the global color registry.
Name matching is case-insensitive and trims surrounding whitespace.
All alias keys that share the same object reference are removed in sync.unregisterColor(name: stringname);
}
}
/**
* Draw one labeled color swatch.
*
* @param {number} x
* @param {number} y
* @param {number} colorIndex
* @param {string} label
*/
Demo.drawSwatch(x: number, y: number, colorIndex: number, label: string): voidDraw one labeled color swatch.drawSwatch(x: numberx, y: numbery, colorIndex: numbercolorIndex, label: stringlabel) {
// Fill the swatch with the palette slot we are demonstrating - the lesson itself.
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(x: numberx, y: numbery, const SWATCH_W: 64SWATCH_W, const SWATCH_H: 26SWATCH_H), colorIndex: numbercolorIndex);
// The outline and the label are chrome, so they use the shared UI theme colors.
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(x: numberx, y: numbery, const SWATCH_W: 64SWATCH_W, const SWATCH_H: 26SWATCH_H), this.Demo.theme: nulltheme.border);
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(x: numberx, y: numbery + const SWATCH_H: 26SWATCH_H + 2), this.Demo.theme: nulltheme.text, label: stringlabel);
}
}
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 built-in and custom named colors.Demo);