Need help with ndwfc?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

183 Stars 5 Forks MIT License 12 Commits 2 Opened issues


🌊💥 N-dimensional Wave Function Collapse with infinite canvas

Services available


Need anything else?

Contributors list

# 18,968
1 commit


A Wave Function Collapse implementation with infinite canvas in arbitrary number of dimensions.

Online Demo




// the main library
const WFC = require('./ndwfc');

// optional helpful tools const {WFCTool2D,WFCTool3D} = require('./ndwfc-tools');


The main library,

, doesn't make any assumption about what you're trying to generate. It is an abstracted implementation of the WFC algorithm, while
provide helpful functions for practical usage such as generating tiled textures or models.

Below are some sample code, but be sure to check out

for detailed usage and examples.


var nd = 2;             // number of dimensions (2, 3, etc.)
var weights = [1, 1, 1] // weight for each type of tile
                        // this also implies the total number of tiles
                        // here all weights are equal, so the tiles will
                        // generate at equal probability

// the rules is an array of 3-tuples. // for each rule, the first element specifies the axis, and the 2nd and 3rd // specifies what tiles can go next to each other on that axis

var rules = [ ['x',0,1], // 0th tile can be placed to the left of 1st tile ['x',1,0], // 1st tile can also be placed to the left of 0th tile ['y',1,2], // if you have more than 3 dimensions, the axis can be specified // using integers instead of 'x', 'y' and 'z'. // in fact 'y' is an alias of 0th axis, 'x' the 1st, and 'z' the 2nd ... ... ]

var wfc = new WFC({nd, weights, rules}); // initialize the wfc!

// define a region of interest inside which you want tiles to be generated // by passing two corners of the bounding box/cube/hypercube var size = 5; wfc.expand([-size,-size],[size,size]);

// the main loop // subsitute with setTimeout/requestAnimationFrame/WebWorker depending on usage

while (true){ var done = wfc.step(); // advance 1 step, filling at least 1 new coordinate. // step() returns true if the region of interest has // been entirely filled

if (done){ 
    size += 5           // all space filled, time to expand more
    wfc.expand([-size,-size],[size,size]);  // newly marked area will begin to 
                                            // be generated in the next step()

// ^ get the current result, an object mapping coordinate to tile index
// something like {'1,2':0, '2,2':2, '3,1':1, ...}

// use wfc.readout(false) to read the result as probability distribution,
// something like {'1,2',[1,0,0], '2,2':[0.3,0.2,0.5], ...}


Using the 2D/3D tile helpers

provides helpers for generating 2D and 3D content. You can use strings of characters to describe the semantics of your tiles, and the tool can figure out what can go next to what and generate the rules for you. Though the tool is also capable of simple visualization using canvas (2D) or three.js (3D), you can just grab the result from
and plug in your own assets such as image files and 3D models to produce the visuals you want.
// initialize the 2d tool
var tool = new WFCTool2D();

// add an 3x3 "L" shaped tile tool.addTile(\ [email protected] [email protected]@ ...) // ^ all rotated versions of the tile will also be added, // unless you specify otherwise (see below)

// add an 3x3 "I" shaped tile tool.addTile(\ [email protected] [email protected] [email protected], {transformations:['cw']}) // ^ for this tile, we only need itself and a clockwise 90 deg rotated version // for 2D tiles, transformations can include 'cw', 'fx' (flip x) and 'fy' (flip y). // you can also combine them using '+' // e.g. for anti-clockwise 90 deg rotation you can do 'cw+cw+cw' // duplicates will be detected and will not be added multiple times.

// add a plain tile tool.addTile(\ ... ... ..., {transformations:[],weight:0.1}) // you can specify the weight of the tile. higher the weight, // more often it will appear. default is 1.

// rules are automatically generated based on this logic: // only tiles with an identical edge can go next to each other, like so: // [email protected] ... // [email protected]@ + @@@ // ... ... // the tiles below can NOT go next to each other: // [email protected] ... // [email protected]@ + ... // ... ... // because the right edge of 1st tile does not match left edge of the 2nd // same for vertical axis.

// define the color of the symbols. // this is used only to quickly visualize the results // you won't need this if you're using your own assets tool.addColor("@", [255,0,0]) tool.addColor(".", [0,255,255])

// print a summary of automatically generated version of the tiles // you'll need this if you're using your own assets // each formula is a 3-tuple: // the first element is the original index (the order you called addTile) // the second element is the transformations applied (e.g. 'fx+cw') // the third element is the transformed version console.log(tool.getTileFormulae());

// this generates all the input which you can directly pass to WFC var wfcInput = tool.generateWFCInput(); var wfc = new WFC(wfcInput);

... ... // see previous section on how to use wfc ...

// visualize the output on a HTML canvas var canvas = document.createElement("canvas");

var viewport = {x:0,y:0,w:10,h:10}; // the region you want to visualize tool.plotWFCOoutput(canvas, viewport, wfc.readout()); // plot it!

is similar to
, see
for usage example.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.