Dual Boundaries
Where this pack earns its paper
- tiles
- tileset
- IMAGE
- MASK
- TILESET
You've probably seen the cheap version of a seamless texture: generate once, flip or blur the seams, call it a day. It looks like exactly that. This pack - from a 2024 ACM TOG paper by Sam Sartor and Pieter Peers - does the version that actually works: instead of one self-tiling image, it produces a whole set of mutually-tileable tiles, using the diffusion model's inpainting ability to fill interiors constrained by fixed exterior boundaries. Dual Boundaries is the node that implements the paper's headline trick, the Dual Wang tiling scheme.
What it does
Dual Boundaries takes a batch of tiles you already have and recombines their edges into new exterior boundary conditions for a Dual Wang tile set. In a plain Wang tile, each edge carries one of colors labels and any two tiles whose touching edges match are compatible. The Dual Wang scheme moves the labels to the corners instead, and generates two interleaved layers - the "interior" tiles and the "cross" tiles - that composite through a diamond mask. The paper claims (and the demo really does show) better texture continuity and more variety than classic Wang tilings, because the corners force continuity in both directions at once.
That's why this node exists: it converts whatever tile material you have into the boundary conditions the inpainter needs to generate a dual set. It's the entry point for a pure dual workflow, and it's also how you upgrade a first-pass Wang set into the fancier scheme.
Inputs and outputs
- tiles (IMAGE) - your existing tile batch, and
- tileset (TILESET, forceInput) - the metadata bundle (kind, colors, resolution, candidates) that every node in this pack carries. This port is
forceInput, so you can't just type a value; it has to come from a boundary or unpacking node. Wiring the image without the tileset is the classic beginner stumble. - candidates (INT, default 1) - how many candidate versions of each boundary to emit. Raise it and you'll get more options for the rejection stage later.
Outputs are IMAGE (the assembled exterior-boundary images), MASK (the diamond-shaped interior region to be inpainted), and TILESET (now kind: dual). Wire IMAGE and MASK into InpaintModelConditioning plus a KSampler to fill the interiors, then feed the results into RejectCandidateTiles → TilePacking → RandomTiling. The included content_aware_tiles_workflow.json shows the whole chain.
Installing and the fine print
Same as every node in the pack: git clone https://github.com/samsartor/content_aware_tiles into ComfyUI/custom_nodes (or search "content_aware_tiles" in ComfyUI Manager), then restart. No models download - you bring your own checkpoint; the sample workflow uses the SD2 inpainting checkpoint.
Two gotchas worth knowing before you hit queue. First, downstream nodes will reject the dual set if you don't generate the full complement - packing and tiling demand colors**4 * 2 tiles (interior + cross), and the error message tells you exactly what it found. Second, a dual workflow is more expensive than self-tiling: you're inpainting two interleaved sets, so budget more steps and more VRAM, and consider SubBatchModel/SubBatchVAE if you're running lots of candidates at once. Also be aware this is a research pack with near-zero community discourse - you're mostly on your own if something breaks, but the code is clean and short enough to read.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| tiles | IMAGE | — | |
| tileset | TILESET | — | |
| candidates | INT | 1 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| MASK | MASK | — |
| TILESET | TILESET | — |