@zakkster/lite-wfc
v1.1.0
Published
Zero-GC Wave Function Collapse. 32-bit bitmask domains, popcount LUT, flat propagation queue.
Maintainers
Readme
@zakkster/lite-wfc
🧩 What is lite-wfc?
@zakkster/lite-wfc is a zero-allocation WFC solver for procedural tilemap generation.
It gives you:
- 🧩 Full Wave Function Collapse algorithm
- 🔢 Uint32 bitmask domains (32 tile types max)
- 📊 Precomputed popcount LUT for O(1) entropy calculation
- 📬 Flat Int32Array propagation queue (zero GC)
- 🎲 Deterministic generation via seeded RNG
- 🔄 Symmetric rule helpers
- ⏸️ Step-by-step solving for animated generation
- 🪶 < 1.5 KB minified
Part of the @zakkster/lite-* ecosystem — micro-libraries built for deterministic, cache-friendly game development.
🚀 Install
npm i @zakkster/lite-wfc🕹️ Quick Start
import { WFC } from '@zakkster/lite-wfc';
const wfc = new WFC(16, 16, 4, 42);
// cols rows tiles seed
// Define adjacency rules: tile 0 can have tile 1 to the right
wfc.addSymmetricRule(0, 1, 1); // 0=up, 1=right, 2=down, 3=left
// Solve instantly
const result = wfc.solve(); // 1 = solved, -1 = contradiction
// Read the grid
for (let y = 0; y < 16; y++) {
for (let x = 0; x < 16; x++) {
const tile = wfc.grid[x + y * 16];
drawTile(x, y, tile);
}
}
// Or solve step-by-step for animation:
// const status = wfc.solve(1); // collapse one cell per call🧠 Why This Exists
Existing WFC libraries use arrays of objects for domains and allocate per step. lite-wfc represents each cell's domain as a single Uint32 bitmask — AND operations constrain neighbors, popcount gives entropy, and a flat queue propagates constraints without allocation.
📊 Comparison
| Library | Size | Domain Repr. | Allocations | Deterministic | Install |
|---------|------|-------------|-------------|---------------|---------|
| wfc | ~15 KB | Arrays | High per step | No | npm i wfc |
| wave-function-collapse | ~10 KB | Objects | High | No | npm i wave-function-collapse |
| lite-wfc | < 1.5 KB | Uint32 bitmask | Zero | Yes (seeded) | npm i @zakkster/lite-wfc |
⚙️ API
new WFC(cols, rows, numTiles, seed?)
addRule(tileA, dir, tileB) — tileB allowed next to tileA in direction (0=up,1=right,2=down,3=left)
addSymmetricRule(tileA, dir, tileB) — Both directions at once
solve(maxSteps?) — Returns 1 (solved), 0 (in progress), -1 (contradiction)
reset(seed?) — Clear grid for a new generation
grid: Int8Array — The collapsed grid (-1 = uncollapsed, 0+ = tile ID)
🧪 Benchmark
64x64 grid, 8 tiles, full solve:
wfc.js: 25ms (object allocation per step)
lite-wfc: 8ms (bitmask AND + pre-allocated queue)📦 TypeScript
Full TypeScript declarations included in WFC.d.ts.
📚 LLM-Friendly Documentation
See llms.txt for AI-optimized metadata and usage examples.
License
MIT
