A 3D Wave Function Collapse (WFC) implementation built with Three.js and TypeScript.
- 3D Wave Function Collapse: Full 3D procedural generation using WFC algorithm
- 6-way Adjacency: Supports up, down, north, south, east, west neighbor constraints
- Web Worker Support: Asynchronous generation to keep UI smooth
- Dual Rendering Modes:
- Voxel-based: Simple colored cubes for prototyping
- Model-based: GLB file support with instanced rendering for memory efficiency
- Interactive Demos:
- Voxel with simple terrain generation
- World with 3D asset loading
- Adjacency Builder Tool: Visual interface for building tile adjacency rules
- 3D preview of tile pairs
- Automatic symmetry enforcement
- Export to JSON or GLB formats
- Continue from existing tilesets
- Customizable Tilesets: Easy-to-configure tile adjacency rules
- TypeScript: Fully typed codebase
- Memory Efficient: Uses InstancedMesh for rendering thousands of models
npm install three-collapse threeThe WFCGenerator class is the main entry point - it handles workers, retries, expansion, and real-time updates automatically:
import { WFCGenerator } from "three-collapse";
// Create generator
const generator = new WFCGenerator(myTileset, {
workerCount: 4,
maxRetries: 3,
autoExpansion: true,
});
// Generate with real-time tile updates
const grid = await generator.generate(20, 10, 20, {
onProgress: (progress) => console.log(`${(progress * 100).toFixed(1)}%`),
onTileUpdate: (x, y, z, tileId) => renderer.updateTile(x, y, z, tileId),
});
// Clean up
generator.dispose();π See WFCGenerator Usage Guide for complete documentation.
For lower-level control, you can use the core WFC classes directly:
import { WFC3D, WFCTile3D, VoxelTile3DConfig } from "three-collapse";See LIBRARY_USAGE.md for advanced usage examples.
Clone the repository and install dependencies:
git clone https://github.com/yourusername/three-collapse.git
cd three-collapse
npm installnpm run devOpen your browser to the URL shown in the terminal (typically http://localhost:5173)
Available Demos:
/- Voxel-based demo (colored cubes)/models.html- Model-based demo (GLB files)/adjacency-builder.html- Manual adjacency builder tool/connector-builder.html- Connector-based adjacency builder (recommended)/vr-demo.html- VR demonstration
npm run buildimport { WFC3D, WFCTile3D, VoxelTile3DConfig } from "./src/wfc3d";
// Define voxel tiles
const tiles = [
new WFCTile3D({
id: "grass",
weight: 1,
color: "#7CFC00",
adjacency: {
up: ["air"],
down: ["dirt"],
// ... other directions
},
} as VoxelTile3DConfig),
// ... more tiles
];
// Create WFC instance
const wfc = new WFC3D({
width: 8,
height: 8,
depth: 8,
tiles,
seed: 12345, // Optional seed for reproducible results
});
// Generate
const success = await wfc.generate((progress) => {
console.log(`Progress: ${progress * 100}%`);
});
if (success) {
// Access generated voxels
const tileId = wfc.buffer.getTileAt(x, y, z);
}const worker = new Worker(new URL("./wfc.worker.ts", import.meta.url), {
type: "module",
});
worker.postMessage({
type: "generate",
width: 8,
height: 8,
depth: 8,
tiles: tilesetConfig,
seed: 12345,
});
worker.onmessage = (e) => {
if (e.data.type === "complete") {
const voxelData = e.data.data; // 3D array of tile IDs
}
};import { WFC3D, WFCTile3D, ModelTile3DConfig } from "./src/wfc3d";
import { GLBTileLoader } from "./src/loaders/GLBTileLoader";
import { InstancedModelRenderer } from "./src/renderers/InstancedModelRenderer";
// Define model tiles
const modelTiles: ModelTile3DConfig[] = [
{
id: "block",
weight: 2,
filepath: "/models/block.glb",
adjacency: {
up: ["block", "air"],
down: ["block", "base"],
// ... other directions
},
},
// ... more tiles
];
// Load GLB models
const loader = new GLBTileLoader();
const modelData = await loader.loadTileset(modelTiles);
// Create and run WFC
const tiles = modelTiles.map((config) => new WFCTile3D(config));
const wfc = new WFC3D({ width: 10, height: 8, depth: 10, tiles });
const success = await wfc.generate();
if (success) {
// Render using instanced meshes
const renderer = new InstancedModelRenderer(scene, modelData, 1);
const gridData = []; // Extract 3D array from wfc.buffer
renderer.render(gridData);
}Building correct adjacency rules is crucial for WFC. We provide two tools:
Automated adjacency generation using connector-based system inspired by Marian42's WFC implementation.
Key Features:
- O(N) connector assignments instead of O(NΒ²) pair reviews
- Grid layout with drag selection
- Automatic adjacency generation from connectors
- Directional exclusion rules
- Transform controls for tile positioning
Usage:
import { ConnectorBuilderUI } from "three-collapse";
new ConnectorBuilderUI({
gridSpacing: 3,
});Web Interface:
- Navigate to
/connector-builder.html - Load GLB files (directory or upload)
- Select tiles and edit their face connectors
- Click "Auto-Generate Adjacencies"
- Export GLB files with embedded data
π See Connector Builder Guide for details.
π See Technical Documentation for implementation.
Traditional pair-by-pair review interface for precise control.
Programmatic Usage:
import { AdjacencyBuilderUI } from "three-collapse";
new AdjacencyBuilderUI({
existingTileset: myTileset,
onExportJSON: (json) => {
console.log("Exported:", json);
},
});Web Interface:
- Navigate to
/adjacency-builder.html - Choose your input mode (Auto-discover / Upload / Continue)
- Review each tile pair direction-by-direction
- Export to JSON or GLB format
The tool automatically enforces symmetry and optimizes self-pair comparisons.
π See Adjacency Builder API for programmatic usage.
π See Adjacency Builder Guide for web interface usage.
- WFCTile3D: Represents a single tile type with adjacency rules
- WFC3DBuffer: Manages the 3D grid and cell states
- WFC3D: Main solver that implements the WFC algorithm
- wfc.worker.ts: Web Worker wrapper for async generation
src/
βββ wfc3d/ # Core WFC modules
β βββ WFCTile3D.ts # Tile definitions (Voxel & Model)
β βββ WFC3DBuffer.ts # Grid buffer
β βββ WFC3D.ts # Main solver
β βββ index.ts # Module exports
βββ loaders/
β βββ GLBTileLoader.ts # GLB model loader with caching
βββ renderers/
β βββ InstancedModelRenderer.ts # Instanced mesh renderer
βββ wfc.worker.ts # Web Worker
βββ main.ts # Voxel
examples/
βββ models/
β βββ demo.ts # Model-based demo
βββ tiles/
βββ voxels/
β βββ tileset.ts # Voxel tileset
βββ models/
βββ tileset.ts # Model tileset
public/
βββ models/ # GLB model assets
βββ README.md # Asset documentation
- Generate: Generate a new voxel world with current seed
- Random Seed: Generate a new random seed
- Seed Input: Enter a specific seed for reproducible results
- Mouse: Orbit camera around the scene
- Scroll: Zoom in/out
- Generate: Load models and generate using WFC
- Random: Generate with a new random seed
- Seed Input: Enter a specific seed for reproducible results
- Mouse: Orbit camera around the scene
- Scroll: Zoom in/out
Note: The World requires GLB files in the /public/models/ directory. See /public/models/README.md for details on obtaining free 3D assets.
The 3D Wave Function Collapse algorithm works by:
- Starting with all cells in superposition (all tiles possible)
- Selecting the cell with minimum entropy (fewest possibilities)
- Collapsing it to a single tile based on weighted random selection
- Propagating constraints to neighbors in all 6 directions
- Repeating until all cells are collapsed or a contradiction occurs
MIT - See LICENSE file for details