/**
 * Synth Toy Demo - procedural chip-tune sound effects with no audio files at all.
 * @description Procedural chip-tune sound effects with no audio files: six presets plus a key that rolls a new one.
 *
 * Prerequisites:
 *   Keyboard Input  https://demos.blit386.dev/keyboard-input
 *   Audio Basics    https://demos.blit386.dev/audio-basics
 *
 * Live version: https://demos.blit386.dev/synth-toy
 *
 * Every sound on this page is built from scratch by the computer, the instant you press a
 * key or tap a button - there are no sound files to download. AudioClip.synth() takes a
 * small recipe called SynthParams (a waveform shape, a pitch, a length, and a few optional
 * knobs like an attack/decay/sustain/release envelope, a pitch sweep, and a noise mix) and
 * calculates every single sample of the resulting sound on the spot. BT.synthPreset bundles
 * six of these recipes for common game sounds - jump, pickup, explosion, laser, hit, and a
 * UI blip - tuned by hand so they sound right without you needing to pick every number
 * yourself.
 *
 * The Randomize button goes the other way: instead of a hand-tuned recipe, it rolls a brand
 * new SynthParams object with every field chosen at random, inside safe ranges, and shows
 * you exactly what was rolled in the right-hand panel. Play it a few times and you will
 * hear (and see) how much variety a handful of numbers can produce - from a clean sine
 * "boop" to a noisy sawtooth growl. (The synth engine also supports a vibrato wobble on top
 * of all this - this demo leaves it out to keep the panel small, but it is worth trying
 * yourself.)
 *
 * The panels and buttons come from the shared UI kit in src/shared/ui.js, so every preset
 * works three ways: click it, tap it on a phone, or press its keyboard shortcut.
 *
 * This page unlocks sound the same "click or press a key first" way audio-basics does -
 * browsers refuse to make any sound until you interact with the page at least once.
 *
 * The engine's built-in overlay also shows live audio meters: little bars that move
 * up and down with how loud each audio bus (main, music, sfx) is right now, plus a
 * count of how many sounds are playing at once. This demo turns that feature on with
 * `isOverlayAudioMetersEnabled: true` in configure() - watch the meters jump every time a
 * preset or a randomized sound plays.
 *
 * Try this:
 * - Click anywhere, or press any key, to unlock sound - watch the message at the top change
 *   once you do.
 * - Tap the preset buttons (or press J, P, E, L, H, or B) to hear the jump, pickup,
 *   explosion, laser, hit, and blip presets.
 * - Tap Randomize (or press R) to hear a randomized sound - watch the right-hand panel
 *   update with the waveform, frequency, duration, noise mix, and pitch sweep target that
 *   were rolled.
 * - Randomize again and again - notice how differently the exact same few lines of "roll a
 *   random number" code can make the engine sound each time.
 */

import { class AudioClip
Decoded audio asset with its winning source URL and buffer-derived metadata. Construct instances with {@link AudioClip.load } , {@link AudioClip.loadAll } , or {@link AudioClip.synth } ; there is no public constructor.
@since1.3.0
AudioClip
, 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.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
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
} from 'blit386';
import { import applyThemeapplyTheme, import THEME_DEFAULT_START_SLOTTHEME_DEFAULT_START_SLOT, import uiui, import UI_ANCHORSUI_ANCHORS } from './shared/ui.js'; /** @typedef {import('blit386').IBTDemo} IBTDemo */ /** @typedef {import('blit386').Palette} Palette */ /** @typedef {import('blit386').SynthParams} SynthParams */ /** @typedef {import('blit386').HardwareSettings} HardwareSettings */ // The waveform shapes AudioClip.synth() accepts. The engine does not export this list as a // runtime value (only as a TypeScript type), so we spell it out here ourselves - the // randomizer picks one of these five names at random for every roll. const const SYNTH_WAVEFORMS: {}SYNTH_WAVEFORMS = ['sine', 'square', 'triangle', 'sawtooth', 'noise']; // One entry per preset. Each `factory` asks BT.synthPreset for a fresh, hand-tuned recipe // (a SynthParams object) for that sound. `label` is the button text (which doubles as the // keyboard hint), and `code` is the bound key. const const PRESET_DEFINITIONS: {}PRESET_DEFINITIONS = [ { code: stringcode: 'KeyJ', label: stringlabel: 'J - Jump', name: stringname: 'Jump', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.jump: (seed?: number) => SynthParams
Platformer jump: a short square-wave tone that sweeps upward in pitch, like a classic arcade jump cue. `seed` jitters the base frequency (+/-8%) and duration (+/-12%), so jumping repeatedly doesn't sound identical every time. Omit `seed` (or pass {@link DEFAULT_PRESET_SEED } ) for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for a jump sound effect.
jump
() },
{ code: stringcode: 'KeyP', label: stringlabel: 'P - Pickup', name: stringname: 'Pickup', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.pickup: (seed?: number) => SynthParams
Item pickup / coin: a short, bright square-wave blip that sweeps upward an octave. `seed` jitters the base frequency (+/-8%) and duration (+/-12%). Omit `seed` for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for a pickup sound effect.
pickup
() },
{ code: stringcode: 'KeyE', label: stringlabel: 'E - Explosion', name: stringname: 'Explosion', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.explosion: (seed?: number) => SynthParams
Explosion: a low sawtooth rumble mixed heavily with noise, with a slow decay and release for a boom that lingers. `seed` jitters the base frequency (+/-8%), duration (+/-12%), and `noiseMix` (+/-10%, clamped to `[0, 1]`) - the mix jitter alone gives every explosion a distinct noisy texture. Omit `seed` for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for an explosion sound effect.
explosion
() },
{ code: stringcode: 'KeyL', label: stringlabel: 'L - Laser', name: stringname: 'Laser', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.laser: (seed?: number) => SynthParams
Laser / sci-fi zap: a bright sawtooth tone that sweeps rapidly downward in pitch. `seed` jitters the base frequency (+/-8%) and duration (+/-12%). Omit `seed` for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for a laser sound effect.
laser
() },
{ code: stringcode: 'KeyH', label: stringlabel: 'H - Hit', name: stringname: 'Hit', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.hit: (seed?: number) => SynthParams
Hit / damage taken: a short, low percussive tone mixed with noise for a punchy impact. `seed` jitters the base frequency (+/-8%) and `noiseMix` (+/-10%, clamped to `[0, 1]`). Omit `seed` for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for a hit sound effect.
hit
() },
{ code: stringcode: 'KeyB', label: stringlabel: 'B - Blip', name: stringname: 'Blip', factory: () => SynthParamsfactory: () =>
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
.
synthPreset: {
    jump: (seed?: number) => SynthParams;
    pickup: (seed?: number) => SynthParams;
    explosion: (seed?: number) => SynthParams;
    laser: (seed?: number) => SynthParams;
    hit: (seed?: number) => SynthParams;
    blip: (seed?: number) => SynthParams;
}
Pre-configured `SynthParams` presets for common sound effects ("jump", "pickup", "explosion", "laser", "hit", "blip"). Each function returns a fresh {@link SynthParams } object; pass it to {@link AudioClip.synth } to render a clip, then play the result via {@link BT.soundPlay } . An optional `seed` argument applies small, bounded, deterministic jitter to a few hand-picked fields per preset, so repeated plays vary without losing reproducibility - the same seed always renders the exact same variant.
@since1.3.0@exampleconst jumpClip = await AudioClip.synth(BT.synthPreset.jump()); BT.soundPlay(jumpClip);
synthPreset
.blip: (seed?: number) => SynthParams
UI blip / menu select: a very short, clean sine tone. `seed` jitters only the base frequency, and only slightly (+/-3%) - UI feedback should stay recognizably consistent rather than vary as much as a gameplay sound effect. Omit `seed` for a fixed baseline variant.
@paramseed - Seed for deterministic jitter. Defaults to {@link DEFAULT_PRESET_SEED }.@returnsA fresh `SynthParams` for a UI blip sound effect.
blip
() },
]; // All preset buttons share one width so the left panel reads as a tidy keypad. const const PRESET_BUTTON_W: 96PRESET_BUTTON_W = 96; // Safe ranges for the randomizer. Every one of these stays inside the bounds // AudioClip.synth() actually accepts (see blit386's synthValidation.ts): frequencies and // durations above zero, everything described as a fraction kept between 0 and 1. const const RANDOM_FREQUENCY_MIN_HZ: 80RANDOM_FREQUENCY_MIN_HZ = 80; const const RANDOM_FREQUENCY_MAX_HZ: 1200RANDOM_FREQUENCY_MAX_HZ = 1200; const const RANDOM_DURATION_MIN_S: 0.05RANDOM_DURATION_MIN_S = 0.05; const const RANDOM_DURATION_MAX_S: 1RANDOM_DURATION_MAX_S = 1.0; const const RANDOM_VOLUME_MIN: 0.8RANDOM_VOLUME_MIN = 0.8; const const RANDOM_VOLUME_MAX: 1RANDOM_VOLUME_MAX = 1.0; const const RANDOM_ATTACK_MAX_S: 0.1RANDOM_ATTACK_MAX_S = 0.1; const const RANDOM_DECAY_MAX_S: 0.3RANDOM_DECAY_MAX_S = 0.3; const const RANDOM_RELEASE_MIN_S: 0.02RANDOM_RELEASE_MIN_S = 0.02; const const RANDOM_RELEASE_MAX_S: 0.4RANDOM_RELEASE_MAX_S = 0.4; // A pitch sweep (the sound's pitch gliding from its starting frequency to a new one) is only // added to the random recipe about half the time, so you get to compare "sweeps" against // "flat pitch" sounds. const const RANDOM_PITCH_SWEEP_CHANCE: 0.5RANDOM_PITCH_SWEEP_CHANCE = 0.5; const const RANDOM_PITCH_SWEEP_MIN_MULTIPLIER: 0.3RANDOM_PITCH_SWEEP_MIN_MULTIPLIER = 0.3; const const RANDOM_PITCH_SWEEP_MAX_MULTIPLIER: 3RANDOM_PITCH_SWEEP_MAX_MULTIPLIER = 3.0; // Upper bound for the random seed handed to AudioClip.synth(). This seed only feeds the // engine's internal noise generator - it is not something we need to remember or reproduce // here, so any number in this range works. const const RANDOM_SEED_MAX: 1000000RANDOM_SEED_MAX = 1_000_000; /** * Builds a brand new SynthParams recipe with every field chosen at random, inside the safe * ranges above. Unlike the six named presets (which only nudge a couple of fields), this * touches every knob AudioClip.synth() understands, so pressing Randomize is a tour of the * whole parameter space rather than a small variation on one sound. * * @returns {SynthParams} */ function function buildRandomSynthParams(): SynthParams
Builds a brand new SynthParams recipe with every field chosen at random, inside the safe ranges above. Unlike the six named presets (which only nudge a couple of fields), this touches every knob AudioClip.synth() understands, so pressing Randomize is a tour of the whole parameter space rather than a small variation on one sound.
@returns
buildRandomSynthParams
() {
// BT.random is the engine's shared random number generator. pick() draws one item out of a list, float() // returns a decimal between two values, bool() flips a weighted coin, and next() gives a plain decimal from // 0 up to (but not including) 1 - which is exactly the range these normalized knobs want. const const waveform: anywaveform =
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.pick<any>(arr: readonly any[]): any
Returns one element chosen uniformly from a non-empty array.
@paramarr - Array to pick from; must contain at least one element.@returnsChosen element.@since1.5.0
pick
(const SYNTH_WAVEFORMS: {}SYNTH_WAVEFORMS);
const const frequency: numberfrequency =
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(const RANDOM_FREQUENCY_MIN_HZ: 80RANDOM_FREQUENCY_MIN_HZ, const RANDOM_FREQUENCY_MAX_HZ: 1200RANDOM_FREQUENCY_MAX_HZ);
const const duration: numberduration =
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(const RANDOM_DURATION_MIN_S: 0.05RANDOM_DURATION_MIN_S, const RANDOM_DURATION_MAX_S: 1RANDOM_DURATION_MAX_S);
const const hasPitchSweep: booleanhasPitchSweep =
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.bool(probability?: number): boolean
Returns true with the given probability.
@paramprobability - Chance in [0, 1]; defaults to 0.5.@returnsTrue when the next unit float is less than `probability`.@since1.5.0
bool
(const RANDOM_PITCH_SWEEP_CHANCE: 0.5RANDOM_PITCH_SWEEP_CHANCE);
return { SynthParams.waveform: any
Oscillator waveform shape.
waveform
,
SynthParams.frequency: number
Base carrier frequency in Hz at the start of the clip (before any pitch sweep or vibrato).
frequency
,
SynthParams.duration: number
Total clip duration in seconds. Must be greater than 0 and no more than {@link MAX_SYNTH_DURATION_SECONDS } .
duration
,
SynthParams.volume?: number | undefined
Overall output amplitude in [0, 1] (unclamped on the high end; final output is always clamped to avoid clipping). Defaults to {@link DEFAULT_VOLUME } .
volume
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(const RANDOM_VOLUME_MIN: 0.8RANDOM_VOLUME_MIN, const RANDOM_VOLUME_MAX: 1RANDOM_VOLUME_MAX),
SynthParams.envelope?: SynthEnvelope | undefined
Optional attack/decay/sustain/release envelope. Defaults to a full ADSR envelope; see {@link SynthEnvelope } .
envelope
: {
SynthEnvelope.attack?: number | undefined
Time in seconds to ramp from silence to full amplitude. Defaults to {@link DEFAULT_ATTACK } .
attack
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(0, const RANDOM_ATTACK_MAX_S: 0.1RANDOM_ATTACK_MAX_S),
SynthEnvelope.decay?: number | undefined
Time in seconds to fall from full amplitude to the `sustain` level. Defaults to {@link DEFAULT_DECAY } .
decay
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(0, const RANDOM_DECAY_MAX_S: 0.3RANDOM_DECAY_MAX_S),
SynthEnvelope.sustain?: number | undefined
Gain level in [0, 1] held between the decay and release phases. Defaults to {@link DEFAULT_SUSTAIN } .
sustain
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.next(): number
Returns the next pseudo-random float in [0, 1).
@returnsNext value in the deterministic sequence.@since1.5.0
next
(),
SynthEnvelope.release?: number | undefined
Time in seconds to fall from the sustain level to silence at the end of the clip. Defaults to {@link DEFAULT_RELEASE } .
release
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(const RANDOM_RELEASE_MIN_S: 0.02RANDOM_RELEASE_MIN_S, const RANDOM_RELEASE_MAX_S: 0.4RANDOM_RELEASE_MAX_S),
}, SynthParams.noiseMix?: number | undefined
Fraction of white noise mixed into the oscillator output, in [0, 1] (`0` is pure tone, `1` is pure noise). Ignored when `waveform` is already `'noise'`. Defaults to {@link DEFAULT_NOISE_MIX } .
noiseMix
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.next(): number
Returns the next pseudo-random float in [0, 1).
@returnsNext value in the deterministic sequence.@since1.5.0
next
(),
SynthParams.dutyCycle?: number | undefined
Fraction of each cycle spent high, in [0, 1]. Only affects the `'square'` waveform. Defaults to {@link DEFAULT_DUTY_CYCLE } .
dutyCycle
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.next(): number
Returns the next pseudo-random float in [0, 1).
@returnsNext value in the deterministic sequence.@since1.5.0
next
(),
SynthParams.seed: number
Seed for the deterministic PRNG driving noise generation - identical seeds render identical output.
seed
:
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.int(minOrMaxExclusive: number, maxExclusive?: number): number
Returns a pseudo-random integer in [0, maxExclusive) or [min, maxExclusive).
@paramminOrMaxExclusive - When alone, exclusive upper bound from 0; otherwise inclusive min.@parammaxExclusive - Exclusive upper bound when two arguments are passed.@returnsWhole number in the half-open range.@since1.5.0
int
(const RANDOM_SEED_MAX: 1000000RANDOM_SEED_MAX),
// Only glide the pitch about half the time, and only when we do, add the field at // all - AudioClip.synth() treats a missing pitchSweep as "stay at one pitch." ...(const hasPitchSweep: booleanhasPitchSweep ? { SynthParams.pitchSweep?: SynthPitchSweep | undefined
Optional linear pitch sweep from `frequency` to a target frequency across the clip.
pitchSweep
: {
SynthPitchSweep.toFrequency: number
Frequency in Hz the carrier linearly reaches by the end of the clip.
toFrequency
:
const frequency: numberfrequency *
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: Random
Default 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.
@since1.5.0@returnsThe shared {@link Random} instance.@exampleBT.randomSeed(42); BT.random.int(150, 420); BT.random.pick(['a', 'b', 'c']);
random
.Random.float(min: number, max: number): number
Returns the next pseudo-random float in [min, max).
@parammin - Inclusive lower bound.@parammax - Exclusive upper bound.@returnsFloat in [min, max).@since1.5.0
float
(const RANDOM_PITCH_SWEEP_MIN_MULTIPLIER: 0.3RANDOM_PITCH_SWEEP_MIN_MULTIPLIER, const RANDOM_PITCH_SWEEP_MAX_MULTIPLIER: 3RANDOM_PITCH_SWEEP_MAX_MULTIPLIER),
}, } : {}), }; } /** * Preset button playback plus a "roll the dice" randomizer, both built on AudioClip.synth(). * * @implements {IBTDemo} */ class class Demo
Preset button playback plus a "roll the dice" randomizer, both built on AudioClip.synth().
@implementsIBTDemo
Demo
{
/** @type {Palette | null} */ Demo.palette: Palette | null
@type{Palette | null}
palette
= null;
/** Palette slots of the shared UI theme colors, filled by applyTheme() in init(). */ Demo.theme: null
Palette slots of the shared UI theme colors, filled by applyTheme() in init().
theme
= null;
/** @type {AudioClip[]} Pre-rendered clips, one per PRESET_DEFINITIONS entry. */ Demo.presetClips: {}
@type{AudioClip[]} Pre-rendered clips, one per PRESET_DEFINITIONS entry.
presetClips
= [];
/** @type {number | null} Index into PRESET_DEFINITIONS of the last preset played. */ Demo.lastPresetIndex: number | null
@type{number | null} Index into PRESET_DEFINITIONS of the last preset played.
lastPresetIndex
= null;
/** @type {SynthParams | null} The most recently rolled random recipe, or null before the first roll. */ Demo.lastRandomParams: SynthParams | null
@type{SynthParams | null} The most recently rolled random recipe, or null before the first roll.
lastRandomParams
= null;
/** * Turns on the engine's built-in audio meters, shows the overlay from the very first * frame, and styles the overlay so its gaps match the demo's background color. * * @returns {Partial<HardwareSettings>} */ Demo.configure(): Partial<HardwareSettings>
Turns on the engine's built-in audio meters, shows the overlay from the very first frame, and styles the overlay so its gaps match the demo's background color.
@returns
configure
() {
return { // Live per-bus level meters and a voice-count readout in the overlay (explained in the header above). isOverlayAudioMetersEnabled: booleanisOverlayAudioMetersEnabled: true, // Shows the overlay body (title, FPS, backend, and the audio meters above) right // from the first frame instead of waiting for a Backquote press or a click in the // toggle-hint corner. This demo is all about sound, so the meters should be // visible immediately. isOverlayVisibleAtStart: booleanisOverlayVisibleAtStart: true, // gapPaletteIndex fills both the thin seams between overlay rows and the empty // (unfilled) track behind each audio meter bar, so it must match the screen // background or those seams would show up as a mismatched color. The shared UI // theme puts its background color at THEME_DEFAULT_START_SLOT (applyTheme()'s // default start slot - see init() below); configure() runs before init(), so we // reference the constant directly instead of calling applyTheme() early.
overlayStyle: {
    gapPaletteIndex: any;
}
overlayStyle
: {
gapPaletteIndex: anygapPaletteIndex: import THEME_DEFAULT_START_SLOTTHEME_DEFAULT_START_SLOT, }, }; } /** * Renders every preset's SynthParams recipe into a ready-to-play clip, so pressing a * preset later has zero delay, and installs the shared UI theme. * * @returns {Promise<boolean>} */ async Demo.init(): Promise<boolean>
Renders every preset's SynthParams recipe into a ready-to-play clip, so pressing a preset later has zero delay, and installs the shared UI theme.
@returns
init
() {
// AudioClip.synth() is async - it has to calculate every sample before it can hand // back a clip. Promise.all() starts all six calculations at once and waits for them // all to finish, the same way audio-basics preloads its sound files up front. this.Demo.presetClips: {}
@type{AudioClip[]} Pre-rendered clips, one per PRESET_DEFINITIONS entry.
presetClips
= await Promise.all(const PRESET_DEFINITIONS: {}PRESET_DEFINITIONS.map((def: anydef) => class AudioClip
Decoded audio asset with its winning source URL and buffer-derived metadata. Construct instances with {@link AudioClip.load } , {@link AudioClip.loadAll } , or {@link AudioClip.synth } ; there is no public constructor.
@since1.3.0
AudioClip
.AudioClip.synth(params: SynthParams): Promise<AudioClip>
Synthesizes a clip from deterministic procedural parameters - no source file, no `OfflineAudioContext`, and no audio graph involved. Rendering happens entirely on the CPU via the pure {@link renderSynthSamples } function against an `AudioBuffer` allocated from the registered decode context. The returned clip flows through the same {@link buffer } getter and playback path as a loaded clip, but uses a synthetic, non-cached identifier (`synth:<waveform>`) - it is never added to the URL-keyed resolved cache and never deduplicated, so identical `params` still render a fresh, independent `AudioBuffer` on every call. See {@link SynthParams } for the full parameter set.
@paramparams - Deterministic synthesis parameters.@returnsA new clip wrapping the synthesized buffer.@throwsError if `params` fails validation, or the engine has not registered a decode context yet (see {@link audioClipNotReadyError }).
synth
(def: anydef.factory())));
this.Demo.palette: Palette | null
@type{Palette | null}
palette
=
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) => Palette
Creates a standalone palette instance.
@since1.0.3@paramsize - Palette size. Defaults to 256 colors.@returnsNew mutable palette.
paletteCreate
(256);
// applyTheme() installs the twelve shared UI colors and reports their slots, so // render() can clear the screen with the theme's background color. this.Demo.theme: null
Palette slots of the shared UI theme colors, filled by applyTheme() in init().
theme
= import applyThemeapplyTheme(this.Demo.palette: Palette
@type{Palette | null}
palette
);
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) => void
Stores 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.
@since1.0.3@parampalette - Palette to make active.
paletteSet
(this.Demo.palette: Palette
@type{Palette | null}
palette
);
return true; } /** * Runs the UI kit's once-per-tick housekeeping. * * The preset keys (J/P/E/L/H/B and R) are bound to the buttons declared in render() * via their { key } option. ui.tick() is where the kit safely catches those presses - * keyboard "was it just pressed?" flags can only be read reliably here in update(), * never in render() (keyboard-input explains why in detail). */ Demo.update(): void
Runs the UI kit's once-per-tick housekeeping. The preset keys (J/P/E/L/H/B and R) are bound to the buttons declared in render() via their { key } option. ui.tick() is where the kit safely catches those presses - keyboard "was it just pressed?" flags can only be read reliably here in update(), never in render() (keyboard-input explains why in detail).
update
() {
import uiui.tick(); } /** * Clears the screen and declares the whole UI: title bar, unlock message, the preset * keypad on the left, and the randomizer readout on the right. */ Demo.render(): void
Clears the screen and declares the whole UI: title bar, unlock message, the preset keypad on the left, and the randomizer readout on the right.
render
() {
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) => void
Sets 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.
@since0.1.0@parampaletteIndex - Palette index for the full-screen clear pass.
clear
(this.Demo.theme: null
Palette slots of the shared UI theme colors, filled by applyTheme() in init().
theme
.bg);
// The full-width title strip along the top edge. import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_BAR); import uiui.panel('Synth Toy - six presets and a randomizer'); import uiui.end(); this.Demo.renderUnlockPrompt(): void
Shows the shared unlock reminder until audio is unlocked, then switches to a plain reminder of the controls. A borderless group - just one line of text pinned under the title strip.
renderUnlockPrompt
();
this.Demo.renderPresetPanel(): void
Left-hand panel: one button per preset, plus the last one played. Each button fires on click, tap, or its keyboard shortcut - ui.button() treats all three the same.
renderPresetPanel
();
this.Demo.renderRandomPanel(): void
Right-hand panel: the Randomize button and the most recently rolled recipe, one field per row.
renderRandomPanel
();
} /** * Shows the shared unlock reminder until audio is unlocked, then switches to a plain * reminder of the controls. A borderless group - just one line of text pinned under * the title strip. */ Demo.renderUnlockPrompt(): void
Shows the shared unlock reminder until audio is unlocked, then switches to a plain reminder of the controls. A borderless group - just one line of text pinned under the title strip.
renderUnlockPrompt
() {
import uiui.begin(import UI_ANCHORSUI_ANCHORS.TOP_LEFT, { y: numbery: 28 }); // The shared "click to enable sound" row - it draws itself only while sound is // still locked, and disappears on its own after the first click or key press. import uiui.audioUnlockHint(); // Once sound works, swap in a short reminder of the controls instead. if (
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
.isAudioUnlocked: boolean
Whether the audio context has been unlocked by a user gesture. Browsers require a user gesture (pointer, key, or touch press) before allowing audio playback. Starts `false`; flips to `true` for the rest of the session after the first gesture successfully resumes the audio context.
@since1.3.0@returns`true` once unlocked; `false` when locked or before initialization.
isAudioUnlocked
) {
import uiui.label('Tap a button, or press its key', { color: stringcolor: 'dim' }); } import uiui.end(); } /** * Left-hand panel: one button per preset, plus the last one played. Each button fires * on click, tap, or its keyboard shortcut - ui.button() treats all three the same. */ Demo.renderPresetPanel(): void
Left-hand panel: one button per preset, plus the last one played. Each button fires on click, tap, or its keyboard shortcut - ui.button() treats all three the same.
renderPresetPanel
() {
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_LEFT); import uiui.panel('Presets'); for (let let i: numberi = 0; let i: numberi < const PRESET_DEFINITIONS: {}PRESET_DEFINITIONS.length; let i: numberi++) { const const def: anydef = const PRESET_DEFINITIONS: {}PRESET_DEFINITIONS[let i: numberi]; if (import uiui.button(const def: anydef.label, { key: anykey: const def: anydef.code, width: numberwidth: const PRESET_BUTTON_W: 96PRESET_BUTTON_W })) { // Play the pre-rendered clip and remember it for the "Last" row below.
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
.soundPlay: (clip: AudioClip, options?: SoundPlayOptions) => SoundRef
Plays a loaded audio clip through the SFX voice pool. Returns an inert {@link SoundRef } without allocating a voice when the clip hasn't finished loading yet (or was already unloaded), when the pool has no free or stealable voice at this priority, or before the engine has unlocked audio playback.
@since1.3.0@paramclip - Loaded audio clip to play.@paramoptions - Playback options.@returnsA handle identifying the new voice; pass it to {@link BT.soundStop} and the other per-sound controls. Safe to use even when playback was silently dropped - every accessor on an inert handle is a no-op.
soundPlay
(this.Demo.presetClips: {}
@type{AudioClip[]} Pre-rendered clips, one per PRESET_DEFINITIONS entry.
presetClips
[let i: numberi]);
this.Demo.lastPresetIndex: number | null
@type{number | null} Index into PRESET_DEFINITIONS of the last preset played.
lastPresetIndex
= let i: numberi;
} } const const lastLabel: anylastLabel = this.Demo.lastPresetIndex: number | null
@type{number | null} Index into PRESET_DEFINITIONS of the last preset played.
lastPresetIndex
=== null ? '-' : const PRESET_DEFINITIONS: {}PRESET_DEFINITIONS[this.Demo.lastPresetIndex: number
@type{number | null} Index into PRESET_DEFINITIONS of the last preset played.
lastPresetIndex
].name;
import uiui.kv('Last', const lastLabel: anylastLabel); import uiui.end(); } /** * Right-hand panel: the Randomize button and the most recently rolled recipe, one * field per row. */ Demo.renderRandomPanel(): void
Right-hand panel: the Randomize button and the most recently rolled recipe, one field per row.
renderRandomPanel
() {
const const params: SynthParams | nullparams = this.Demo.lastRandomParams: SynthParams | null
@type{SynthParams | null} The most recently rolled random recipe, or null before the first roll.
lastRandomParams
;
import uiui.begin(import UI_ANCHORSUI_ANCHORS.BOTTOM_RIGHT); import uiui.panel('Randomizer'); if (import uiui.button('R - Randomize', { key: stringkey: 'KeyR' })) { this.Demo.triggerRandomize(): void
Rolls a new random SynthParams recipe and starts rendering + playing it. This method itself stays synchronous: it builds the recipe and updates what the panel will show right away, so the numbers on screen always match the most recent press even though the actual sound takes a moment longer to render (see playRandomParams()).
triggerRandomize
();
} // Each row reports one part of the rolled recipe ('-' before the first roll). import uiui.kv('Waveform', const params: SynthParams | nullparams === null ? '-' : const params: SynthParamsparams.SynthParams.waveform: any
Oscillator waveform shape.
waveform
);
import uiui.kv('Frequency', const params: SynthParams | nullparams === null ? '-' : `${Math.round(const params: SynthParamsparams.SynthParams.frequency: number
Base carrier frequency in Hz at the start of the clip (before any pitch sweep or vibrato).
frequency
)} Hz`);
import uiui.kv('Duration', const params: SynthParams | nullparams === null ? '-' : `${const params: SynthParamsparams.SynthParams.duration: number
Total clip duration in seconds. Must be greater than 0 and no more than {@link MAX_SYNTH_DURATION_SECONDS } .
duration
.toFixed(2)} s`);
// Noise mix: how much white noise is mixed into the tone (0 is a pure, clean tone; // 1 is pure hiss). The meter bar fills up left-to-right with the amount. import uiui.kv('Noise mix', const params: SynthParams | nullparams === null ? '-' : const params: SynthParamsparams.SynthParams.noiseMix?: number | undefined
Fraction of white noise mixed into the oscillator output, in [0, 1] (`0` is pure tone, `1` is pure noise). Ignored when `waveform` is already `'noise'`. Defaults to {@link DEFAULT_NOISE_MIX } .
noiseMix
.toFixed(2));
import uiui.meter(null, const params: SynthParams | nullparams === null ? 0 : const params: SynthParamsparams.SynthParams.noiseMix?: number | undefined
Fraction of white noise mixed into the oscillator output, in [0, 1] (`0` is pure tone, `1` is pure noise). Ignored when `waveform` is already `'noise'`. Defaults to {@link DEFAULT_NOISE_MIX } .
noiseMix
);
const const sweepLabel: stringsweepLabel = const params: SynthParams | nullparams === null ? '-' : const params: SynthParamsparams.SynthParams.pitchSweep?: SynthPitchSweep | undefined
Optional linear pitch sweep from `frequency` to a target frequency across the clip.
pitchSweep
? `${Math.round(const params: SynthParamsparams.SynthParams.pitchSweep?: SynthPitchSweep
Optional linear pitch sweep from `frequency` to a target frequency across the clip.
pitchSweep
.SynthPitchSweep.toFrequency: number
Frequency in Hz the carrier linearly reaches by the end of the clip.
toFrequency
)} Hz` : 'none';
import uiui.kv('Sweep', const sweepLabel: stringsweepLabel); // The duty cycle only shapes square waves, so other waveforms show 'n/a'. const const dutyLabel: anydutyLabel = const params: SynthParams | nullparams === null ? '-' : const params: SynthParamsparams.SynthParams.waveform: any
Oscillator waveform shape.
waveform
=== 'square' ? const params: SynthParamsparams.SynthParams.dutyCycle?: number | undefined
Fraction of each cycle spent high, in [0, 1]. Only affects the `'square'` waveform. Defaults to {@link DEFAULT_DUTY_CYCLE } .
dutyCycle
.toFixed(2) : 'n/a';
import uiui.kv('Duty', const dutyLabel: anydutyLabel); import uiui.end(); } /** * Rolls a new random SynthParams recipe and starts rendering + playing it. * * This method itself stays synchronous: it builds the recipe and updates what the panel * will show right away, so the numbers on screen always match the most recent press * even though the actual sound takes a moment longer to render (see playRandomParams()). */ Demo.triggerRandomize(): void
Rolls a new random SynthParams recipe and starts rendering + playing it. This method itself stays synchronous: it builds the recipe and updates what the panel will show right away, so the numbers on screen always match the most recent press even though the actual sound takes a moment longer to render (see playRandomParams()).
triggerRandomize
() {
const const params: SynthParamsparams = function buildRandomSynthParams(): SynthParams
Builds a brand new SynthParams recipe with every field chosen at random, inside the safe ranges above. Unlike the six named presets (which only nudge a couple of fields), this touches every knob AudioClip.synth() understands, so pressing Randomize is a tour of the whole parameter space rather than a small variation on one sound.
@returns
buildRandomSynthParams
();
this.Demo.lastRandomParams: SynthParams | null
@type{SynthParams | null} The most recently rolled random recipe, or null before the first roll.
lastRandomParams
= const params: SynthParamsparams;
// The kit calls render() synchronously, and this handler cannot be async, so we // start the render-and-play and let it run in the background instead of waiting for // it. The .catch() just logs a problem instead of crashing the page, as a safety // net - it should never actually trigger with the ranges above. this.Demo.playRandomParams(params: SynthParams): Promise<void>
Renders a SynthParams recipe into a clip and plays it.
@paramparams - Recipe to render and play.@returns
playRandomParams
(const params: SynthParamsparams).catch((error: anyerror) => console.error(error: anyerror));
} /** * Renders a SynthParams recipe into a clip and plays it. * * @param {SynthParams} params - Recipe to render and play. * @returns {Promise<void>} */ async Demo.playRandomParams(params: SynthParams): Promise<void>
Renders a SynthParams recipe into a clip and plays it.
@paramparams - Recipe to render and play.@returns
playRandomParams
(params: SynthParams
- Recipe to render and play.
@paramparams - Recipe to render and play.
params
) {
const const clip: Promise<AudioClip>clip = await class AudioClip
Decoded audio asset with its winning source URL and buffer-derived metadata. Construct instances with {@link AudioClip.load } , {@link AudioClip.loadAll } , or {@link AudioClip.synth } ; there is no public constructor.
@since1.3.0
AudioClip
.AudioClip.synth(params: SynthParams): Promise<AudioClip>
Synthesizes a clip from deterministic procedural parameters - no source file, no `OfflineAudioContext`, and no audio graph involved. Rendering happens entirely on the CPU via the pure {@link renderSynthSamples } function against an `AudioBuffer` allocated from the registered decode context. The returned clip flows through the same {@link buffer } getter and playback path as a loaded clip, but uses a synthetic, non-cached identifier (`synth:<waveform>`) - it is never added to the URL-keyed resolved cache and never deduplicated, so identical `params` still render a fresh, independent `AudioBuffer` on every call. See {@link SynthParams } for the full parameter set.
@paramparams - Deterministic synthesis parameters.@returnsA new clip wrapping the synthesized buffer.@throwsError if `params` fails validation, or the engine has not registered a decode context yet (see {@link audioClipNotReadyError }).
synth
(params: SynthParams
- Recipe to render and play.
@paramparams - Recipe to render and play.
params
);
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
.soundPlay: (clip: AudioClip, options?: SoundPlayOptions) => SoundRef
Plays a loaded audio clip through the SFX voice pool. Returns an inert {@link SoundRef } without allocating a voice when the clip hasn't finished loading yet (or was already unloaded), when the pool has no free or stealable voice at this priority, or before the engine has unlocked audio playback.
@since1.3.0@paramclip - Loaded audio clip to play.@paramoptions - Playback options.@returnsA handle identifying the new voice; pass it to {@link BT.soundStop} and the other per-sound controls. Safe to use even when playback was silently dropped - every accessor on an inert handle is a no-op.
soundPlay
(const clip: Promise<AudioClip>clip);
} } 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.
@since0.2.0@changed1.4.0 Calling `bootstrap()` again while already initialized now routes to a hot swap (via {@link registerHotReload}) when a Vite HMR context is registered, or logs a double-bootstrap guard and returns `false` otherwise - previously it silently started a second, unstoppable `GameLoop`.@changed1.7.0 Exposes `BT` on `window.BT` after bootstrap finishes, gated by {@link BootstrapOptions.exposeGlobal} (default: {@link BT.isDevMode}).@paramDemoClass - Demo class constructor implementing `IBTDemo` (optional `configure()` for hardware settings).@paramoptions - Optional configuration for IDs and callbacks.@returns`true` when the demo boots successfully; otherwise `false`.@example// Simplest usage - uses default IDs. bootstrap(MyDemo);@example// With custom options. bootstrap(MyDemo, { canvasID: 'custom-canvas', containerID: 'custom-container', onSuccess: () => console.log('Demo started!'), onError: (err) => analytics.trackError(err), });@example// Await the result. const success = await bootstrap(MyDemo); if (success) { console.log('Demo is running'); }
bootstrap
(class Demo
Preset button playback plus a "roll the dice" randomizer, both built on AudioClip.synth().
@implementsIBTDemo
Demo
);