Blit-Tech #
A palette-first WebGPU retro engine for TypeScript, inspired by RetroBlit. Draw with palette indices, animate with palette cycling and fades, and ship authentic VGA-era effects on modern GPUs.

Inspiration #
Blit-Tech draws heavy inspiration from RetroBlit by Martin Cietwierkowski (@daafu) - a retro pixel demo framework for Unity that replaces the editor with a clean, low-level demo loop. Blit-Tech brings the same philosophy to the web using WebGPU: no scene graphs, no complex frameworks, just sprites, primitives, and fonts.
Features #
- True indexed rendering: primitives and sprites write palette indices, not RGBA pixels
- Palette effects built-in: cycling, fade, flash, and swap run per frame with no per-sprite rewrites
- Built-in retro palettes: VGA, CGA, C64, Game Boy, PICO-8, and NES preset factories
- Palette offset variants: recolor one sprite sheet into team colors, states, or themes without duplicate textures
- Performance-first data model: tiny palette uploads (4 KB), smaller sprite textures, and compact primitive vertices
- WebGPU rendering with dual-pipeline architecture (primitives + sprites); automatic Canvas 2D software fallback
- Post-process effects: two-tier system - pixel tier on the
r8uintindex framebuffer; display tier on upscaled RGBA; bundled CRT presets - Primitive drawing: pixels, lines, rectangles (outline and filled)
- Sprite system: palette-indexed textures, palette offset, automatic texture batching
- Bitmap fonts: variable-width rendering from
.btfontfiles with palette offset support - Camera system: scrolling with offset/reset and world-bounds clamping via
BT.cameraClamp - Asset loading: sprite sheets and bitmap fonts with automatic caching
- Pointer input: mouse, touch, and pen unified under four slots; scroll delta; cursor control
- Keyboard input: raw keys via
KeyboardEvent.code, virtual face buttons, remapping, text accumulation - Gamepad input: up to four players via standard Gamepad API, stick dead zone, face buttons
- Fixed timestep: deterministic update loop with tick counter,
Timer, and timing helpers - Frame capture:
BT.captureFrame()andBT.downloadFrame()for PNG export
Why Blit-Tech? #
| Feature | Blit-Tech | Typical 2D WebGPU engines |
|---|---|---|
| Rendering model | Native indexed palette pipeline | RGBA textures and framebuffers |
| Color animation | Palette cycling/fade/flash built-in | Manual sprite or shader rewrites |
| Global recolor/fade cost | One palette update | Scene redraw and blend passes |
| Color variants | Palette offsets | Duplicate assets or tint logic |
| Retro palette presets | C64, NES, Game Boy, CGA, VGA, etc. | Usually custom/manual only |
Prerequisites #
Runtime (browser)
- A WebGPU-compatible browser (the engine falls back to Canvas 2D software rendering when WebGPU is unavailable):
- Chrome/Edge 113+ (Windows, macOS, Linux, Android)
- Firefox 141+ on Windows; 145+/147+ on macOS; Nightly on Linux and Android
- Safari 26+ (macOS Tahoe / iOS 26); or Safari 18-25 with WebGPU enabled via Feature Flags
App toolchain
- Node.js >=22.18.0 (LTS)
- An ESM bundler (Vite, webpack, esbuild, and similar) to load the published package in the browser
Installation #
Install blit-tech from npm:
pnpm add blit-tech
Or with npm:
npm install blit-tech
Package page: npmjs.com/package/blit-tech
Examples & Demos #
For interactive examples and demos, visit the Blit-Tech Demos repository.
Quick Start #
bootstrap() expects a canvas inside #canvas-container (defaults: canvas id blit-tech-canvas, container id
canvas-container). Pair the HTML below with a TypeScript entry module in any ESM bundler setup.
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Blit-Tech Demo</title>
</head>
<body>
<div id="canvas-container"><canvas id="blit-tech-canvas"></canvas></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
src/main.ts
import { bootstrap, BT, Color32, Palette, Rect2i, type IBlitTechDemo } from 'blit-tech';
const BG = 1;
const WATER_A = 9;
const WATER_B = 12;
class MyDemo implements IBlitTechDemo {
async init(): Promise<boolean> {
const palette = Palette.c64();
palette.set(BG, new Color32(20, 30, 40, 255));
BT.paletteSet(palette);
// Animate every pixel that uses slots 9..12 (water/lava style cycling).
BT.paletteCycle(WATER_A, WATER_B, 6);
// Quick full-screen impact flash via palette manipulation.
BT.paletteFlash(Color32.white, 120);
return true;
}
update(): void {
// fixed-step logic here
}
render(): void {
BT.clear(BG);
BT.drawRectFill(new Rect2i(100, 100, 50, 50), WATER_A);
}
}
bootstrap(MyDemo);
Scaffold and run (Vite + TypeScript):
pnpm create vite my-demo --template vanilla-ts
cd my-demo
pnpm add blit-tech
# Add the HTML and main.ts snippets above, then:
pnpm dev
Documentation #
See API: Core for bootstrap() options.
| Guide | What it covers |
|---|---|
| API: Core | bootstrap, game loop, camera, Timer, core types |
| API: Rendering | primitives, sprites, text, post-process, frame capture |
| API: Palette | palette setup, presets, effects, serialization |
| API: Assets | sprite sheets, bitmap fonts, asset loading |
| Input Guide | pointer, keyboard, gamepad |
| Palette Guide | palette-first workflow, offsets, effects |
| Palette Presets | built-in preset reference and exact color data |
| Post-Process Effects | effect chain, built-in effects, custom effects |
| Bitmap Fonts | .btfont format and BMFont conversion |
Browser Compatibility #
WebGPU support varies by browser:
| Browser | Version | Status |
|---|---|---|
| Chrome/Edge | 113+ | Enabled by default |
| Firefox | 141+ (Windows) | Enabled by default; 145+/147+ on macOS; Nightly on Linux/Android |
| Safari | 26+ | Enabled by default; Safari 18-25 available via Feature Flags |
When WebGPU is unavailable the engine falls back to the Canvas 2D software renderer automatically. A dismissible
in-canvas "SOFTWARE RENDERER" banner appears to confirm the fallback is active. Use BT.activeBackend to detect which
backend is running at runtime.
Contributors #
Contributor workflow, scripts, release process, and repository tooling docs live in Developer Experience and CONTRIBUTING.md.
License #
ISC