Something went wrong. Try again.
A WebGPU retro game engine for TypeScript, inspired by RetroBlit. Build pixel-perfect 2D games with a clean, fantasy-console-style API.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494/** * Shared user-facing error message strings for the Blit-Tech bootstrap and runtime paths. * * Both the production bootstrap (Bootstrap.ts) and the error-preview demo * (BootstrapHelpers.ts) import from here, guaranteeing they can never drift * apart. Runtime message helpers (palette, sprite) are also centralized here * so every site uses identical wording. */
/** * Returns the canvas-not-found error message for the given canvas element ID. * * @param canvasId - The canvas element ID that was searched for. * @returns User-facing error string. */export function CANVAS_NOT_FOUND_MESSAGE(canvasId: string): string { return `Can't find the canvas on the page. Make sure your HTML has a <canvas id='${canvasId}'> element.`;}
/** * Generic engine initialization failure message. * * Shown when the engine returns false for any reason not covered by a more * specific GPU failure message. */export const INIT_FAILED_MESSAGE = 'Something went wrong starting the engine. Check the browser console (press F12) for details.';
/** * Friendly message for a WebGPU adapter failure. * * Shown when `requestAdapter()` resolves to null (hardware acceleration * disabled, drivers too old, or running in a VM / remote desktop). */export const WEBGPU_ADAPTER_MESSAGE = "Your computer's graphics card couldn't start WebGPU. Try updating your browser, or check that hardware acceleration is enabled.";
/** * Friendly message for a WebGPU device failure. * * Shown when `requestDevice()` rejects (GPU resource exhaustion or a * transient driver error). */export const WEBGPU_DEVICE_MESSAGE = "Couldn't connect to the graphics card. Try closing other tabs or restarting the browser.";
// #region Runtime - Render configuration
/** * Returns the error message for a render dimension that is not a positive whole-number pixel size. * * @param field - Hardware settings field that contains the invalid size. * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @returns User-facing error string. */export function renderDimensionInvalidError(field: string, size: string): string { return ( `${field} must use whole-number pixel dimensions greater than 0 (got ${size}). ` + 'Update configure() to return a positive integer width and height' );}
/** * Returns the error message for a render dimension whose width or height exceeds engine limits. * * @param field - Hardware settings field that contains the invalid size. * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @param maxWidth - Maximum accepted width in pixels. * @param maxHeight - Maximum accepted height in pixels. * @returns User-facing error string. */export function renderDimensionTooLargeError(field: string, size: string, maxWidth: number, maxHeight: number): string { return ( `${field} is too large (got ${size}). ` + `Use a size no larger than ${maxWidth}x${maxHeight} in configure()` );}
/** * Returns the error message for a render dimension whose total pixel area exceeds engine limits. * * @param field - Hardware settings field that contains the invalid size. * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @param maxPixels - Maximum accepted total pixels. * @returns User-facing error string. */export function renderDimensionAreaTooLargeError(field: string, size: string, maxPixels: number): string { return `${field} uses too many pixels (got ${size}). Use a size with ${maxPixels.toLocaleString('en-US')} total pixels or fewer`;}
/** * Returns the error message for a render dimension that exceeds the active WebGPU texture limit. * * @param field - Hardware settings field that contains the invalid size. * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @param maxTextureDimension2D - WebGPU adapter/device texture dimension limit. * @returns User-facing error string. */export function renderDimensionGpuLimitError(field: string, size: string, maxTextureDimension2D: number): string { return ( `${field} is too large for this graphics card (got ${size}). ` + `Use a width and height of ${maxTextureDimension2D} pixels or fewer` );}
// #endregion
// #region Runtime - Assets
/** * Returns the error message for an asset whose width or height is not a positive whole number. * * @param context - Asset label (for example `'sprite sheet'`). * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @returns User-facing error string. */export function assetDimensionInvalidError(context: string, size: string): string { return ( `This ${context} must use whole-number pixel dimensions greater than 0 (got ${size}). ` + 'Check the image file or width and height values and try again' );}
/** * Returns the error message for an asset whose width or height exceeds engine limits. * * @param context - Asset label (for example `'sprite sheet'`). * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @param maxWidth - Maximum accepted width in pixels. * @param maxHeight - Maximum accepted height in pixels. * @returns User-facing error string. */export function assetDimensionTooLargeError( context: string, size: string, maxWidth: number, maxHeight: number,): string { return ( `This ${context} is too large (got ${size}). ` + `Use an image no larger than ${maxWidth}x${maxHeight} pixels on each side` );}
/** * Returns the error message for an asset whose total pixel area exceeds engine limits. * * @param context - Asset label (for example `'sprite sheet'`). * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @param maxPixels - Maximum accepted total pixels. * @returns User-facing error string. */export function assetDimensionAreaTooLargeError(context: string, size: string, maxPixels: number): string { return ( `This ${context} uses too many pixels (got ${size}). ` + `Use an image with ${maxPixels.toLocaleString('en-US')} total pixels or fewer` );}
/** * Returns the error message when indexed pixel dimensions overflow safe allocation limits. * * @param size - Invalid size formatted as `WIDTHxHEIGHT`. * @returns User-facing error string. */export function assetIndexedPixelOverflowError(size: string): string { return `The indexed sprite size ${size} is too large to load safely. Use smaller width and height values`;}
/** * Returns the error message when an indexed pixel buffer length does not match its dimensions. * * @param actualLength - Number of values supplied in the buffer. * @param width - Declared width in pixels. * @param height - Declared height in pixels. * @param expectedLength - Required number of values (`width * height`). * @returns User-facing error string. */export function assetIndexedPixelLengthError( actualLength: number, width: number, height: number, expectedLength: number,): string { return ( `The pixel data has ${actualLength} values, but a ${width}x${height} sheet needs exactly ${expectedLength}. ` + 'Make sure indexedPixels has one entry per pixel' );}
/** * Returns the error message when a `.btfont` JSON payload is too large to parse safely. * * @param byteLength - UTF-8 byte length of the JSON text. * @param maxBytes - Maximum accepted JSON size in bytes. * @returns User-facing error string. */export function btfontJsonTooLargeError(byteLength: number, maxBytes: number): string { return ( `This font file is too large to load safely (${byteLength.toLocaleString('en-US')} bytes). ` + `Use a .btfont file of ${maxBytes.toLocaleString('en-US')} bytes or fewer, ` + 'or move large textures to a separate PNG file' );}
/** * Returns the error message when an embedded `.btfont` texture URI is not a PNG data URI. * * @returns User-facing error string. */export function btfontEmbeddedTextureFormatError(): string { return ( 'Embedded font textures must use a PNG data URI (data:image/png;base64,...). ' + 'Use a relative PNG path in the texture field, or re-export the font with --embed' );}
/** * Returns the error message when an embedded `.btfont` texture payload exceeds the size cap. * * @param payloadLength - Base64 payload length in characters (after the data-URI prefix). * @param maxPayloadBytes - Maximum accepted embedded texture payload size. * @returns User-facing error string. */export function btfontEmbeddedTextureTooLargeError(payloadLength: number, maxPayloadBytes: number): string { return ( `The embedded font texture is too large (${payloadLength.toLocaleString('en-US')} characters of base64 data). ` + `Keep embedded textures under ${maxPayloadBytes.toLocaleString('en-US')} bytes, ` + 'or save the atlas as a separate PNG file and reference it by path' );}
/** * Returns the error message when a `.btfont` file defines too many glyphs. * * @param count - Number of glyph entries found. * @param maxGlyphs - Maximum accepted glyph count. * @returns User-facing error string. */export function btfontGlyphCountTooLargeError(count: number, maxGlyphs: number): string { return ( `This font defines too many glyphs (${count.toLocaleString('en-US')}). ` + `Use ${maxGlyphs.toLocaleString('en-US')} glyphs or fewer` );}
/** * Returns a human-readable label for a `.btfont` glyph metric key. * * @param metricKey - `.btfont` metric key (for example `w` or `adv`). * @returns Label text for error messages. */function getBtfontMetricLabel(metricKey: string): string { switch (metricKey) { case 'adv': return 'advance width (adv)'; case 'h': return 'height (h)'; case 'ox': return 'horizontal offset (ox)'; case 'oy': return 'vertical offset (oy)'; case 'w': return 'width (w)'; case 'x': return 'horizontal position (x)'; case 'y': return 'vertical position (y)'; default: return metricKey; }}
/** * Returns the error message when a glyph entry is not a metric object. * * @param charLabel - Character label used in the message. * @returns User-facing error string. */export function btfontGlyphEntryNotObjectError(charLabel: string): string { return ( `The '${charLabel}' glyph in this font file is invalid. ` + 'Each glyph must be an object with x, y, w, h, ox, oy, and adv fields' );}
/** * Returns the error message when a glyph metric is not a whole number. * * @param charLabel - Character label used in the message. * @param metricKey - `.btfont` metric key (for example `w` or `adv`). * @param value - Invalid metric value. * @returns User-facing error string. */export function btfontGlyphMetricNotIntegerError(charLabel: string, metricKey: string, value: number): string { const label = getBtfontMetricLabel(metricKey);
return ( `The '${charLabel}' glyph has an invalid ${label} (got ${value}). ` + 'Use a whole number for every glyph metric in the .btfont file' );}
/** * Returns the error message when a glyph position is negative. * * @param charLabel - Character label used in the message. * @returns User-facing error string. */export function btfontGlyphNegativePositionError(charLabel: string): string { return ( `The '${charLabel}' glyph has a negative position in the texture atlas. ` + 'Use 0 or greater for x and y in the .btfont file' );}
/** * Returns the error message when a glyph width or height is negative. * * @param charLabel - Character label used in the message. * @returns User-facing error string. */export function btfontGlyphNegativeSizeError(charLabel: string): string { return ( `The '${charLabel}' glyph has a negative width or height. ` + 'Use 0 or greater for w and h in the .btfont file' );}
/** * Returns the error message when a glyph advance width is negative. * * @param charLabel - Character label used in the message. * @returns User-facing error string. */export function btfontGlyphNegativeAdvanceError(charLabel: string): string { return `The '${charLabel}' glyph has a negative advance width. ` + 'Use 0 or greater for adv in the .btfont file';}
/** * Returns the error message when a glyph is larger than the engine allows. * * @param charLabel - Character label used in the message. * @param width - Glyph width in pixels. * @param height - Glyph height in pixels. * @param maxWidth - Maximum accepted width in pixels. * @param maxHeight - Maximum accepted height in pixels. * @returns User-facing error string. */export function btfontGlyphSizeTooLargeError( charLabel: string, width: number, height: number, maxWidth: number, maxHeight: number,): string { return ( `The '${charLabel}' glyph is too large (${width}x${height}). ` + `Use a glyph size no larger than ${maxWidth}x${maxHeight} pixels` );}
/** * Returns the error message when a glyph rectangle falls outside the font texture. * * @param charLabel - Character label used in the message. * @param x - Glyph X position in the atlas. * @param y - Glyph Y position in the atlas. * @param width - Glyph width in pixels. * @param height - Glyph height in pixels. * @param atlasWidth - Texture atlas width in pixels. * @param atlasHeight - Texture atlas height in pixels. * @returns User-facing error string. */export function btfontGlyphOutsideAtlasError( charLabel: string, x: number, y: number, width: number, height: number, atlasWidth: number, atlasHeight: number,): string { return ( `The '${charLabel}' glyph rectangle (${x}, ${y}, ${width}x${height}) is outside the ` + `${atlasWidth}x${atlasHeight} font texture. Move the glyph inside the atlas image` );}
/** * Returns the error message when a glyph area is too large to render safely. * * @param charLabel - Character label used in the message. * @returns User-facing error string. */export function btfontGlyphAreaTooLargeError(charLabel: string): string { return `The '${charLabel}' glyph covers too many pixels to render safely. Use a smaller glyph rectangle`;}
// #endregion
// #region Runtime - Palette
/** * Returns the "no active palette" error message used whenever a palette must * be set before an operation can proceed. * * @returns User-facing error string. */export function noActivePaletteError(): string { return 'No palette set yet. Call BT.paletteSet(somePalette) before drawing or running palette effects.';}
/** * Returns the error message for a palette index that is negative or not a * whole number. * * @param index - The invalid index value that was supplied. * @returns User-facing error string. */export function paletteIndexNegativeError(index: number): string { return `The color number must be a whole number that's 0 or higher (got ${index}).`;}
/** * Returns the error message for a palette index that exceeds the palette size. * * @param index - The out-of-range index that was supplied. * @param size - The number of colors in the active palette. * @returns User-facing error string. */export function paletteIndexOutOfRangeError(index: number, size: number): string { return `The color number ${index} is too big for this palette. The palette has ${size} colors, so use a number from 0 to ${size - 1}.`;}
/** * Returns the error message when `applyHUD` is called with `startSlot` less than 1. * * @param startSlot - The invalid start slot value that was supplied. * @returns User-facing error string. */export function hudStartSlotError(startSlot: number): string { return `HUD preset slots start from 1 (slot 0 is always transparent). Got ${startSlot}.`;}
/** * Returns the error message when the HUD preset slots would exceed the palette size. * * @param startSlot - The requested start slot. * @param count - Number of HUD slots needed. * @param size - The palette size. * @returns User-facing error string. */export function hudRangeError(startSlot: number, count: number, size: number): string { return ( `HUD preset needs ${count} slots starting at ${startSlot}, ` + `but this palette only has ${size} entries (max slot: ${size - 1}).` );}
// #endregion
// #region Runtime - Sprites
/** * Returns the error message for a sprite pixel whose color is absent from the * active palette. * * @param x - Pixel x coordinate within the source image. * @param y - Pixel y coordinate within the source image. * @param src - Source image label (e.g. `'sheet.png'` or `(unnamed)`). * @param hex - The color that was not found, as a lowercase hex string. * @returns User-facing error string. */export function spriteColorNotInPaletteError(x: number, y: number, src: string, hex: string): string { return ( `The pixel at (${x}, ${y}) in ${src} has the color ${hex}, but that color isn't in your palette.` + ` Either add ${hex} to the palette, or change that pixel in the image.` );}
/** * Returns the error message shown when a sprite sheet has not been indexized * before use. * * @returns User-facing error string. */export function spriteNotIndexizedError(): string { return ( "This sprite sheet hasn't been prepared yet. Use SpriteSheet.loadIndexed(...) for one-step setup," + ' or call sheet.indexize(palette) after BT.paletteSet.' );}
// #endregion