{"id":25815436,"url":"https://github.com/vancura/blit-tech","last_synced_at":"2026-04-27T04:32:34.854Z","repository":{"id":330739906,"uuid":"1122612880","full_name":"vancura/blit-tech","owner":"vancura","description":"A lightweight WebGPU retro game engine for TypeScript, inspired by RetroBlit. Build pixel-perfect 2D games with a clean, fantasy-console-style API.","archived":false,"fork":false,"pushed_at":"2026-04-19T17:23:16.000Z","size":1392,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-19T19:24:57.440Z","etag":null,"topics":["2d-game","canvas","fantasy-console","game-engine","pixel-art","retro","sprite","typescript","webgpu"],"latest_commit_sha":null,"homepage":"https://vancura.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vancura.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-25T06:04:54.000Z","updated_at":"2026-04-19T17:54:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vancura/blit-tech","commit_stats":null,"previous_names":["vancura/blit-tech","ambilab/blit-tech"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/vancura/blit-tech","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vancura%2Fblit-tech","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vancura%2Fblit-tech/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vancura%2Fblit-tech/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vancura%2Fblit-tech/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vancura","download_url":"https://codeload.github.com/vancura/blit-tech/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vancura%2Fblit-tech/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32323213,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2d-game","canvas","fantasy-console","game-engine","pixel-art","retro","sprite","typescript","webgpu"],"created_at":"2025-02-28T04:28:27.014Z","updated_at":"2026-04-27T04:32:34.847Z","avatar_url":"https://github.com/vancura.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blit-Tech\n\n[![CI](https://github.com/vancura/blit-tech/actions/workflows/ci.yml/badge.svg)](https://github.com/vancura/blit-tech/actions/workflows/ci.yml)\n[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)\n[![TypeScript](https://img.shields.io/badge/TypeScript-6.0.3-blue.svg)](https://www.typescriptlang.org/)\n[![WebGPU](https://img.shields.io/badge/WebGPU-Enabled-green.svg)](https://www.w3.org/TR/webgpu/)\n[![pnpm](https://img.shields.io/badge/pnpm-10.26.2-yellow.svg)](https://pnpm.io/)\n\nA lightweight WebGPU retro engine for TypeScript, inspired by [RetroBlit](https://badcastle.itch.io/retroblit). Build\npixel-perfect 2D demos with a clean, fantasy-console-style API.\n\n![Blit-Tech logo](assets/logo.png)\n\n## Inspiration\n\nBlit-Tech draws heavy inspiration from [RetroBlit](https://www.badcastle.com/retroblit/docs/doc/index.html), a retro\npixel demo framework for Unity created by Martin Cietwierkowski ([@daafu](https://github.com/daafu)). RetroBlit provides\nan ideal environment for making pixel-perfect retro demos through a traditional demo loop and code-only development,\ndiscarding the Unity Editor in favor of a clean, low-level API.\n\nBlit-Tech brings a similar philosophy to the web using WebGPU: no scene graphs, no complex frameworks – just sprites,\nprimitives, and fonts.\n\n## Features\n\n- **WebGPU rendering** with dual-pipeline architecture (primitives + sprites)\n- **Palette system**: 256-entry indexed color palette with built-in presets (VGA, CGA, C64, Game Boy, PICO-8, NES)\n- **Palette effects**: cycling, fade, flash, swap with easing functions -- animated color manipulation each frame\n- **Post-process effects**: two-tier system — pixel-tier effects (chunky glitch, mosaic) at logical resolution, plus\n  display-tier effects (CRT scanlines, barrel curvature, RGB shadow mask, bloom, etc.) at output resolution. Both chains\n  add zero cost when empty. Bundled `BT.preset.crtPipBoy()` / `amber()` / `green()` for one-line setup\n- **Primitive drawing**: pixels, lines, rectangles (outline and filled)\n- **Sprite system**: sprite sheets, palette-indexed textures, palette offset for color variations, automatic texture\n  batching\n- **Bitmap fonts**: variable-width font rendering with palette offset support\n- **Camera system**: scrolling with offset and reset\n- **Asset loading**: sprite sheets and bitmap fonts from images with automatic caching\n- **Fixed timestep**: deterministic 60 FPS loop with tick counter and optional dropped-frame detection\n- **Clean API**: all engine access through the `BT` namespace\n- **Display scaling**: optional CSS upscaling via `canvasDisplaySize` for crisp pixel art\n\n## Prerequisites\n\n- **Node.js** v22 or higher (LTS)\n- **pnpm** v10.26.2 or higher\n- A **WebGPU-compatible browser**:\n  - Chrome/Edge 113+ (Windows, macOS, Linux, Android)\n  - Firefox 141+ on Windows; 145+/147+ on macOS; Nightly on Linux and Android\n  - Safari 26+ (macOS Tahoe / iOS 26); or Safari 18–25 with WebGPU enabled via Feature Flags\n\n## Installation\n\n**Note:** Blit-Tech is currently in development and not yet published to npm. Clone the repository to use it:\n\n```bash\ngit clone https://github.com/vancura/blit-tech.git\ncd blit-tech\npnpm install\n```\n\n## Examples \u0026 Demos\n\nFor interactive examples and demos, visit the [Blit-Tech Demos repository](https://github.com/vancura/blit-tech-demos).\nThe demos showcase all engine features with a guided learning path from basic concepts to advanced techniques.\n\n## Documentation\n\nAdditional documentation is available in the `docs/` directory:\n\n- **[Testing Guide](docs/testing.md)** — Testing infrastructure, tiers, and WebGPU mocks\n- **[Performance Testing Guide](docs/performance-testing.md)** — CPU benchmarks, browser frame-time tests, and CI perf\n  workflows\n- **[Performance Best Practices](docs/performance-best-practices.md)** — Optimization guidelines and performance tips\n- **[Post-Process Effects Guide](docs/post-process-effects.md)** — Effect chain, built-in `PipBoyEffect` and\n  `BloomEffect`, writing custom effects, and shader attribution\n- **[Bitmap Fonts Guide](docs/bitmap-fonts.md)** — Built-in system font, `.btfont` format spec, BMFont conversion, and\n  font rendering API\n- **[Developer Experience Guide](docs/developer-experience-guide.md)** — Development workflow and tooling (roadmap)\n\n## Scripts\n\n| Command                     | Description                                                              |\n| --------------------------- | ------------------------------------------------------------------------ |\n| `pnpm build`                | Build the library for npm distribution                                   |\n| `pnpm lint`                 | Run ESLint                                                               |\n| `pnpm lint:fix`             | Run ESLint with auto-fix                                                 |\n| `pnpm format`               | Format all code (Biome + Prettier)                                       |\n| `pnpm format:check`         | Check all formatting without changes                                     |\n| `pnpm format:biome`         | Format TS/JS/JSON/CSS only (Biome)                                       |\n| `pnpm format:prettier`      | Format Markdown/YAML/HTML/HBS (Prettier)                                 |\n| `pnpm typecheck`            | Run TypeScript type checking                                             |\n| `pnpm spellcheck`           | Check spelling in source files                                           |\n| `pnpm test`                 | Run all unit tests (alias for `test:unit`)                               |\n| `pnpm test:unit`            | Run all unit tests                                                       |\n| `pnpm test:unit:watch`      | Run unit tests in watch mode                                             |\n| `pnpm test:unit:coverage`   | Run unit tests with coverage report (80% threshold)                      |\n| `pnpm test:visual`          | Playwright visual regression tests (requires Chrome with WebGPU)         |\n| `pnpm test:visual:update`   | Update visual test baseline screenshots                                  |\n| `pnpm test:visual:coverage` | Run visual tests with Istanbul coverage report                           |\n| `pnpm bench`                | Run Tier 1 CPU benchmarks (Vitest bench)                                 |\n| `pnpm bench:json`           | Run Tier 1 benchmarks and write `benchmark-results.json`                 |\n| `pnpm preflight`            | Run all quality checks (format, lint, typecheck, spellcheck, knip, test) |\n| `pnpm knip`                 | Find unused exports and dependencies                                     |\n| `pnpm knip:fix`             | Auto-fix unused exports and dependencies                                 |\n| `pnpm clean`                | Remove dist and cache directories                                        |\n| `pnpm release`              | Build library and publish to npm                                         |\n| `pnpm convert-font`         | Convert BMFont to .btfont format                                         |\n| `pnpm system-font:export`   | Export system font data to PNG atlas (`assets/system-font.png`)          |\n| `pnpm system-font:convert`  | Regenerate `systemFontData.ts` from edited PNG atlas                     |\n| `pnpm security:audit`       | Run dependency security audit                                            |\n| `pnpm security:audit:fix`   | Run dependency security audit and auto-fix                               |\n\n## Quick Start\n\nCreate a demo by implementing the `IBlitTechDemo` interface:\n\n```ts\nimport {\n  bootstrap,\n  BT,\n  Color32,\n  Palette,\n  Rect2i,\n  Vector2i,\n  type HardwareSettings,\n  type IBlitTechDemo,\n} from '../src/BlitTech';\n\n// Palette indices — give each color a named constant for readability.\nconst BG = 1;\nconst RED = 2;\nconst BLUE = 3;\n\nclass MyDemo implements IBlitTechDemo {\n  /**\n   * Configures hardware settings for this demo.\n   * Sets up a 320×240 internal resolution with optional CSS upscaling.\n   *\n   * @returns Hardware configuration specifying display size and target FPS.\n   */\n  queryHardware(): HardwareSettings {\n    return {\n      displaySize: new Vector2i(320, 240), // Internal rendering resolution\n      canvasDisplaySize: new Vector2i(640, 480), // Optional: CSS display size (2× upscale)\n      targetFPS: 60,\n      // detectDroppedFrames: true, // Optional: log a console warning on missed vsync\n    };\n  }\n\n  /**\n   * Initializes demo state after the engine is ready.\n   * A palette must be set before any drawing calls are made.\n   *\n   * @returns Promise resolving to true when initialization succeeds.\n   */\n  async initialize(): Promise\u003cboolean\u003e {\n    // Define the palette — all rendering uses indices into this table.\n    const palette = new Palette(16);\n    palette.set(BG, new Color32(20, 30, 40, 255));\n    palette.set(RED, new Color32(255, 100, 50, 255));\n    palette.set(BLUE, new Color32(50, 100, 255, 255));\n    BT.paletteSet(palette);\n\n    // Load assets here (sprites, fonts, etc.)\n    // Example: const spriteSheet = await SpriteSheet.load('assets/sprites.png');\n    // After loading: spriteSheet.indexize(palette);\n    return true;\n  }\n\n  /**\n   * Updates animation state based on ticks.\n   */\n  update(): void {\n    // Demo logic at fixed timestep (60 FPS)\n    // Note: Keyboard input (BT.keyDown, BT.keyPressed) is planned but not yet implemented\n  }\n\n  /**\n   * Renders demo graphics.\n   */\n  render(): void {\n    BT.clear(BG);\n    BT.drawRectFill(new Rect2i(100, 100, 50, 50), RED);\n    BT.drawRect(new Rect2i(160, 100, 50, 50), BLUE);\n  }\n}\n\n// One-liner bootstrap - handles WebGPU detection, DOM ready, and error display\nbootstrap(MyDemo);\n```\n\nFor more control over initialization:\n\n```ts\nimport { BT, checkWebGPUSupport, displayError, getCanvas } from '../src/BlitTech';\n\n// Manual initialization with custom error handling\nif (!checkWebGPUSupport()) {\n  displayError(\n    'WebGPU Not Supported',\n    'Please use a WebGPU-compatible browser (Chrome/Edge 113+, Firefox 141+ on Windows, Safari 18+ with Feature Flags or Safari 26+).',\n  );\n} else {\n  const canvas = getCanvas('my-canvas-id');\n  if (canvas) {\n    await BT.initialize(new MyDemo(), canvas);\n  }\n}\n```\n\n## Project Structure\n\n```text\nblit-tech/\n├── src/\n│   ├── BlitTech.ts             # Main API (BT namespace)\n│   ├── assets/\n│   │   ├── AssetLoader.ts      # Image loading with caching\n│   │   ├── BitmapFont.ts       # Bitmap font system (.btfont)\n│   │   ├── Palette.ts          # 256-entry indexed color palette\n│   │   ├── PaletteEffect.ts    # Palette effect system (cycle, fade, flash, swap)\n│   │   ├── SpriteSheet.ts      # GPU texture wrapper with palette indexization\n│   │   └── palettes/           # Built-in preset palette data (VGA, CGA, C64, etc.)\n│   ├── core/\n│   │   ├── BTAPI.ts            # Internal API singleton\n│   │   ├── GameLoop.ts         # Fixed-timestep game loop\n│   │   ├── IBlitTechDemo.ts    # Demo interface + HardwareSettings\n│   │   └── WebGPUContext.ts    # WebGPU adapter/device/context setup\n│   ├── render/\n│   │   ├── Renderer.ts         # High-level renderer (coordinates pipelines + chains)\n│   │   ├── PrimitivePipeline.ts # Batched palette-indexed geometry\n│   │   ├── SpritePipeline.ts   # Batched palette-indexed textured quads\n│   │   ├── PostProcessChain.ts # Tier-aware fullscreen effect chain\n│   │   ├── UpscalePass.ts      # Logical -\u003e output upscale (nearest/linear)\n│   │   └── effects/\n│   │       ├── Effect.ts        # Effect interface + EffectTier\n│   │       ├── FullscreenEffect.ts # Base class for typical fullscreen effects\n│   │       ├── pixel/           # Pixel-tier (PixelGlitch, PixelMosaic)\n│   │       ├── display/         # Display-tier (BarrelDistortion, Scanlines, ...)\n│   │       └── presets/         # crtPipBoy, amber, green\n│   ├── utils/\n│   │   ├── Bootstrap.ts        # Demo bootstrap utilities\n│   │   ├── BootstrapHelpers.ts # WebGPU detection, error display\n│   │   ├── Color32.ts          # 32-bit RGBA color\n│   │   ├── Easing.ts           # Easing functions for palette effects\n│   │   ├── FrameCapture.ts     # GPU readback + PNG export\n│   │   ├── Rect2i.ts           # Integer rectangle\n│   │   └── Vector2i.ts         # Integer 2D vector\n│   └── __test__/\n│       ├── webgpu-mock.ts      # WebGPU mock factories\n│       └── setup.ts            # Vitest global setup (GPU constants + OffscreenCanvas stub)\n├── tests/\n│   └── visual/                 # Playwright visual regression tests\n├── dist/                       # Built library output\n├── docs/                       # Library documentation\n├── package.json\n├── tsconfig.json\n├── vite.config.ts\n├── vitest.config.ts\n├── playwright.config.ts\n└── eslint.config.js\n```\n\n## API Reference\n\n### Bootstrap Utilities\n\nThe bootstrap utilities provide a streamlined way to initialize demos with automatic WebGPU detection and error\nhandling:\n\n```ts\n// One-liner demo startup (recommended)\nbootstrap(MyDemo); // Uses defaults: canvas='blit-tech-canvas', container='canvas-container'\n\n// With custom options\nbootstrap(MyDemo, {\n  canvasId: 'custom-canvas',\n  containerId: 'error-container',\n  onSuccess: () =\u003e console.log('Demo started!'),\n  onError: (err) =\u003e trackError(err),\n});\n\n// Individual utilities for manual control\ncheckWebGPUSupport(); // Returns true if WebGPU is available\ndisplayError(title, message, containerId?); // Show styled error in DOM\ngetCanvas(canvasId?); // Get canvas element safely\n```\n\n### Initialization\n\n```ts\nBT.initialize(demo, canvas); // Start the engine (low-level)\nBT.displaySize(); // Get display resolution\nBT.fps(); // Get target FPS\nBT.ticks(); // Get current tick count\nBT.ticksReset(); // Reset tick counter\n```\n\nA palette must be set via `BT.paletteSet()` before any draw calls are made. The recommended place is `initialize()` in\nthe demo, before loading any sprite sheets.\n\n### Palette\n\nThe palette is the color authority for all rendering. Index 0 is always transparent.\n\n```ts\n// Create a palette and populate it\nconst palette = new Palette(16); // 16-color palette (valid sizes: 2, 4, 16, 32, 64, 128, 256)\npalette.set(1, new Color32(255, 0, 0, 255)); // red at index 1\npalette.set(2, new Color32(0, 255, 0, 255)); // green at index 2\nBT.paletteSet(palette); // activate for rendering\nBT.paletteGet(); // retrieve the active palette\n\n// Optional named aliases\npalette.setNamed('player', 3);\npalette.getNamed('player'); // returns 3\n\n// Built-in retro presets\nPalette.vga(); // VGA 256-color\nPalette.cga(); // CGA 16-color\nPalette.c64(); // Commodore 64 16-color\nPalette.gameboy(); // Game Boy 4-shade\nPalette.pico8(); // PICO-8 16-color\nPalette.nes(); // NES 64-color\n\n// Serialization\nconst json = palette.toJSON();\nconst restored = Palette.fromJSON(json);\n```\n\n### Palette Effects\n\nAnimated palette effects run automatically each frame, modifying palette entries in place. The renderer picks up changes\nvia the dirty flag and re-uploads the palette to the GPU.\n\n```ts\n// Cycle a range of palette entries (creates flowing water, fire, etc.)\nBT.paletteCycle(start, end, speed); // speed: steps/second (positive=forward, negative=backward)\n\n// Smooth fade between palettes (day/night transitions, etc.)\nBT.paletteFade(targetPalette, durationMs); // fade entire palette\nBT.paletteFade(targetPalette, durationMs, 'ease-in-out'); // with easing\nBT.paletteFadeRange(start, end, targetPalette, durationMs, 'ease-out'); // fade a sub-range only\n\n// Flash all palette entries to a single color (lightning, damage, etc.)\nBT.paletteFlash(Color32.white(), 200); // 200ms flash\n\n// Swap two palette entries instantly\nBT.paletteSwap(indexA, indexB);\n\n// Remove all active effects\nBT.paletteClearEffects();\n```\n\nAvailable easing functions: `'linear'`, `'ease-in'`, `'ease-out'`, `'ease-in-out'`.\n\nEffects are processed after `demo.render()` but before the GPU upload in `Renderer.endFrame()`, so user code and effects\nnever conflict. Multiple effects can run simultaneously on different palette ranges.\n\n### Post-Process Effects\n\nTwo-tier fullscreen post-process system that runs between the scene render and the swap-chain present. Effects are\norganized into two chains by what they operate on:\n\n- **Pixel tier** — runs at the logical render resolution on the rendered palette pixels (`nearest` sampling, palette\n  preserved). Hosts chunky glitch, block mosaic, etc.\n- **Display tier** — runs at the canvas output resolution after an upscale pass. Hosts CRT scanlines, barrel curvature,\n  RGB shadow mask, vignette, chromatic aberration, bloom, etc. Operating at output resolution is what lets curved\n  sampling (barrel) express smoothly without quantizing onto the source pixel grid.\n\nBoth chains add zero cost when empty. Set `canvasDisplaySize` in `queryHardware()` to enable the display tier.\n\n```ts\nimport { BT, Vector2i, BarrelDistortion, Scanlines, Bloom, PixelGlitch } from 'blit-tech';\n\n// In queryHardware(): unlock the display tier and pick an output size.\nreturn {\n  displaySize: new Vector2i(320, 240),\n  canvasDisplaySize: new Vector2i(1280, 960), // 4x integer scale\n  outputUpscaleFilter: 'nearest',\n  targetFPS: 60,\n};\n\n// In initialize(): mix and match effects from both tiers.\nBT.effectAdd(new PixelGlitch()); // tier='pixel' on the effect routes automatically\nBT.effectAdd(new BarrelDistortion());\nBT.effectAdd(new Scanlines());\nBT.effectAdd(new Bloom());\n\n// Or use a preset for the full CRT look in one line:\nfor (const fx of BT.preset.crtPipBoy()) BT.effectAdd(fx);\n\n// Tear down\nBT.effectClear(); // clears both chains\n```\n\n**Built-in effects (pixel tier):** `PixelGlitch`, `PixelMosaic`.\n\n**Built-in effects (display tier):** `BarrelDistortion`, `Scanlines`, `RGBMask`, `Vignette`, `ChromaticAberration`,\n`Flicker`, `RollLine`, `Interference`, `Noise`, `Bloom`.\n\n**Bundled presets:** `BT.preset.crtPipBoy()`, `BT.preset.amber()`, `BT.preset.green()`.\n\nSee the [Post-Process Effects Guide](docs/post-process-effects.md) for parameter reference, the `Effect` interface, the\n`FullscreenEffect` base class, and how to write a custom effect.\n\n### Drawing Primitives\n\nAll drawing methods accept a palette index instead of a `Color32` directly.\n\n```ts\nBT.clear(paletteIndex); // Clear screen\nBT.clearRect(rect, paletteIndex); // Clear rectangular region\nBT.drawPixel(pos, paletteIndex); // Draw single pixel\nBT.drawLine(p0, p1, paletteIndex); // Draw line\nBT.drawRect(rect, paletteIndex); // Draw rectangle outline\nBT.drawRectFill(rect, paletteIndex); // Draw filled rectangle\n```\n\n### Asset Loading\n\n```ts\n// Load sprite sheet from image (automatically cached)\nconst spriteSheet = await SpriteSheet.load('path/to/sprites.png');\n\n// Load bitmap font from .btfont file (automatically cached)\nconst font = await BitmapFont.load('fonts/MyFont.btfont');\n\n// Load multiple images in parallel\nconst images = await AssetLoader.loadImages(['sprite1.png', 'sprite2.png']);\n\n// Check if asset is already cached\nif (AssetLoader.isLoaded('path/to/sprites.png')) {\n  // Asset already loaded\n}\n```\n\n### Sprites and Text\n\nSprites use a palette-first rendering model. Every sprite sheet must be converted to palette indices before drawing:\n\n```ts\n// Convert RGBA pixels to palette indices (call once after paletteSet).\nspriteSheet.indexize(palette);\n\nBT.drawSprite(sheet, srcRect, destPos); // Draw with original palette colors\nBT.drawSprite(sheet, srcRect, destPos, 16); // Draw with paletteOffset=16 (color variation)\nBT.printFont(font, pos, text); // Draw text using bitmap font\nBT.printFont(font, pos, text, 8); // Draw text with paletteOffset=8\nBT.systemPrint(pos, paletteIndex, text); // Draw text with the built-in 6x14 system font\nBT.systemPrintMeasure(text); // Measure system font text dimensions\nBT.spritesRefresh(); // Re-index all loaded sheets after palette swap\n```\n\n**Palette offset:** The `paletteOffset` parameter shifts which palette range a sprite samples from at draw time. Useful\nfor team colors, damage flashes, or palette-swap effects without duplicate assets.\n\n**System font:** `BT.systemPrint()` renders text using the built-in 6x14 bitmap font. See the\n[Bitmap Fonts Guide](docs/bitmap-fonts.md) for editing instructions. For custom bitmap fonts with proportional glyphs,\nuse `BT.printFont()` with a loaded `BitmapFont`.\n\n**Sprite Transforms:** Sprite transform flags (`BT.FLIP_H`, `BT.FLIP_V`, `BT.ROT_90_CW`, etc.) are defined but not yet\nimplemented in `drawSprite()`. They are planned for a future release.\n\n### Camera\n\n```ts\nBT.cameraSet(offset); // Set camera offset\nBT.cameraGet(); // Get current offset\nBT.cameraReset(); // Reset to (0, 0)\n```\n\n### Core Types\n\n```ts\n// Vectors and rectangles\nVector2i(x, y); // Integer 2D vector\nRect2i(x, y, width, height); // Integer rectangle\n\n// Colors (used to populate palette entries)\nnew Color32(r, g, b); // Create color from RGB (0-255)\nnew Color32(r, g, b, a); // Create color with alpha (0-255)\n\n// Cached color constants (recommended for common colors)\nColor32.white();\nColor32.black();\nColor32.red();\nColor32.green();\nColor32.blue();\nColor32.yellow();\nColor32.cyan();\nColor32.magenta();\nColor32.transparent();\n\n// Assets\nSpriteSheet.load(url); // Load sprite sheet (static method)\nBitmapFont.load(url); // Load bitmap font (static method)\n```\n\n### Input\n\n**Note:** Keyboard and gamepad input methods (`BT.keyDown()`, `BT.keyPressed()`, `BT.buttonDown()`, etc.) are planned\nbut not yet implemented. They currently return `false`. Button constants (`BT.BTN_UP`, `BT.BTN_A`, etc.) are defined for\nfuture use. See the Blit-Tech Demos repository for workarounds using browser APIs directly.\n\n## Browser Compatibility\n\nWebGPU support varies by browser:\n\n| Browser     | Version        | Status                                                           |\n| ----------- | -------------- | ---------------------------------------------------------------- |\n| Chrome/Edge | 113+           | Enabled by default                                               |\n| Firefox     | 141+ (Windows) | Enabled by default; 145+/147+ on macOS; Nightly on Linux/Android |\n| Safari      | 26+            | Enabled by default; Safari 18–25 available via Feature Flags     |\n\nThe engine displays an error message if the browser doesn’t support WebGPU.\n\n## Technologies\n\n- **WebGPU** — Modern GPU API for the web\n- **TypeScript** — Type-safe JavaScript\n- **Vite** — Fast build tool with HMR\n- **WGSL** — WebGPU Shading Language\n- **Biome** — Fast formatter and linter\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on:\n\n- Developer Certificate of Origin (DCO) requirements\n- Commit message format (Conventional Commits)\n- Code style guidelines\n- Pull request process\n\nAll commits must be signed off with a DCO. Use `git commit -s` to automatically add the sign-off.\n\nPlease review our [Code of Conduct](CODE_OF_CONDUCT.md) before participating. To report a security vulnerability, follow\nthe process in [SECURITY.md](SECURITY.md).\n\n## License\n\nISC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvancura%2Fblit-tech","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvancura%2Fblit-tech","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvancura%2Fblit-tech/lists"}