/*
Camera: scroll a view across a world larger than the screen.
@description Scroll a camera over a world larger than the screen, then reset it so the HUD and mini-map stay put.
Part of the BLIT386 demo series.
Prerequisites:
- Basics: https://demos.blit386.dev/basics
- Primitives: https://demos.blit386.dev/primitives
Live version: https://demos.blit386.dev/camera
Guides:
- Game Loop: https://blit386.dev/docs/guides/game-loop#smoothing-motion-between-updates
- Overlay: https://blit386.dev/docs/guides/overlay#custom-rows
- Random: https://blit386.dev/docs/guides/random#deterministic-by-default
Reference:
- Camera: https://blit386.dev/docs/api/camera
- Game Loop: https://blit386.dev/docs/api/game-loop#interpolating-render-state-with-renderalpha
- Overlay: https://blit386.dev/docs/api/overlay#palette-grid-sizing
- Random: https://blit386.dev/docs/api/random#spatial-helpers
---
WHAT YOU WILL SEE
-----------------
An 800x600 pixel world seen through a 320x240 screen. The ground is sky blue with green
grid lines every 40 pixels and a red rectangle around the world's edge. Scattered over it
are 50 trees (brown trunk, green canopy with a darker outline), 20 buildings in random
blue-gray tints with pale-yellow windows, and one 16x16 red square - the "player" - that
never moves from world position (400, 300). The camera drifts on its own along a looping
wave path, so the whole world slides around under the screen.
A UI kit panel in the top-left corner shows the camera position and the world size. A
mini-map in the bottom-right corner shows the whole world at once: a dot per building, a
yellow box for the part of the world the screen is showing, and a tiny red square for the
player. The engine overlay gets two custom rows (camera position and world size), a
palette grid, and the timing chart.
WHAT YOU WILL LEARN
-------------------
- BT.cameraSet(offset) shifts every later draw call by that offset, so world coordinates
land in the right place on screen. BT.cameraReset() switches back to plain screen
coordinates for the HUD.
- BT.cameraClamp(pos, worldSize, viewSize) keeps the camera from looking past the world's
edges.
- Smooth scrolling between ticks: remember the camera position from the start of
update(), then blend it toward the new one in render() using BT.renderAlpha.
- Placing things at random with BT.random.int(), BT.random.pointInRange(), and
BT.random.insideRect().
- Giving each building its own palette slot with palette.set(), so draw calls pass a slot
number instead of a color.
- Reusing a few Vector2i and Rect2i objects instead of creating new ones every frame.
- Custom overlay rows via overlayRows(), plus configure() flags for the overlay palette
grid and timing chart.
HOW THE CAMERA WORKS
--------------------
Imagine looking through a window: the window does not move, but you can shift which part
of the outside world you see through it. That is what a camera does in a game. Here the
camera is just an offset - how far the view has scrolled to the right and down from the
world's top-left corner. A camera X of 200 means the left edge of the screen shows world
pixel column 200, so the world appears to have slid 200 pixels to the left.
update() moves the camera along a smooth looping path built from sine and cosine (a
Lissajous curve) and clamps it to the world. render() applies the blended offset with
BT.cameraSet(), draws the world, calls BT.cameraReset(), and then draws the panel and
mini-map in screen coordinates so they stay put.
TRY THIS
--------
- Press the backquote key (`) to open the engine overlay. Two custom rows repeat the
camera position and world size, and a palette grid shows 32 swatches per row, 2 rows at
a time - scroll the wheel over the grid to browse the rest of the 256 slots.
- Watch the yellow box on the mini-map: it traces the same path the view takes.
*/
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 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';
import { import applyThemeapplyTheme, import uiui, import UI_ANCHORSUI_ANCHORS } from './shared/ui.js';
/** @typedef {import('blit386').Palette} Palette */
// Every color in this demo is pre-registered in a numbered palette slot. Slot 0 is always
// transparent, so custom colors start at 1. Static colors (fixed forever) live here; the
// 20 random building colors are added later. The title panel and the mini-map frame use
// the shared UI kit theme instead, which applyTheme() installs into slots 240-251.
const const C_SKY: 2C_SKY = 2; // sky blue: screen background
const const C_GRID: 3C_GRID = 3; // medium green: grid lines on the ground
const const C_WORLD_BORDER: 4C_WORLD_BORDER = 4; // red: rectangle around the entire world boundary
const const C_TRUNK: 5C_TRUNK = 5; // brown: tree trunk
const const C_FOLIAGE: 6C_FOLIAGE = 6; // dark green: tree foliage fill
const const C_FOLIAGE_OUTLINE: 7C_FOLIAGE_OUTLINE = 7; // darker green: tree foliage outline
const const C_BUILDING_OUTLINE: 8C_BUILDING_OUTLINE = 8; // very dark gray: building border
const const C_WINDOW: 9C_WINDOW = 9; // pale yellow (semi-transparent): building windows
const const C_PLAYER: 10C_PLAYER = 10; // salmon red: player square fill
const const C_PLAYER_OUTLINE: 11C_PLAYER_OUTLINE = 11; // darker red: player square border
const const C_BUILDING_DOT: 16C_BUILDING_DOT = 16; // blue-gray: building dot on the mini-map
const const C_VIEWPORT: 17C_VIEWPORT = 17; // yellow: viewport rectangle on the mini-map
const const C_OVERLAY_BAR: 40C_OVERLAY_BAR = 40; // semi-transparent bar behind overlay custom rows
const const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT = 41; // light gray text for camera position in the overlay
const const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER = 42; // amber accent for world size in the overlay
const const C_OVERLAY_GAP: 43C_OVERLAY_GAP = 43; // gray: gap between overlay rows
// Each of the 20 buildings gets its own randomly chosen color stored at slots 20-39.
const const C_BUILDING_BASE: 20C_BUILDING_BASE = 20; // building 0 is at slot 20, building 1 at 21, and so on
// A procedurally generated city seen through an auto-scrolling camera. Buildings and
// trees are placed at random once in init(); after that only the camera moves.
class class DemoDemo {
// The total size of the game world in pixels. The screen is only 320x240, but the
// world is much bigger.
Demo.worldWidth: numberworldWidth = 800;
Demo.worldHeight: numberworldHeight = 600;
// Where the camera is currently looking, in world coordinates. (0, 0) means the
// top-left corner of the world is visible.
Demo.cameraPos: Vector2icameraPos = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0);
// Where the camera was at the start of the most recent update() tick, before that
// tick's sine/cosine math moved it. render() blends between cameraPrevPos and
// cameraPos using BT.renderAlpha, so the camera pans smoothly between ticks instead
// of jumping - see the Game Loop guide linked in the header.
Demo.cameraPrevPos: Vector2icameraPrevPos = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0);
// Reused every render() call for the blended camera position, so no new Vector2i is
// allocated per frame.
Demo.cameraRenderPos: Vector2icameraRenderPos = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0);
// A stationary red square we call the "player" - it stays in place while the camera
// moves around it.
Demo.playerPos: Vector2iplayerPos = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(400, 300);
// The randomly generated world objects. Each building has a position, a size, and a
// palette slot number (colorIndex). Each tree just has a position.
Demo.buildings: {}buildings = [];
Demo.trees: {}trees = [];
// The palette holds all the colors this demo uses.
/** @type {Palette | null} */
Demo.palette: Palette | nullpalette = null;
// Slot map for the shared UI kit theme, filled in init() by applyTheme(). It tells us
// which palette slots hold the kit's panel, border, and text colors.
Demo.theme: nulltheme = null;
// Reused every frame for the engine overlay (camera position and world size). We keep
// one array and update the text strings in place, so nothing new is allocated on each
// screen refresh.
Demo.overlayRowData: {}overlayRowData = [
{ leftText: stringleftText: 'Camera (0, 0)', textPaletteIndex: numbertextPaletteIndex: const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT },
{ leftText: stringleftText: 'World 800x600', textPaletteIndex: numbertextPaletteIndex: const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER },
];
// Scratch objects reused every frame instead of creating new ones in the draw loop.
// Reusing objects is faster because the browser does not have to clean up old ones.
Demo.tempVec1: Vector2itempVec1 = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0);
Demo.tempVec2: Vector2itempVec2 = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0);
Demo.tempRect: Rect2itempRect = new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(0, 0, 0, 0);
Demo.worldSize: Vector2iworldSize = new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(800, 600); // matches worldWidth/worldHeight above
// Called once before init(). Turns on the overlay's palette grid (32 swatches per
// row, 2 rows visible at a time - scroll the band to browse the rest of the 256
// slots) and the timing chart, and picks palette slots for the overlay bars and text.
Demo.configure(): {
isOverlayPaletteEnabled: boolean;
overlayPaletteColumns: number;
overlayPaletteRowsVisible: number;
overlayStyle: {
barPaletteIndex: number;
textPaletteIndex: number;
gapPaletteIndex: number;
};
isOverlayTimingChartEnabled: boolean;
overlayTimingChartStyle: {
updateBarPaletteIndex: number;
renderBarPaletteIndex: number;
warningPaletteIndex: number;
errorPaletteIndex: number;
tagPaletteIndex: number;
};
}
configure() {
return {
isOverlayPaletteEnabled: booleanisOverlayPaletteEnabled: true,
overlayPaletteColumns: numberoverlayPaletteColumns: 32,
overlayPaletteRowsVisible: numberoverlayPaletteRowsVisible: 2,
overlayStyle: {
barPaletteIndex: number;
textPaletteIndex: number;
gapPaletteIndex: number;
}
overlayStyle: {
barPaletteIndex: numberbarPaletteIndex: const C_OVERLAY_BAR: 40C_OVERLAY_BAR,
textPaletteIndex: numbertextPaletteIndex: const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT,
gapPaletteIndex: numbergapPaletteIndex: const C_OVERLAY_GAP: 43C_OVERLAY_GAP,
},
isOverlayTimingChartEnabled: booleanisOverlayTimingChartEnabled: true,
overlayTimingChartStyle: {
updateBarPaletteIndex: number;
renderBarPaletteIndex: number;
warningPaletteIndex: number;
errorPaletteIndex: number;
tagPaletteIndex: number;
}
overlayTimingChartStyle: {
updateBarPaletteIndex: numberupdateBarPaletteIndex: const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT,
renderBarPaletteIndex: numberrenderBarPaletteIndex: const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER,
warningPaletteIndex: numberwarningPaletteIndex: const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER,
errorPaletteIndex: numbererrorPaletteIndex: const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER,
tagPaletteIndex: numbertagPaletteIndex: const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT,
},
};
}
// Runs once when the demo starts. Sets up the palette and generates random buildings
// and trees to fill the world.
async Demo.init(): unknowninit() {
// Think of a palette like an artist choosing paint colors before painting. Every
// color we might draw with gets a numbered slot. The static colors go in first;
// the 20 random building colors are added when the buildings are generated.
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 - the same every time the demo runs. Each slot's role is
// described on its C_* constant at the top of the file.
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_SKY: 2C_SKY, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(135, 206, 235));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_GRID: 3C_GRID, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(100, 180, 100));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_WORLD_BORDER: 4C_WORLD_BORDER, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 0, 0));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_TRUNK: 5C_TRUNK, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(101, 67, 33));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_FOLIAGE: 6C_FOLIAGE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(34, 139, 34));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_FOLIAGE_OUTLINE: 7C_FOLIAGE_OUTLINE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(20, 100, 20));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_BUILDING_OUTLINE: 8C_BUILDING_OUTLINE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(50, 50, 50));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_WINDOW: 9C_WINDOW, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 255, 200, 200));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_PLAYER: 10C_PLAYER, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 100, 100));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_PLAYER_OUTLINE: 11C_PLAYER_OUTLINE, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(200, 50, 50));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_BUILDING_DOT: 16C_BUILDING_DOT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(150, 150, 200));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_VIEWPORT: 17C_VIEWPORT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(255, 255, 0));
// Overlay colors (must match configure().overlayStyle and overlayRowData).
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OVERLAY_BAR: 40C_OVERLAY_BAR, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(0, 0, 0, 200));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OVERLAY_TEXT: 41C_OVERLAY_TEXT, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(200, 200, 200));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OVERLAY_AMBER: 42C_OVERLAY_AMBER, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(220, 180, 60));
this.Demo.palette: Palettepalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const C_OVERLAY_GAP: 43C_OVERLAY_GAP, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(48, 48, 48));
// Install the shared UI kit theme. applyTheme() writes twelve UI colors into high
// palette slots (240-251), far above this demo's scene slots (2-43), and returns
// a map of slot numbers we can draw with (panel, border, text...).
this.Demo.theme: nulltheme = import applyThemeapplyTheme(this.Demo.palette: Palettepalette);
// Tell the engine "use this palette from now on."
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);
// Generate buildings after the palette is set up: generateBuildings() adds 20
// random colors to the palette (slots 20-39) and stores the slot number on each
// building instead of a Color32 object.
this.Demo.generateBuildings(): voidgenerateBuildings();
this.Demo.generateTrees(): voidgenerateTrees();
return true;
}
// Runs at a fixed rate (60 times per second) to move the camera along a smooth,
// wave-like path through the world. In a real game you would move the camera based on
// player input instead.
Demo.update(): voidupdate() {
// Remember where the camera was before this tick's math moves it, so render() has
// an "old" and a "new" position to blend between.
this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x, this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y);
// t grows slowly each tick and drives the wave motion. Multiplying the tick count
// by 0.02 keeps the movement nice and slow.
const const t: numbert = 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.ticks: numberCurrent fixed-update tick counter.
Increments once per engine update. Reset via
{@link
BT.ticksReset
}
.ticks * 0.02;
// Math.sin and Math.cos produce values between -1 and +1. Multiplying by 150 and
// 100 turns those into pixel distances; adding 200 and 150 keeps the path
// centered in the world instead of hugging its top-left corner.
this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x = Math.floor(200 + Math.sin(const t: numbert) * 150);
this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y = Math.floor(150 + Math.cos(const t: numbert * 0.7) * 100);
// Make sure the camera does not scroll past the edges of the world. The largest
// allowed X is worldWidth minus the screen width, so the screen never shows empty
// space beyond the world's right boundary.
this.Demo.cameraPos: Vector2icameraPos = 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.cameraClamp: (camera: Vector2i, worldSize: Vector2i, viewSize?: Vector2i) => Vector2iClamps a camera origin so the viewport stays within world bounds.
Uses integer clamping per axis: `[0, worldSize - viewSize]`.
If `viewSize` is omitted, the active
{@link
BT.displaySize
}
is used.cameraClamp(this.Demo.cameraPos: Vector2icameraPos, this.Demo.worldSize: Vector2iworldSize, 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.displaySize: Vector2iActive logical render resolution in pixels.
This is the game/simulation coordinate space configured by the demo, not
the canvas element's CSS size. Each read returns a clone.displaySize);
// BT.cameraSet() happens in render(), using a position blended between
// cameraPrevPos and cameraPos.
}
// Runs once per screen refresh to draw the world and then the HUD. Anything drawn
// before BT.cameraReset() is shifted by the camera; anything drawn after it is in
// plain screen coordinates.
Demo.render(): voidrender() {
// Clear the screen to sky blue.
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_SKY: 2C_SKY);
// Blend cameraPrevPos toward cameraPos by BT.renderAlpha - a fraction from 0 (a
// tick just finished) to just under 1 (the next tick is about to happen) - so the
// camera's on-screen position matches this exact render moment instead of only
// its last-tick position. Set it here, right before any world drawing, so every
// draw call this frame uses the same smoothed offset.
this.Demo.cameraRenderPos: Vector2icameraRenderPos.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(
Math.floor(this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.x: numberHorizontal component (defaults to 0).x + (this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x - this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.x: numberHorizontal component (defaults to 0).x) * 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.renderAlpha: numberFractional progress between the last completed fixed update and the next.
Intended for interpolating render state between fixed-update steps.renderAlpha),
Math.floor(this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.y: numberVertical component (defaults to 0).y + (this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y - this.Demo.cameraPrevPos: Vector2icameraPrevPos.Vector2i.y: numberVertical component (defaults to 0).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;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.renderAlpha: numberFractional progress between the last completed fixed update and the next.
Intended for interpolating render state between fixed-update steps.renderAlpha),
);
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.cameraSet: (offset: Vector2i) => voidSets the global camera offset applied to subsequent draw calls.cameraSet(this.Demo.cameraRenderPos: Vector2icameraRenderPos);
// Draw all the world content (grid, trees, buildings, player). These are shifted
// by the camera, so they appear to scroll.
this.Demo.renderWorld(): voidrenderWorld();
// Reset the camera so the UI (panel, mini-map) stays fixed on screen. Without
// this, the UI would scroll away with the world.
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.cameraReset: () => voidResets the global camera offset to `(0, 0)`.cameraReset();
// Draw the HUD (title panel, camera position, mini-map) in screen coordinates.
this.Demo.renderUI(): voidrenderUI();
}
// Optional hook: tells the engine what extra lines to draw in the overlay. Custom
// rows stack upward from just above the bottom FPS bar; their colors come from the
// palette slots set in init() and from configure().overlayStyle. We return the same
// overlayRowData array every time and only change the text.
Demo.overlayRows(): {}overlayRows() {
// Use this.cameraPos, not BT.camera: the engine calls this hook after render(),
// and render() ends with BT.cameraReset(), so BT.camera would read (0, 0) here.
this.Demo.overlayRowData: {}overlayRowData[1].leftText = `World size: ${this.Demo.worldWidth: numberworldWidth}x${this.Demo.worldHeight: numberworldHeight}`;
this.Demo.overlayRowData: {}overlayRowData[0].leftText = `Camera position: (${this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x}, ${this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y})`;
return this.Demo.overlayRowData: {}overlayRowData;
}
// Creates 20 buildings with random positions, sizes, and colors. Each building's
// color is registered in the palette and the slot number is stored on the building -
// this is why draw calls get numbers (slot indices) instead of Color32 objects.
Demo.generateBuildings(): voidgenerateBuildings() {
for (let let i: numberi = 0; let i: numberi < 20; let i: numberi++) {
// Each building gets its own palette slot starting at C_BUILDING_BASE (20).
const const colorIndex: numbercolorIndex = const C_BUILDING_BASE: 20C_BUILDING_BASE + let i: numberi;
// Give each building a slightly different blue-gray tint by randomizing R, G,
// and B. BT.random is the engine's shared random number generator. Its int()
// method gives a whole number from the first value up to (but not including)
// the second, so int(100, 200) can be 100, 101, ... 199 - but never 200.
const const r: numberr = 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.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.int(minOrMaxExclusive: number, maxExclusive?: number): numberReturns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).int(100, 200);
const const g: numberg = 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.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.int(minOrMaxExclusive: number, maxExclusive?: number): numberReturns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).int(100, 200);
const const b: numberb = 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.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.int(minOrMaxExclusive: number, maxExclusive?: number): numberReturns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).int(150, 250);
// Register this building's color in the palette at its reserved slot. Later,
// renderBuilding() passes colorIndex to BT.drawRectFill() instead of a
// Color32.
this.Demo.palette: Palette | nullpalette.Palette.set(index: number, color: Color32): voidWrites a color into a palette slot.set(const colorIndex: numbercolorIndex, new new Color32(r?: number, g?: number, b?: number, a?: number): Color32Creates a clamped 8-bit RGBA color.Color32(const r: numberr, const g: numberg, const b: numberb));
// Size first, then position, so the full rectangle stays inside the world.
// pointInRange() rolls both numbers of a Vector2i at once: x lands somewhere
// between the two x values we hand it, and y between the two y values. Here
// that means a width of 30-69 pixels and a height of 40-99.
const const size: Vector2isize = 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.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.pointInRange(min: Vector2i, max: Vector2i): Vector2iReturns a random integer point with each axis drawn from a half-open range.
Per axis uses
{@link
int
}
: `x` in `[min.x, max.x)`, `y` in `[min.y, max.y)`.pointInRange(new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(30, 40), new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(70, 100));
// Now the top-left corner. Stopping the range at "world size minus building
// size" guarantees the far edge of the building still fits on the map.
const const pos: Vector2ipos = const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.pointInRange(min: Vector2i, max: Vector2i): Vector2iReturns a random integer point with each axis drawn from a half-open range.
Per axis uses
{@link
int
}
: `x` in `[min.x, max.x)`, `y` in `[min.y, max.y)`.pointInRange(
new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(0, 0),
new new Vector2i(x?: number, y?: number): Vector2iCreates an integer 2D vector, truncating inputs toward zero.Vector2i(this.Demo.worldWidth: numberworldWidth - const size: Vector2isize.Vector2i.x: numberHorizontal component (defaults to 0).x, this.Demo.worldHeight: numberworldHeight - const size: Vector2isize.Vector2i.y: numberVertical component (defaults to 0).y),
);
this.Demo.buildings: {}buildings.push({
pos: Vector2ipos,
size: Vector2isize,
// Store the palette slot number, not a Color32 object. When drawing, we
// just pass this number to the draw call.
colorIndex: numbercolorIndex,
});
}
}
// Creates 50 trees at random positions across the entire world.
Demo.generateTrees(): voidgenerateTrees() {
// renderTree() draws the foliage as a 12x12 square centered on pos, sitting 16
// pixels above the ground point - so keep a 6-pixel side margin and a 16-pixel
// top margin.
const const treeMarginX: 6treeMarginX = 6;
const const treeMarginTop: 16treeMarginTop = 16;
// Describe the plantable area once as a rectangle: where it starts, and how wide
// and tall it is. Trimming the margins off each side keeps the foliage on the
// map.
const const treeArea: Rect2itreeArea = new new Rect2i(x?: number, y?: number, width?: number, height?: number): Rect2iCreates an integer rectangle, truncating all inputs toward zero.Rect2i(
const treeMarginX: 6treeMarginX,
const treeMarginTop: 16treeMarginTop,
this.Demo.worldWidth: numberworldWidth - const treeMarginX: 6treeMarginX * 2,
this.Demo.worldHeight: numberworldHeight - const treeMarginTop: 16treeMarginTop,
);
for (let let i: numberi = 0; let i: numberi < 50; let i: numberi++) {
this.Demo.trees: {}trees.push({
// insideRect() hands back a Vector2i somewhere inside that rectangle -
// like closing your eyes and pointing at a spot on a map.
pos: Vector2ipos: const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.random: RandomDefault engine PRNG (live reference - not a copy).
Time-seeded when the engine singleton is created. Call
{@link
BT.randomSeed
}
for a reproducible run, or open the page with `?seed=N` - applied in `BT.init()`
just before the demo's own `init()`, so a `randomSeed` call there still wins.
Mutating the instance (for example `BT.random.int(10)`) advances the shared stream.random.Random.insideRect(rect: Rect2i): Vector2iReturns a random integer point inside a rectangle (half-open, like
{@link
Rect2i.isContaining
}
).insideRect(const treeArea: Rect2itreeArea),
});
}
}
// Draws everything in the game world: the ground grid, the world border, trees,
// buildings, and the player. All of these are in world coordinates, so the camera
// offset applies.
Demo.renderWorld(): voidrenderWorld() {
// Draw a green grid over the ground.
this.Demo.renderGrid(): voidrenderGrid();
// Draw a red rectangle around the entire world boundary so you can see the edge.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(0, 0, this.Demo.worldWidth: numberworldWidth, this.Demo.worldHeight: numberworldHeight);
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, const C_WORLD_BORDER: 4C_WORLD_BORDER);
// Draw trees first so buildings appear on top of them.
for (const const tree: anytree of this.Demo.trees: {}trees) {
this.Demo.renderTree(pos: any): voidrenderTree(const tree: anytree.pos);
}
// Draw each building using its pre-stored palette slot.
for (const const building: anybuilding of this.Demo.buildings: {}buildings) {
this.Demo.renderBuilding(building: any): voidrenderBuilding(const building: anybuilding);
}
// Draw the player on top of everything else.
this.Demo.renderPlayer(): voidrenderPlayer();
}
// Draws a grid of green lines across the entire world. The grid helps you see that
// the world is larger than the visible screen.
Demo.renderGrid(): voidrenderGrid() {
const const gridSize: 40gridSize = 40; // lines every 40 pixels
// Draw vertical lines (top to bottom).
for (let let x: numberx = 0; let x: numberx < this.Demo.worldWidth: numberworldWidth; let x: numberx += const gridSize: 40gridSize) {
this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(let x: numberx, 0);
this.Demo.tempVec2: Vector2itempVec2.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(let x: numberx, this.Demo.worldHeight: numberworldHeight);
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => voidDraws a pixel-perfect line between two points.
Uses rasterized line drawing without antialiasing.drawLine(this.Demo.tempVec1: Vector2itempVec1, this.Demo.tempVec2: Vector2itempVec2, const C_GRID: 3C_GRID);
}
// Draw horizontal lines (left to right).
for (let let y: numbery = 0; let y: numbery < this.Demo.worldHeight: numberworldHeight; let y: numbery += const gridSize: 40gridSize) {
this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(0, let y: numbery);
this.Demo.tempVec2: Vector2itempVec2.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(this.Demo.worldWidth: numberworldWidth, let y: numbery);
const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.drawLine: (p0: Vector2i, p1: Vector2i, paletteIndex: number) => voidDraws a pixel-perfect line between two points.
Uses rasterized line drawing without antialiasing.drawLine(this.Demo.tempVec1: Vector2itempVec1, this.Demo.tempVec2: Vector2itempVec2, const C_GRID: 3C_GRID);
}
}
// Draws a single tree: a brown trunk below a green leafy top. `pos` is the
// center-bottom of the tree in world coordinates.
Demo.renderTree(pos: any): voidrenderTree(pos: anypos) {
// Brown trunk: 4 pixels wide, 8 pixels tall, centered on pos.x.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(pos: anypos.x - 2, pos: anypos.y - 8, 4, 8);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, const C_TRUNK: 5C_TRUNK);
// Green foliage: 12 pixels wide, 12 pixels tall, centered and above the trunk.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(pos: anypos.x - 6, pos: anypos.y - 16, 12, 12);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, const C_FOLIAGE: 6C_FOLIAGE);
// Darker green outline around the foliage.
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, const C_FOLIAGE_OUTLINE: 7C_FOLIAGE_OUTLINE);
}
// Draws a single building: a colored rectangle with a dark outline and small windows.
// The building's color is its colorIndex (a palette slot number), so no Color32
// object is created while drawing.
Demo.renderBuilding(building: any): voidrenderBuilding(building: anybuilding) {
// Draw the filled body of the building using its stored palette slot.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(building: anybuilding.pos.x, building: anybuilding.pos.y, building: anybuilding.size.x, building: anybuilding.size.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;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, building: anybuilding.colorIndex);
// Draw a dark outline around the building.
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, const C_BUILDING_OUTLINE: 8C_BUILDING_OUTLINE);
// Draw a grid of small windows inside the building: start 10 pixels from the top
// and 5 from the left, stop 10 from the bottom and 5 from the right, one window
// every 15 pixels.
for (let let y: numbery = 10; let y: numbery < building: anybuilding.size.y - 10; let y: numbery += 15) {
for (let let x: numberx = 5; let x: numberx < building: anybuilding.size.x - 5; let x: numberx += 15) {
// Each window is an 8x8 filled rectangle in the pale-yellow window color.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(building: anybuilding.pos.x + let x: numberx, building: anybuilding.pos.y + let y: numbery, 8, 8);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, const C_WINDOW: 9C_WINDOW);
}
}
}
// Draws the player as a red square with a darker red outline. It stays in the center
// of the world and does not move.
Demo.renderPlayer(): voidrenderPlayer() {
// Center the 16x16 square on playerPos by subtracting half the size (8).
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(this.Demo.playerPos: Vector2iplayerPos.Vector2i.x: numberHorizontal component (defaults to 0).x - 8, this.Demo.playerPos: Vector2iplayerPos.Vector2i.y: numberVertical component (defaults to 0).y - 8, 16, 16);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, const C_PLAYER: 10C_PLAYER);
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, const C_PLAYER_OUTLINE: 11C_PLAYER_OUTLINE);
}
// Draws the HUD (heads-up display) on top of the world. Everything here is in screen
// coordinates (not shifted by the camera). The same camera position and world size
// also appear in overlayRows() above the bottom FPS bar (see the Basics demo for the
// same pattern).
Demo.renderUI(): voidrenderUI() {
// The title panel is built with the shared UI kit. Every widget declared between
// ui.begin() and ui.end() stacks into one anchored group; the kit measures the
// rows, draws the panel background, and places it for us. The kit draws in
// whatever camera space is active, so this must run after BT.cameraReset() -
// otherwise the panel would scroll away with the world.
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT);
import uiui.panel();
import uiui.label('Auto-scrolling camera', { color: stringcolor: 'dim' });
// Key-value rows showing where the camera is looking right now and how big the
// world is, so you can watch the numbers change as the view drifts around.
import uiui.kv('Camera position:', `${this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x}, ${this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y}`);
import uiui.kv('World size: ', `${this.Demo.worldWidth: numberworldWidth}x${this.Demo.worldHeight: numberworldHeight}`);
import uiui.end();
// Draw the mini-map in the bottom-right corner.
this.Demo.renderMiniMap(): voidrenderMiniMap();
}
// Draws a small overview map showing the whole world scaled down. Buildings appear as
// dots, the visible screen area as a yellow box, and the player as a tiny red square.
Demo.renderMiniMap(): voidrenderMiniMap() {
// Position and size of the mini-map on screen.
const const mapX: 226mapX = 226;
const const mapY: 166mapY = 166;
const const mapW: 90mapW = 90;
const const mapH: 70mapH = 70;
// Background and border for the mini-map frame. The kit has no mini-map widget,
// so we draw this frame by hand - but we borrow the shared theme's panel and
// border slots so it matches the kit's look.
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(const mapX: 226mapX, const mapY: 166mapY, const mapW: 90mapW, const mapH: 70mapH);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, 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;
... 124 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, this.Demo.theme: nulltheme.border);
// Draw a dot for each building, scaled down to fit the mini-map. Dividing by the
// world width/height gives a fraction from 0.0 to 1.0; multiplying by the map
// width/height turns that fraction into mini-map pixels.
for (const const building: anybuilding of this.Demo.buildings: {}buildings) {
const const miniX: anyminiX = const mapX: 226mapX + Math.floor((const building: anybuilding.pos.x / this.Demo.worldWidth: numberworldWidth) * const mapW: 90mapW);
const const miniY: anyminiY = const mapY: 166mapY + Math.floor((const building: anybuilding.pos.y / this.Demo.worldHeight: numberworldHeight) * const mapH: 70mapH);
this.Demo.tempVec1: Vector2itempVec1.Vector2i.set(x: number, y: number): Vector2iSets both components of this vector.
Modifies this vector directly for maximum performance.
WARNING: Mutates this vector. Don't use on frozen/cached singletons.set(const miniX: anyminiX, const miniY: anyminiY);
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.drawPixel: (posOrX: Vector2i | number, yOrColor: number, maybeColor?: number) => voidDraws a single pixel.
Accepts either:
- `(posOrX: Vector2i, yOrColor: number)` where `yOrColor` is the palette index.
- `(posOrX: number, yOrColor: number, maybeColor: number)` for `(x, y, paletteIndex)`.drawPixel(this.Demo.tempVec1: Vector2itempVec1, const C_BUILDING_DOT: 16C_BUILDING_DOT);
}
// Draw a yellow rectangle showing the visible area (the camera viewport).
const const displaySize: Vector2idisplaySize = 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.displaySize: Vector2iActive logical render resolution in pixels.
This is the game/simulation coordinate space configured by the demo, not
the canvas element's CSS size. Each read returns a clone.displaySize;
const const viewX: anyviewX = const mapX: 226mapX + Math.floor((this.Demo.cameraPos: Vector2icameraPos.Vector2i.x: numberHorizontal component (defaults to 0).x / this.Demo.worldWidth: numberworldWidth) * const mapW: 90mapW);
const const viewY: anyviewY = const mapY: 166mapY + Math.floor((this.Demo.cameraPos: Vector2icameraPos.Vector2i.y: numberVertical component (defaults to 0).y / this.Demo.worldHeight: numberworldHeight) * const mapH: 70mapH);
const const viewW: anyviewW = Math.floor((const displaySize: Vector2idisplaySize.Vector2i.x: numberHorizontal component (defaults to 0).x / this.Demo.worldWidth: numberworldWidth) * const mapW: 90mapW);
const const viewH: anyviewH = Math.floor((const displaySize: Vector2idisplaySize.Vector2i.y: numberVertical component (defaults to 0).y / this.Demo.worldHeight: numberworldHeight) * const mapH: 70mapH);
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(const viewX: anyviewX, const viewY: anyviewY, const viewW: anyviewW, const viewH: anyviewH);
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.drawRect: (rect: Rect2i, paletteIndex: number) => voidDraws an unfilled rectangle outline.drawRect(this.Demo.tempRect: Rect2itempRect, const C_VIEWPORT: 17C_VIEWPORT);
// Draw the player position as a small red square on the mini-map.
const const playerMiniX: anyplayerMiniX = const mapX: 226mapX + Math.floor((this.Demo.playerPos: Vector2iplayerPos.Vector2i.x: numberHorizontal component (defaults to 0).x / this.Demo.worldWidth: numberworldWidth) * const mapW: 90mapW);
const const playerMiniY: anyplayerMiniY = const mapY: 166mapY + Math.floor((this.Demo.playerPos: Vector2iplayerPos.Vector2i.y: numberVertical component (defaults to 0).y / this.Demo.worldHeight: numberworldHeight) * const mapH: 70mapH);
this.Demo.tempRect: Rect2itempRect.Rect2i.set(x: number, y: number, width: number, height: number): Rect2iSets all components of this rectangle.
Modifies this rectangle directly for maximum performance.
WARNING: Mutates this rectangle. Don't use on frozen/cached singletons.set(const playerMiniX: anyplayerMiniX - 1, const playerMiniY: anyplayerMiniY - 1, 2, 2);
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.drawRectFill: (rect: Rect2i, paletteIndex: number) => voidDraws a filled rectangle.drawRectFill(this.Demo.tempRect: Rect2itempRect, const C_PLAYER: 10C_PLAYER);
}
}
// 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);