// Camera: shows how to scroll a view over a world larger than the screen.
// @description Scroll a camera over a world larger than the screen, and convert between world and screen space.
//
// Prerequisites: We learned about drawing and the game loop in Basics demo
// (https://demos.blit386.dev/basics) and shapes in Primitives demo
// (https://demos.blit386.dev/primitives).
//
// Guide: https://blit386.dev/docs/api/camera
//
// How BT.cameraSet() works: a positive camera offset shifts the view to the right, so the
// world appears to scroll left on the screen. A positive X offset means the camera is
// looking that many pixels to the right of the world's left edge - for example, an X
// offset of 200 shows the world starting 200 pixels in from the left (like the camera
// moved 200 steps east along the map).
//
// Imagine looking through a window: the window doesn't move, but you can shift
// what part of the outside world you see through it. That's exactly what a camera
// does in a game. The "camera" here is just an offset - how far we've scrolled
// the view to the right and down.
//
// This demo creates a 800x600 pixel world (bigger than the 320x240 screen),
// fills it with random buildings and trees, then automatically scrolls the camera
// along a smooth looping path (Lissajous-style motion from sine and cosine) so you can see
// more of the world.
//
// It also shows a mini-map in the corner that shows where in the world we currently are.
// The title panel in the top-left corner is drawn with the shared UI kit (src/shared/ui.js),
// so it looks the same as the info panels in every other demo.
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';
import { import applyThemeapplyTheme, import uiui, import UI_ANCHORSUI_ANCHORS } from './shared/ui.js';
/** @typedef {import('blit386').IBTDemo} IBTDemo */
/** @typedef {import('blit386').HardwareSettings} HardwareSettings */
/** @typedef {import('blit386').Palette} Palette */
// Every color in this demo is pre-registered in a numbered palette slot.
// Index 0 is always transparent. Custom colors start at 1.
// We separate static colors (fixed forever) from building colors (20 random ones).
// UI chrome (the title panel and the mini-map frame) uses the shared UI kit theme
// instead, which applyTheme() installs into high palette slots (240 and up).
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 index 20..39.
// We define the base index here so the code stays easy to read.
const const C_BUILDING_BASE: 20C_BUILDING_BASE = 20; // building 0 is at index 20, building 1 at 21, and so on
/**
* Demonstrates camera scrolling with a procedurally generated city.
* Buildings and trees are randomly placed; the camera automatically scrolls.
*
* @implements {IBTDemo}
*/
class class DemoDemonstrates camera scrolling with a procedurally generated city.
Buildings and trees are randomly placed; the camera automatically scrolls.Demo {
// 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 this
// tick's sine/cosine math moved it. render() blends between cameraPrevPos and
// cameraPos using BT.renderAlpha so the camera pans smoothly between physics ticks
// instead of jumping - see "Interpolating render state with renderAlpha" in the
// engine's docs/api-game-loop.md.
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 render-time (interpolated) camera position,
// so we do not allocate a new Vector2i every 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);
// Arrays that store the randomly generated world objects.
// Each building has a position, size, and a palette colorIndex number.
// 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 + world size).
// We keep one array and update the text strings in place so we do not
// allocate new objects on every 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 },
];
// These objects are reused every frame instead of creating new ones in the draw loop.
// Reusing objects is faster because the browser doesn't have to reclaim 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 at the very start. Tells the engine which palette slots to use
* for the overlay bars (FPS strip, demo title, and custom debug rows).
*
* The palette grid shows 32 swatches per row and 2 visible rows (64 colors at
* a time); scroll the band to browse the rest of the 256-slot palette.
*
* @returns {Partial<HardwareSettings>}
*/
Demo.configure(): Partial<HardwareSettings>Called once at the very start. Tells the engine which palette slots to use
for the overlay bars (FPS strip, demo title, and custom debug rows).
The palette grid shows 32 swatches per row and 2 visible rows (64 colors at
a time); scroll the band to browse the rest of the 256-slot palette.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.
*
* @returns {Promise<boolean>} Returns true when ready to run.
*/
async Demo.init(): Promise<boolean>Runs once when the demo starts. Sets up the palette and generates random
buildings and trees to fill the world.init() {
// Set up the color palette
// Think of a palette like an artist choosing paint colors before painting a picture.
// Every color we might draw with gets a numbered slot. We set the static colors
// first, then add the 20 random building colors when we generate the buildings.
this.Demo.palette: Palette | nullpalette = const BT: {
FLIP_H: number;
FLIP_V: number;
ROT_90_CW: number;
ROT_180_CW: number;
ROT_270_CW: number;
BTN_UP: number;
BTN_DOWN: number;
BTN_LEFT: number;
BTN_RIGHT: number;
BTN_A: number;
BTN_B: number;
BTN_X: number;
BTN_Y: number;
BTN_L: number;
BTN_R: number;
BTN_START: number;
BTN_SELECT: number;
BTN_POINTER_A: number;
BTN_POINTER_B: number;
BTN_POINTER_C: number;
BTN_POINTER_D: number;
PLAYER_ONE: number;
PLAYER_TWO: number;
PLAYER_THREE: number;
PLAYER_FOUR: number;
AXIS_LEFT_X: number;
AXIS_LEFT_Y: number;
AXIS_RIGHT_X: number;
AXIS_RIGHT_Y: number;
AXIS_TRIGGER_L: number;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.paletteCreate: (size?: number) => PaletteCreates a standalone palette instance.paletteCreate(256);
// Static colors - these are the same every time the demo runs.
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)); // sky blue background
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)); // medium green for the ground grid
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)); // red world boundary rectangle
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)); // warm brown tree trunk
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)); // green tree leaves
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)); // darker green leaf outline
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)); // near-black building border
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)); // pale yellow semi-transparent window
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)); // salmon red player fill
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)); // darker red player outline
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)); // blue-gray dots on mini-map
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)); // yellow viewport box on mini-map
// 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)); // dark bar behind custom overlay rows
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)); // camera position line
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)); // world size line
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)); // gray gap between overlay rows
// Install the shared UI kit theme. applyTheme() writes twelve UI colors into
// high palette slots (240 and up), far above this demo's scene slots (1..42),
// 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;
... 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);
// Generate buildings AFTER the palette is set up.
// generateBuildings() adds 20 random colors to the palette (slots 20..39)
// and stores the slot index on each building instead of a Color32 object.
this.Demo.generateBuildings(): voidCreates 20 buildings with random positions, sizes, and colors.
Each building color is registered in the palette and the index is stored on the building.
This is why we pass numbers (indices) to draw calls instead of Color32 objects.generateBuildings();
this.Demo.generateTrees(): voidCreates 50 trees at random positions across the entire world.generateTrees();
return true;
}
/**
* Runs at a fixed rate (60 times per second) to move the camera.
* The camera follows a smooth sinusoidal (wave-like) path through the world.
* In a real game you would move the camera based on player input instead.
*/
Demo.update(): voidRuns at a fixed rate (60 times per second) to move the camera.
The camera follows a smooth sinusoidal (wave-like) path through the world.
In a real game you would move the camera based on player input instead.update() {
// Remember where the camera was before this tick's math moves it, so render()
// has an "old" and "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 increases slowly each tick, driving the sinusoidal movement.
// Multiplying ticks by 0.02 makes 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;
... 106 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 or 150 keeps the camera away from the very 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 doesn't scroll past the edges of the world.
// The right edge is worldWidth minus the screen width, because we don't want
// the screen to show empty space past 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;
... 106 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;
... 106 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() now happens in render(), using a position blended between
// cameraPrevPos and cameraPos - see renderWorld() below.
}
/**
* Runs once per screen refresh to draw the world and the UI overlay.
*
* Important: anything drawn BEFORE BT.cameraReset() is offset by the camera.
* Anything drawn AFTER BT.cameraReset() is drawn in screen coordinates (no offset).
*/
Demo.render(): voidRuns once per screen refresh to draw the world and the UI overlay.
Important: anything drawn BEFORE BT.cameraReset() is offset by the camera.
Anything drawn AFTER BT.cameraReset() is drawn in screen coordinates (no offset).render() {
// 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;
... 106 more ...;
spritesRefresh: () => void;
}
Main BLIT386 API namespace used by runtime demos.BT.clear: (paletteIndex: number) => voidSets the frame clear color using a palette index.
The renderer uses this color when clearing the full display at the start
of the next frame.clear(const C_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;
... 106 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;
... 106 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;
... 106 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 (trees, buildings, player).
// These are offset by the camera, so they appear to scroll.
this.Demo.renderWorld(): voidDraws everything in the game world: the ground grid, trees, buildings, and player.
All of these are drawn in world coordinates, so the camera offset applies.renderWorld();
// Reset the camera so the UI (text, mini-map) stays fixed on screen.
// Without this, the UI would scroll away when the camera moves.
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.cameraReset: () => voidResets the global camera offset to `(0, 0)`.cameraReset();
// Draw the UI overlay (title, camera position, mini-map).
// These are drawn in screen coordinates, so they never move.
this.Demo.renderUI(): voidDraws the HUD (heads-up display) overlaid on the screen.
Camera position and world size are shown in overlayRows() above the bottom
FPS bar (see the Basics demo for the same pattern).
Everything here is in screen coordinates (not offset by the camera).renderUI();
}
/**
* Optional hook: tells the engine what extra lines to draw in the overlay.
*
* The overlay is the thin bars at the top and bottom (FPS, demo title, etc.).
* Custom rows stack upward from just above the bottom FPS bar. Colors come from
* palette slots we set in init() and from configure().overlayStyle.
* We return the same overlayRowData array every time and only change the text.
*
* @returns {readonly { leftText: string }[]}
*/
Demo.overlayRows(): readonly {
leftText: string;
}[]
Optional hook: tells the engine what extra lines to draw in the overlay.
The overlay is the thin bars at the top and bottom (FPS, demo title, etc.).
Custom rows stack upward from just above the bottom FPS bar. Colors come from
palette slots we set in init() and from configure().overlayStyle.
We return the same overlayRowData array every time and only change the text.overlayRows() {
// Use this.cameraPos, not BT.camera: the engine calls this hook after render(),
// and we call BT.cameraReset() at the end of render() so screen UI stays fixed.
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 color is registered in the palette and the index is stored on the building.
* This is why we pass numbers (indices) to draw calls instead of Color32 objects.
*/
Demo.generateBuildings(): voidCreates 20 buildings with random positions, sizes, and colors.
Each building color is registered in the palette and the index is stored on the building.
This is why we pass numbers (indices) to draw calls instead of Color32 objects.generateBuildings() {
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, 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;
... 106 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. 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;
... 106 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. 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;
... 106 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. 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, render() will pass 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 place so the full rectangle stays inside the world.
// pointInRange() rolls both numbers of a Vector2i at once: the x lands somewhere between the two x values
// we hand it, and the y between the two y values we hand it.
// 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;
... 106 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. 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;
... 106 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. 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 index 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(): voidCreates 50 trees at random positions across the entire world.generateTrees() {
// renderTree() draws foliage as a 12x12 square centered on pos, sitting 16 px above
// the ground point - so keep a 6 px side margin and a 16 px 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-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;
... 106 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. 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, trees, buildings, and player.
* All of these are drawn in world coordinates, so the camera offset applies.
*/
Demo.renderWorld(): voidDraws everything in the game world: the ground grid, trees, buildings, and player.
All of these are drawn in world coordinates, so the camera offset applies.renderWorld() {
// Draw a green grid over the ground.
this.Demo.renderGrid(): voidDraws a grid of green lines across the entire world.
The grid helps you see that the world is larger than the visible screen.renderGrid();
// 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;
... 106 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: Vector2i): voidDraws a single tree: a brown trunk below a green leafy top.renderTree(const tree: anytree.pos);
}
// Draw each building using its pre-stored palette color index.
for (const const building: anybuilding of this.Demo.buildings: {}buildings) {
this.Demo.renderBuilding(building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}): void
Draws a single building: a colored rectangle with a dark outline and small windows.
The building's color is identified by its colorIndex (a palette slot number),
so no Color32 object is created during drawing.renderBuilding(const building: anybuilding);
}
// Draw the player on top of everything else.
this.Demo.renderPlayer(): voidDraws the player as a red square with a darker red outline.
It stays in the center of the world and doesn't move.renderPlayer();
}
/**
* 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(): voidDraws a grid of green lines across the entire world.
The grid helps you see that the world is larger than the visible screen.renderGrid() {
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;
... 106 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;
... 106 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.
*
* @param {Vector2i} pos - The center-bottom of the tree in world coordinates.
*/
Demo.renderTree(pos: Vector2i): voidDraws a single tree: a brown trunk below a green leafy top.renderTree(pos: Vector2i- The center-bottom of the tree in world coordinates.pos) {
// 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: Vector2i- The center-bottom of the tree in world coordinates.pos.Vector2i.x: numberHorizontal component (defaults to 0).x - 2, pos: Vector2i- The center-bottom of the tree in world coordinates.pos.Vector2i.y: numberVertical component (defaults to 0).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;
... 106 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: Vector2i- The center-bottom of the tree in world coordinates.pos.Vector2i.x: numberHorizontal component (defaults to 0).x - 6, pos: Vector2i- The center-bottom of the tree in world coordinates.pos.Vector2i.y: numberVertical component (defaults to 0).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;
... 106 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;
... 106 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 identified by its colorIndex (a palette slot number),
* so no Color32 object is created during drawing.
*
* @param {{pos: Vector2i, size: Vector2i, colorIndex: number}} building - The building data.
*/
Demo.renderBuilding(building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}): void
Draws a single building: a colored rectangle with a dark outline and small windows.
The building's color is identified by its colorIndex (a palette slot number),
so no Color32 object is created during drawing.renderBuilding(building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building) {
// Draw the filled body of the building using its stored palette index.
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: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.pos: Vector2ipos.Vector2i.x: numberHorizontal component (defaults to 0).x, building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.pos: Vector2ipos.Vector2i.y: numberVertical component (defaults to 0).y, building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.size: Vector2isize.Vector2i.x: numberHorizontal component (defaults to 0).x, building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.size: Vector2isize.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;
... 106 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: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.colorIndex: numbercolorIndex);
// 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;
... 106 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, stop 10 from the bottom, space every 15 pixels.
for (let let y: numbery = 10; let y: numbery < building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.size: Vector2isize.Vector2i.y: numberVertical component (defaults to 0).y - 10; let y: numbery += 15) {
for (let let x: numberx = 5; let x: numberx < building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.size: Vector2isize.Vector2i.x: numberHorizontal component (defaults to 0).x - 5; let x: numberx += 15) {
// Each window is an 8x8 filled rectangle with 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: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.pos: Vector2ipos.Vector2i.x: numberHorizontal component (defaults to 0).x + let x: numberx, building: {
pos: Vector2i;
size: Vector2i;
colorIndex: number;
}
- The building data.building.pos: Vector2ipos.Vector2i.y: numberVertical component (defaults to 0).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;
... 106 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 doesn't move.
*/
Demo.renderPlayer(): voidDraws the player as a red square with a darker red outline.
It stays in the center of the world and doesn't move.renderPlayer() {
// 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;
... 106 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;
... 106 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) overlaid on the screen.
* Camera position and world size are shown in overlayRows() above the bottom
* FPS bar (see the Basics demo for the same pattern).
* Everything here is in screen coordinates (not offset by the camera).
*/
Demo.renderUI(): voidDraws the HUD (heads-up display) overlaid on the screen.
Camera position and world size are shown in overlayRows() above the bottom
FPS bar (see the Basics demo for the same pattern).
Everything here is in screen coordinates (not offset by the camera).renderUI() {
// 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(): voidDraws a small overview map showing the whole world scaled down.
Buildings appear as dots. The visible screen area is shown as a yellow box.
The player is shown as a tiny red square.renderMiniMap();
}
/**
* Draws a small overview map showing the whole world scaled down.
* Buildings appear as dots. The visible screen area is shown as a yellow box.
* The player is shown as a tiny red square.
*/
Demo.renderMiniMap(): voidDraws a small overview map showing the whole world scaled down.
Buildings appear as dots. The visible screen area is shown as a yellow box.
The player is shown as a tiny red square.renderMiniMap() {
// 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 panel by hand - but we borrow the shared theme's
// panel and border slots so it matches the kit's look exactly.
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;
... 106 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;
... 106 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.
// We divide by worldWidth/Height to get a 0.0-1.0 fraction, then multiply
// by mapW/H to convert to 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;
... 106 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;
... 106 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;
... 106 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;
... 106 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 DemoDemonstrates camera scrolling with a procedurally generated city.
Buildings and trees are randomly placed; the camera automatically scrolls.Demo);