Strategies & Example Workflows Monoceros 3
Practical strategies and step-by-step example workflows for Monoceros 3. If you are new to Monoceros, start with the Quick Start guide first. For frequently asked questions and practical tips, see FAQ & Tips. For data type and component reference, see the main documentation.
Documentation
Complete reference for all data types and Grasshopper components.
FAQ & tips
Frequently asked questions, tips & tricks for common workflows and troubleshooting.
Use your AI agent
Get instant help from ChatGPT, Claude, Gemini, or any AI assistant using the official Monoceros documentation.
Join a workshop
Hands-on workshops covering Monoceros fundamentals, module design, and advanced workflows.
Bare minimum ↓ GH
The simplest possible Monoceros setup - one module, one rule, one solver call. Grasshopper file for download.
Puzzle ↓ GH
Interlocking puzzle-piece modules that can only connect one way. Grasshopper file for download.
Table of contents
- 1. What are the main strategies for using Monoceros?
- 1.1 How do I design top-down (envelope first)?
- 1.2 How do I design bottom-up (Modules first)?
- 1.3 How do I iterate and refine a Monoceros design?
- 1.4 How do I use Monoceros at multiple scales?
- 1.5 Debugging strategy
- 1.6 Fabrication-oriented workflow
- 1.7 Spatial weight gradients
- 1.8 System-based Module design
- 2. Example Workflows
- 2.1 Bare minimum
- 2.2 Extending the bare minimum
- 2.3 The Assembly workflow
- 2.4 Using Connectors for rotation-aware rule generation
- 2.5 Combining Connectors with explicit Rules
- 2.6 Empty Module
- 2.7 Rotating the envelope base plane
- 2.8 Defining Rules from Faces
- 2.9 Working with multiple Modules
- 2.10 Automatic Module rotations
- 2.11 Heterogeneous grid
- 2.12 Weighted Module placement
- 2.13 Boundary handling
- 2.14 Constructing Slots from geometry
- 2.15 Fixing Modules in the Envelope
- 2.16 Disallowing Rules
- 2.17 Rule Exclusivity
- 2.18 Megamodule construction
- 2.19 Materializing results
- 2.20 Solver settings
- 2.21 Audit-driven debugging
- 2.22 Visualizing Rules and Faces
- 2.23 Grid topology analysis
- 2.24 Rules from Face Groups
- 2.25 Proto-results workflow
- 2.26 2D grids (floor layouts and panel systems)
- 2.27 Sparse grids with intentional gaps
- 2.28 Rectangular (non-square) Modules
- 2.29 Combining manual and automatic Rules
- 2.30 Restricting Modules to specific regions
- 2.31 Occurrence Count analysis
- 2.32 Exporting results for fabrication
- 2.33 Auditing an Assembly
- 2.34 Iterative solving with partial results
- 2.35 Marking unused Faces as Terminators
- FAQ & Tips →
1. What are the main strategies for using Monoceros?
1.1 How do I design top-down (envelope first)?
When a spatial volume already defines the constraint - a site boundary, a building Envelope, a specific Rhino shape - define the Envelope first and derive the Module vocabulary from it. Working from the outside in respects spatial constraints before committing to Module design.
- Define the Envelope shape in Rhino (a Brep, Mesh, or Surface).
- Use Grid Boxes From Geometry to convert it into Grid Boxes.
- Choose cell dimensions that suit the design intent.
- Design Modules to fit the cell size.
- Define Rules and solve.
Best for: Site-specific projects, spatial planning, filling existing volumes.
1.2 How do I design bottom-up (Modules first)?
When a library of physical or designed Module pieces already exists, let the Modules define the grid rather than the other way around. Grid dimensions derive from the Module size; the WFC engine combines the pieces into coherent assemblies.
- Design Module geometry in Rhino at a specific scale.
- Construct Modules with Construct Module.
- Generate rotations with Module Rotations.
- Suggest Rules with Suggest Rules From Voxels.
- Create a simple grid matching the Module dimensions.
- Solve and iterate on the Rules.
Best for: Product design, pattern generation, fabrication-driven projects.
1.3 How do I iterate and refine a Monoceros design?
When initial results are not quite right - certain Module types are too common, unexpected adjacencies appear, or the Solver fails after scaling up - refine incrementally rather than rebuilding from scratch. The approach is a tight loop between solving and adjusting.
- Start with a rough Module set and simple Rules.
- Solve on a small grid (e.g. 5×5×5).
- Analyze the result: are Modules distributed well? Are there undesired adjacencies?
- Adjust Rules: add disallowed pairs, modify Weights, add boundary constraints.
- Scale up the Envelope gradually.
Best for: Exploratory design, prototyping, complex Rule sets.
1.4 How do I use Monoceros at multiple scales?
When a design operates at two or more scales simultaneously - large zones (Assembly, logistics, residential) at one resolution, detailed Module filling within each zone at a finer resolution - apply WFC twice rather than using a single unmanageable grid.
- Solve a coarse grid first (large cells, few Modules representing zones: Assembly, logistics, residential, etc.).
- Use the coarse result as input for a finer grid: each coarse Module defines the Module palette for the corresponding fine-grid region.
- Solve the fine grid with per-region Module assignments.
A variation that avoids maintaining two grids of different resolution: run the coarse pass on the same grid and Envelope, but with a drastically reduced Module palette - one Module type per functional zone (Assembly, logistics, residential, etc.). Clustering is not automatic and achieving large, contiguous zones is non-trivial; dedicated clustering strategies must be applied, or the Solver run many times until a result with a convenient zone layout is found. The boundary between zones can be geometrically rich, shaped by the Faces you define. Once the clusters are determined, extract each zone's occupied Slots as a new, independent Envelope and run a second WFC pass on it with a richer Module palette and a ruleset tailored to that zone.
Best for: Mixed-use layout planning, large facility design, hierarchical Assembly line design.
1.5 Debugging strategy
When the Solver fails or produces unexpected results, use Audit Assembly to diagnose. Connect both your input Assembly (before solving) and the Solver's output Assembly (after solving) to Audit Assembly to compare what changed. The Audit report covers Envelope validity, Slot configuration, Module coverage, and Rule completeness. See 2.21 Audit-driven debugging for the full workflow.
1.6 Fabrication-oriented workflow
When a WFC result will be physically built - 3D printed, laser cut, CNC milled, or assembled from prefabricated parts - account for material constraints, Assembly sequence, and manufacturing limitations from the start.
- Module design - Design Modules around your fabrication method. For 3D printing: ensure overhangs stay within printable angles. For CNC: avoid undercuts. For laser cutting: keep panels flat and unfoldable.
- Face design - If physical Faces exist (tabs, Slots, magnets), model them as part of the Module geometry. Use Suggest Rules From Geometry so that only Modules with matching physical Faces are paired. Module geometry may protrude outside the Grid Box: bolts, screws, or latching tabs intended to physically join adjacent Modules can be modelled this way. Design the matching receiving feature into the neighbouring Module. The Solver is unaware of geometry and will not flag protrusions.
- Scale and tolerance - Set cell dimensions to match your real-world unit. Account for material thickness and Assembly tolerances.
- Solve and count - Use Occurrence Count to produce a bill of materials. Verify that each Module type is fabricable in the required quantity.
- Export - See example 2.32 Exporting results for fabrication.
Best for: Pavilion design, discrete furniture, modular construction, prototyping.
1.7 Spatial weight gradients
By default WFC distributes Module types evenly across the Envelope. Weight gradients let you override this: assign a high Weight to a Module only in the region where you want it to appear, and a near-zero Weight everywhere else. This steers the result without hard constraints - the Solver can still deviate, but it will prefer the weighted choice.
The technique consists of computing a per-Slot number from geometry (distance to a point or curve, height, proximity to an edge, etc.), remapping that number to a Weight range, and feeding the result to the relevant Module’s Weight input on Construct Slot. Each Slot gets its own Weight for each Module. Setting a Weight to exactly 0.0 (not just low) prevents the Solver from ever placing that Module in that Slot.
A concrete example: a 2D panel grid where access hatches should cluster at maintenance height and solid panels should dominate near the base. Assign each Slot’s Z-coordinate to the hatch Module Weight (remapped so Weight peaks at waist height) and invert the same curve for the solid Module Weight. Define edge-profile Rules so adjacent panels always produce continuous joint lines, and add dedicated boundary Modules for sill, cap, and corners. Running the Solver then produces a panel distribution driven by the gradient, not by a fixed pattern.
Best for: Facade panelling, floor layout zoning, any design where different Module types belong in different spatial regions.
1.8 System-based Module design
When a design contains multiple independent spatial systems - circulation, structure, services, landscaping - trying to design all Modules at once produces an unmanageable combinatorial explosion. Instead, treat each system as a separate design problem and connect them through a thin layer of interface Modules.
Step 1: Identify the spatial systems
List the distinct systems in the design. Each system has its own spatial logic and its own vocabulary of elements. Examples: a road network (straight, curve, intersection, dead-end), a building grid (column, beam, slab, void), a landscape layer (path, planting, water, edge). Systems are independent if their internal connectivity Rules do not depend on each other.
Step 2: Design Modules per system
For each system, design the Modules that handle its internal connectivity.
A typical set includes: straight, corner (90°), T-junction, crossing,
dead-end, and empty. Follow the
Module design principles - exciting
middle, boring edges, half-size scale - within each system
independently. Name Modules with a system prefix
(e.g. road-straight, road-corner,
green-path, green-planting).
Step 3: Design interface Modules
Where two systems meet, create dedicated interface Modules. An interface
Module has Faces that match system A on some Faces and system B on
others. For example, a road-edge Module has road-compatible
Faces on one side and greenery-compatible Faces on the opposite
side. Keep the number of interface Modules small - the goal is a
controlled bridge, not a full mesh between systems.
Step 4: Define Rules within each system first
Build and test Rules for each system independently on a small Envelope (e.g. 5×5×1). Verify that the Solver produces valid configurations for each system in isolation before combining. This makes debugging far easier - if a system works alone but fails when combined, the problem is in the interface Rules, not the system itself.
Step 5: Add cross-system Rules through interface Modules
Once each system works independently, add Rules that connect interface Modules to both systems. Run the combined Solver on a small Envelope and verify that systems interact correctly at their boundaries. Scale up the Envelope only after the combined Rule set is stable.
Best for: Complex designs with multiple interacting spatial systems, projects with clear system boundaries (urban planning, building services, multi-layer facades).
See also workflows and FAQs: FAQ 1.5 What makes a good Module?, 2.9 Working with multiple Modules, 2.30 Restricting Modules to specific regions.
2. Example Workflows
2.1 Bare minimum
This is the true bare minimum to get Wave Function Collapse running end-to-end in Monoceros. Nothing here is designed - the goal is to confirm the entire pipeline works, from defining a Module and its Rules through to seeing materialized geometry in the viewport. Once you have this working, you can add more Module types, define richer Rules, change the Envelope shape, and iterate from there.
The Solver supports up to 16,370 distinct Module Names across all Slots. Each rotation variant counts as a separate name, so the limit applies to the expanded set after applying the Module Rotations component.
Concept
Every Monoceros definition needs five things before it can run:
- A Module - the design element the Solver places, carrying optional geometry and six Faces (+X, −X, +Y, −Y, +Z, −Z).
- Rules - allowed adjacencies between Faces. A
Rule is always between two Faces that point in opposite Directions on the
same Axis (for example
+Xand-X). Any Face that has no Rule at all is called an Indifferent Face and behaves differently: you only define Rules for the Faces where you want to control what may be adjacent (explained below). - An Envelope - the spatial field to fill. You create Grid Boxes with a grid component and then convert each Grid Box into a Slot, specifying which Modules that Slot is allowed to contain. The resulting collection of Slots is the Envelope.
- The WFC Solver - the component that runs the algorithm and returns solved Slots. The Solver assigns exactly one Module to every Slot in the Envelope. It does not leave cells unoccupied or skip areas where no Module fits well: it either fills everything completely, or it reports a Contradiction and returns no result.
- A Materialize step - turns the solved Slot assignments into visible geometry.
- An Assembly - the single object that packages Modules, Slots, and Rules for the Solver. Created by Construct Assembly, which also generates rotation variants and runs an internal Audit.
A 1×1×1 Envelope technically works: the Solver places the one allowed Module without Contradiction. But with only a single Slot there are no neighbours, so no Rule is ever evaluated. The smallest Envelope where at least one Rule is actually exercised is 2×1×1 - two adjacent Slots that must agree on their shared Face. For this example, 5×5×5 (or 5×5×1 for a flat layout) is a much better starting point. It is still fast to solve and small enough to inspect visually, but large enough that every interior Slot has six neighbours and every Rule is exercised multiple times. A 3×3×3 grid can produce degenerate or ambiguous results with certain Rule combinations that a slightly larger grid resolves clearly.
For geometry, use a simple line segment running from the centre of the
-X Face to the centre of the +X Face of
the cell - imagine it represents a pipe in the real world. Once the
bare minimum is working, you can replace the straight pipe with an
L-shape, a cross, or other curve configurations and explore how the
Rules and Solver respond.
Implementation
Define the Module and Rules first, then create the Envelope. This order mirrors the conceptual flow: design the discrete element, specify how the elements connect, then provide the space to fill.
-
Establish a shared cell size - Add a Vector parameter (or
a Panel) with value
{1, 1, 1}. You will feed this same vector as the Diagonal input into every Homogeneous Grid component in the definition. Using one shared vector guarantees that Module Grid Boxes and Envelope Slots always have identical dimensions, which the Solver requires. -
Create a Module Grid Box - Place a Homogeneous Grid with
the shared diagonal vector, counts of
1×1×1(the defaults), and a base plane with its origin somewhere clearly away from where the Envelope will sit - for example at{-10, 0, 0}. The origin of the base plane marks the centre of the Grid Box. The plane Axes set the Orientation of the grid. Place it with enough room for future Modules. -
Draw the pipe geometry - Create a line from point
{-10, 0.5, 0.5}to{-9, 0.5, 0.5}. This runs through the centre of the Module cell from its-XFace to its+XFace, clearly showing the pipe's entry and exit. -
Construct the Module - Use Construct Module with name
pipe, the single Grid Box from step 2, and the line from step 3 as geometry. -
Get the Faces - Connect the Module to
Get Module Faces. It outputs six Faces as separate named parameters:
+X,-X,+Y,-Y,+Z,-Z. -
Define one Rule - Wire the
+XFace into the Source Faces input of Construct Rules From Faces, and the-XFace into the Target Faces input. This single Rule says that the exit of one pipe Module may sit adjacent to the entrance of another - the pipe continues without leaking. The four remaining Faces (+Y,-Y,+Z,-Z) have no explicit Rule because it doesn't matter what is placed next to a pipe. In Monoceros, a Face with no Rule is called an Indifferent Face. When indifference is enabled on Construct Assembly, every Indifferent Face automatically pairs with any other Indifferent Face facing the opposite Direction on the same Axis. For this example that means pipe sides can sit next to each other freely without any extra Rule definitions. For a detailed explanation of Indifferent Faces and how to define them manually when needed, see 2.8 Defining Rules from Faces. -
Create the Envelope Grid - Place a second
Homogeneous Grid with the same shared diagonal vector and counts of
5 × 5 × 5(or5 × 5 × 1for a flat layout). Set the base plane to wherever the Envelope should appear in the scene - the origin of that plane marks the centre of the first Slot, and the plane Axes set the Envelope’s Orientation. For a first test, the world origin works fine. Because the diagonal vector is shared with step 2, every Grid Box here is identical in size to the Module's Grid Box. - Construct Slots - Use Construct Slot with all Grid Boxes from the Envelope grid. Leave the Allowed Module Names input unconnected: Construct Assembly will resolve the Slots to the full Module set automatically, which is what you want for the bare minimum where every Slot accepts every Module. (Wiring the Module Name explicitly still works; it is simply not required.)
- Construct Assembly - Feed the Module, Slots, and Rules into Construct Assembly. Enable Indifference if you want uncovered Faces to pair freely. The component packages everything into a Discrete Assembly.
- Solve - Connect the Assembly to the WFC Solver. The Solver runs Wave Function Collapse and returns an output Assembly with solved Slot states.
- Materialize - Connect the Solver's Assembly output to Materialize Assembly. For each solved Slot, the component locates the corresponding Module (including rotation variants), transforms its geometry into the Slot's position, and outputs the result. You should see a uniform grid of pipe lines. To keep the geometry in Grasshopper, route the output into other components as normal. To bring the result into Rhino, bake Materialize Assembly directly - this creates block instances in the document - or route the output through a floating Geometry parameter and bake that parameter to get the geometry as individual objects.
2.2 Extending the bare minimum
The bare minimum produces a first result, but a uniform pipe grid has limited design value. The sub-sections below describe the most productive next steps, each introducing one concept and pointing to the dedicated example that covers it in full.
Expanding the Module vocabulary
Model a second pipe as an L-shape: one line segment along one Axis and another segment bent 90° onto a second Axis, both meeting at the cell centre. Each Module type needs its own Rules, but that is not enough on its own. Three sets of Rules are required in total:
- Straight-to-straight - the straight pipe continues linearly (already defined in 2.1).
- L-to-L - two L-pipes meeting at their open ends.
- Straight-to-L and L-to-straight - the transition from a straight run into a corner and back. Without these cross-Rules the Solver sees the two Module types as incompatible and will contradict whenever it tries to place them adjacent to each other.
Merge all three Rule lists together before passing them to the Solver. Merge the two Module lists the same way. Make sure both of the lists are flat - if not, flatten them first. For the full workflow of managing multiple Module types see 2.9 Working with multiple Modules.
Simplifying Rule definition with Face type grouping
Listing every cross-Module Rule explicitly becomes tedious as the Module set grows. A more scalable approach is to assign all Faces that should be interchangeable to the same type - a conceptual grouping you maintain on the Grasshopper canvas. Face objects carry no type field themselves; the type is simply the list you collect them into.
In practice: extract the open-end Faces from both the straight pipe and the L-pipe using Get Module Faces. Collect them all into one list - this list is the type. Feed that same list into both the Source Faces and Target Faces inputs of Construct Rules From Faces. The component generates every pairwise combination - straight-to-straight, L-to-L, and all cross-pairings - in a single operation, replacing the three manually merged Rule lists from above.
See 2.24 Rules from Face Groups for the full technique applied to larger Module libraries.
Generating rotation variants automatically
The simplest way to create rotation variants is to set the Rotate X, Rotate Y, or Rotate Z flags directly on Construct Module. Construct Assembly will automatically expand these into all valid rotation variants and generate the corresponding Rules. For finer control (for example custom deduplication or selecting specific rotations), use the dedicated Module Rotations component described below.
Both the straight pipe and the L-pipe have multiple valid orientations. Rather than
modelling each by hand, feed either Module into Module Rotations and enable
rotations around whichever Axes make sense. The component produces counter-named
variants (pipe-0, pipe-1, pipe-2, …
and L-pipe-0, L-pipe-1, …) and already includes the
identity rotation, so you replace the original Module output with the rotation output
everywhere downstream. See 2.10 Automatic Module
rotations.
Alternatively, instead of defining Rules from Faces, you can use Connectors - named interfaces placed on Module Faces with symmetry flags. Declare which Connector types are compatible via Connector Pairs, and Construct Assembly generates the corresponding Rules automatically. See 2.4 Using Connectors for details.
Restricting specific adjacencies
The Disallowed Rules input on Construct Assembly lets you remove specific pairings from an otherwise complete Rule set. Two immediately useful applications on the pipe example:
- No long straight runs. Disallow the straight pipe from connecting to itself along its own Axis. The Solver must always turn, producing only meandering paths.
- No winding paths. Conversely, disallow the L-pipe from connecting to any other L-pipe. Consecutive corners are prevented, so runs of straight pipe are forced between every turn.
Remember to apply the disallow Rule to all rotation variants, not just the base Module. See 2.16 Disallowing Rules.
The Rules you connect to the Disallowed Rules input are ordinary Rules - constructed by the same methods as the rest of your Rule set. The typed-Face workflow (see 2.8 Defining Rules from Faces) is particularly precise for this: assign distinct Face types to the two Faces whose pairing you want to forbid, run Construct Rules From Faces to produce exactly those Rules, and connect them to the Disallowed Rules input of Construct Assembly. Alternatively, connect unwanted Connector Pairs to the Disallowed Connector Pairs input.
Adding an empty Module
An empty Module represents a void - a Slot the Solver may leave without visible geometry - and gives the Solver freedom to leave gaps in the pipe network. See 2.6 Empty Module.
The empty Module is also a practical escape hatch when the Solver cannot find any solution at all. A setup without it can be too constrained: the Modules and Rules together may leave no arrangement that satisfies every Slot simultaneously, so the Solver reports a Contradiction or returns no result. Adding an empty Module loosens the constraint space - where a forced adjacency would otherwise be impossible, the Solver can now place a void instead. Many setups that appear stuck become solvable as soon as an empty Module is included. The trade-off is explicit: the resulting layout will contain gaps, so the solution is structurally different from what a fully-packed arrangement would produce. Whether that is acceptable depends on the design intent, but it is often preferable to no solution at all.
Enforcing containment at the envelope boundary
Without boundary handling, outward-facing Faces at the Envelope edge have no neighbouring Slot. The Solver applies no constraint from that Direction. Instead, those Faces are simply unconstrained: any Module is valid at a boundary Slot regardless of what Face points outward. The boundary Slots are constrained only from inside the Envelope. For pipes this means open ends can appear at the grid surface; the pipe network “leaks” out of the Envelope.
One effective solution for the pipe example: add a surrounding layer of boundary Slots and fill it with empty Modules, but allow those empty Modules only to connect to the non-pipe-end Faces of the pipe Modules - the “sides” that carry the Indifferent or neutral Face type, not the pipe-opening Face. Because no pipe-end Face is allowed to Face the boundary layer, the Solver is forced to route every pipe opening inward. The result is a self-contained loop topology: every pipe end must connect to another pipe end within the Envelope, and nothing leaks out. See 2.13 Boundary handling.
Rotating the envelope base plane
Homogeneous Grid accepts any plane as its base, so the Envelope can live anywhere in space at any angle. Module geometry stays in local coordinates and is transformed by Materialize accordingly. See 2.7 Rotating the envelope base plane.
2.3 The Assembly workflow
The Assembly (formally Discrete Assembly) is the single object that packages Modules, Slots, Rules, Connectors, and Connector Pairs into a ready-to-solve unit. A single Construct Assembly component takes all these inputs, generates rotation variants and the full Rule set, runs an internal Audit, and produces the Assembly object. The WFC Solver accepts an Assembly directly.
Workflow
- Prepare Modules, Slots, and (optionally) explicit Rules as before.
- Define Connectors and Connector Pairs (see 2.4).
- Connect everything to Construct Assembly. The component generates all Module rotation variants, merges explicit Rules with Connector-generated Rules, and runs an Audit. Inspect the Audit output to catch setup errors early.
- Connect the Assembly to the WFC Solver. The Solver reads Modules, Slots, and Rules from the Assembly directly.
- After solving, use Materialize Assembly to extract placed geometry from the solved Assembly. Alternatively, use Deconstruct Assembly to extract Modules, Slots, and Rules for further processing.
The WFC Solver takes a Discrete Assembly as its sole data input. All Modules, Slots, Rules, Connectors, and Connector Pairs are packaged into the Assembly before solving.
2.4 Using Connectors for rotation-aware rule generation
A Connector combines interface identity (name + symmetry) with placement (Module + Face + rotation) in a single object. Think of a Connector the way you think of a USB socket on a device: it has a specific type, a specific Orientation, and only mates with a compatible counterpart. All Connectors sharing the same name are the same type. Each Connector carries symmetry flags for 0°, 90°, 180°, and 270°, which tell the Solver which rotational orientations are considered identical.
Instead of manually creating Rules for every valid Face pairing, you create Connectors on the Module Faces that need them, declare which Connector names can connect via Connector Pairs, and let Monoceros generate the corresponding Rules automatically. This is especially powerful when Modules have many rotation variants - the Connector system handles all rotational bookkeeping for you. There is no separate type-definition step: every Connector already carries its type identity and its placement.
Steps
- Create Connectors with Connector From Face (formerly
Construct Connector). Give each Connector a name (e.g.
"pipe_end","flat_wall"), set its symmetry flags, and specify the Module and Face it belongs to. A Connector that looks the same at every 90° turn (like a round pipe) has all four flags set totrue. A Connector that has a distinct top and bottom (like a door frame) may only have the 0° and 180° flags set. - Alternatively, use Connector From Point to author Connectors by clicking on a Module Face in the Rhino viewport: wire a Point3d tag on the Face, the Modules list, and the name and symmetry flags, and the component returns one Connector per matched Face in a single step (Face lookup + Connector construction combined).
- Or use Suggest Connectors From Geometry or Suggest Connectors From Voxels to derive Connectors automatically by comparing Module Face geometry. These components take one Connector as an exemplar and assign matching Connectors to all Modules with matching Face content.
- Declare which Connector names can connect using
Construct Connector Pair. It takes single items:
Source Connector + Target Connector produces one Connector Pair.
Use Grasshopper’s Cross Reference to make multiple pairs.
pipe_end → pipe_endmeans a pipe end can connect to another pipe end, butpipe_end → flat_wallis a separate declaration. - Feed Modules, Slots, Connectors, and Connector Pairs into Construct Assembly. The Assembly bundles everything together, generates all rotation variants and the full Rule set, and runs an internal Audit.
When to use Connectors
- Many rotation variants - Connector symmetry flags eliminate the need to manually enumerate every rotated Face pairing.
- Physical Connector interfaces - When Module Faces represent physical Connectors (pipe ends, beam flanges, panel clips), Connectors model them naturally.
- Large Module libraries - Defining a handful of Connector names is faster than creating hundreds of individual Rules.
Practical examples
The following scenarios show how a small number of Connector names and Connector Pairs can replace dozens of explicit Rules.
- Wall-to-wall connections. Name all wall cross-section
Faces
"wall". Create a single Connector Pairwall → wall. Construct Assembly generates all wall-to-wall Rules automatically, including every rotation variant. Any Module whose wall Face has the same Connector name will connect to any other Module with a matching wall Face. - Open-to-open and solid-to-solid. Name open Faces
"open"and solid Faces"solid". Create two Connector Pairs:open → openandsolid → solid. Modules will never place an opening against a solid wall, because the two Connector names are never paired. - Directional connections (floor/ceiling). Name floor
Faces
"floor-top"and ceiling Faces"floor-bottom". Create one Connector Pair:floor-top → floor-bottom. This ensures floors always stack correctly regardless of Module rotation - a floor surface always Faces a ceiling surface, never another floor or an unrelated Face.
2.5 Combining Connectors with explicit Rules
Connectors and explicit Rules are not mutually exclusive. You can use Connectors for the bulk of adjacency logic and add explicit Rules for special cases that Connectors cannot express - for example, a one-off connection between two specific Module Faces that does not fit any Connector name.
Strategy
- Define Connectors for the general connectivity pattern (see 2.4).
- Create additional explicit Rules for specific pairings that fall outside the Connector system - e.g. a structural column Module that must always sit below a beam Module regardless of Connector name.
- Connect any unwanted Rules to the Disallowed Rules input of Construct Assembly, or connect unwanted Connector Pairs to Disallowed Connector Pairs.
- Feed all inputs - Modules, Slots, explicit Rules, Connectors, and Connector Pairs - into Construct Assembly. The Assembly merges Connector-generated and explicit Rules into a single set.
Tips
- Connector-generated Rules and explicit Rules can overlap. Duplicates are harmless - the Solver ignores them.
- Use Deconstruct Assembly to extract the merged Rule set, or Audit Assembly to inspect diagnostic outputs and verify that both Connector-generated and explicit Rules are present.
- When a Connector-generated Rule creates an unwanted adjacency, connect the unwanted Rules to the Disallowed Rules input of Construct Assembly rather than redesigning the Connector name.
2.6 Empty Module
If you want the Solver result to contain voids, blank areas, or gaps - areas with no visible geometry - you need an empty Module. Without one there is simply no way to achieve this: the WFC Solver always fills every Slot with exactly one Module and has no concept of leaving a position unoccupied. An empty Module is a designated placeholder that carries no geometry, giving the Solver a legal option for any Slot you do not want filled with purposeful content.
Steps
- Create a Module with a distinctive name such as
empty. Leave the geometry input unconnected in Construct Module. The bounding box is inferred from the Grid Box alone, so the Module is spatially valid with no geometry. - Add
emptyto the Allowed Modules list for Construct Slot, alongside all other Module Names that Slot may contain. Every Slot in the Envelope must list every Module permitted to occupy it. - Define the adjacency behaviour of the empty Module. Two approaches:
With indifference enabled (the default): define no explicit Rules for
empty. All six of its Faces become Indifferent, pairing freely with any other Indifferent Face facing them. The empty Module sits silently next to any neighbour that also has an Indifferent Face on the facing side, with no Rule entries required.With indifference disabled, or when you need explicit control: define Rules for each Face of
emptythat you want it to connect to. Only the pairings you create will be allowed; Faces with no Rule will accept nothing. This approach is more work but gives precise control over where the empty Module may appear. - Consider which Slots the empty Module should be permitted to enter. If you
want to exclude it from specific zones or limit it to certain regions, remove
emptyfrom the Allowed Modules list of those Slots when constructing them. Slot-level allowed names are the primary tool for controlling Module placement spatially.
What Materialize produces
Materialize outputs no geometry for Slots assigned the empty Module. Those Slots appear blank in the viewport. This is intentional: an empty Module is a spatial placeholder, not a visible element.
Filler and padding Modules
The empty Module is the minimal case of a broader pattern. Any Module designed to be placed broadly across the Envelope - contributing little or no programmatic content but making the layout work - serves the same function. Whether it carries geometry is a design decision: a grass lawn, a structural void, a plain open courtyard, or a neutral corridor section can all fill this role.
What these Modules share is a deliberately permissive Face design. All six Faces carry Rules, but those Rules are written to match a wide range of neighbours rather than demanding specific pairings. A grass lawn in an urban layout has explicit Rules on bottom and top Faces and the horizontal Faces may remain unassigned and therefore Indifferent, so the Solver can place it in many contexts without Contradiction. The breadth of what it accepts is a design decision, expressed through the Rules, not a default behaviour.
This permissiveness is a practical tool for unblocking overconstrained setups. When the Solver cannot find a complete arrangement, it usually means some Slot has no Module that satisfies all its neighbour constraints simultaneously. Adding a broadly-accepting filler Module gives the Solver a legal option for those Slots. Many setups that consistently report contradictions become solvable as soon as one such Module is included. The result will look different - some Slots will be occupied by the filler rather than by purposeful content - which is an explicit design trade-off, not a failure.
2.7 Rotating the envelope base plane
If you need your solved result to appear at a specific position in the model, oriented at a particular angle, or sitting on a non-horizontal plane, all you need to change is the Base Plane input on the grid component. The entire Envelope moves and rotates as one - every placed Module inherits the new position and Orientation while the Module definitions and Rules stay exactly as they are. This works because Modules and Slots both operate in local coordinate systems: geometry is authored relative to the Grid Box, not the world origin, and Materialize maps it into whatever plane the Slot sits on.
Concept
Every Module is defined in the local space of its own Grid Box. When you author Module geometry, you place it relative to the Box origin and Axes - not relative to the world origin. From a world perspective the Box may sit at any position and angle, but the Module still describes the same shape inside it.
An Envelope produced by Homogeneous Grid (or Heterogeneous Grid) is a collection of Slots that all share the same Orientation. Their local planes are parallel to one another; only their origins differ, offset by exact multiples of the cell size along the local X, Y, and Z Axes. This shared Orientation is what makes them a regular grid. The Base Plane input sets the plane of the first Slot - the one at the local origin of the grid. Viewed in local coordinates, that first Slot sits at the bottom, left, closest corner, and the grid grows in the positive local X, Y, and Z Directions from there.
When Materialize places a Module into a Slot, it maps the Module geometry from the Module's own Grid Box plane into the Slot's plane. The result therefore inherits the Slot's world position and Orientation. Change the Envelope's base plane and every placed piece moves and rotates with it; the Module definitions and Rules stay untouched.
Steps
- Take any working definition that produces a solved result. Note where the output appears in the viewport.
- Locate the Base Plane input on Homogeneous Grid (or Heterogeneous Grid). By default it is World XY. Replace it with a rotated or translated plane - use a Plane Origin component to move it, or a Rotate component (or the Angle input and an ordinary Plane constructor) to tilt it.
- Observe the Envelope Grid Boxes in the viewport: they all shift and rotate together, maintaining their spacing and relative Orientation.
- Run the Solver and Materialize without changing anything else. The output geometry appears at the new position and Orientation. The topology of the result - which Modules ended up adjacent to which - is identical to the original; only its world placement has changed.
Module geometry and local space
Because Modules are defined in local space, geometry authored relative to the Grid Box origin is automatically correct regardless of where the Box ends up in the world. If you have existing geometry built at the world origin that you need to rebase, use an Orient component with the source plane set to World XY and the target plane set to the Module's Grid Box plane. This remaps the coordinates so the geometry sits correctly inside the Box.
A common alternative is to work directly from an existing model. If a piece of geometry is already placed and oriented somewhere in space, you can place a Grid Box around it - matching its position and rotation - and reference the geometry as-is. Because the Box defines the local coordinate frame, and the geometry sits inside that Box, no rebasing is necessary regardless of where or at what angle the piece sits in the world. This makes it straightforward to Sample Modules directly from a Rhino model: arrange and rotate the pieces as desired, fit a Grid Box around each one, and feed the geometry references into Construct Module.
Multiple envelopes
Any number of independent Envelopes can coexist in the same Grasshopper definition, each with a different base plane. You can tile a curved surface by approximating it with locally-flat planar patches, each with its own oriented plane, and run a separate Solver per patch. The Module library is shared across all of them; only the Envelope planes differ.
2.8 Defining Rules from Faces
Monoceros 3 offers several routes for defining which Faces are allowed to touch - from the most explicit (pairing Faces by hand) to the most automated (letting the voxel engine infer compatible pairs from geometry). Choosing the right method for your situation keeps the canvas readable and prevents accidentally over-constraining the Solver.
Concept
Every Rule in Monoceros 3 is a pair of two Face UIDs - one from a source
Module Face and one from a target Module Face - where the two Faces point in
opposite Directions (+X touching -X, +Y touching
-Y, and so on). Rules are
Direction-agnostic for equality: defining “A connects to B” is equivalent
to “B connects to A”, so you never need to define both sides of the same
adjacency. The more Rules you define, the more flexibility the Solver has to find
valid combinations. A Module Face with no explicit Rule becomes an Indifferent
Face. With the default
Construct Assembly setting (Indifference enabled), Indifferent Faces
pair freely with any other Indifferent Face facing the opposite Direction on
the same Axis - they do not block neighbours. Only define explicit Rules for
Faces where you want to control what may be adjacent.
Method A: From Face pairs
This is the most explicit approach and gives you the finest control over individual
Face connections. Extract the six Faces of each Module using
Get Module Faces, which outputs them as separate named parameters
(+X, +Y, +Z,
-X, -Y, -Z). Wire the Face you want on the
source side into the Source Faces
input of Construct Rules From Faces, and the matching opposite-Direction Face
of the target Module into the Target Faces input.
This component does not use Grasshopper’s default element-wise data matching. Instead it uses cross-matching: every item in the Source list is tested against every item in the Target list, producing all valid opposite-Direction combinations. If you feed three source Faces and four target Faces, you get up to twelve Rules, not three. This is intentional - the common use case is to allow all listed Faces to connect to all listed Faces. If you want strictly one-to-one pairing (first source with first target, second with second, and so on), graft both inputs before connecting them. Each branch will then contain a single Face, forcing the component to process one pair at a time.
Method B: From Module Names and directions
Use Construct Rules From Modules to create Rules by specifying source Module Names and target Module Names per Direction. This is convenient for batch Rule creation when you know which Module types should be adjacent but do not need to select individual Faces.
Method C: From string literals
Rules can be cast from strings in the format
modulea:+X -> moduleb:-X. Use a Grasshopper Panel with the Rule
parameter type for quick prototyping or when you want to hard-code a short list of
adjacencies as readable text.
Method D: Suggest from geometry
Suggest Rules From Geometry inspects each Module's geometry and collects the elements that lie precisely flat on each Face plane:
- Naked edges of Breps - boundary edges that belong to only one Face of a Brep surface or solid
- Naked edges of Meshes - edges shared by only one polygon in a mesh
- End points of open curves - the start and end of any non-closed, non-periodic curve
- Standalone Point objects
For each Face, only elements whose vertices all fall exactly on the Face plane within tolerance are kept. The surviving points are remapped into the Face's local coordinate space (relative to its Face plane), then compared across Faces. Two Faces match when they Face in opposite Directions, have the same Face dimensions, and their sets of local-space points are identical within tolerance (order-independent). The component outputs Rules directly - no additional Rule construction step is needed.
This method is reliable when Module geometry is modelled so that Faces intended to touch share the same boundary pattern - for example, a pipe Module whose open end sits exactly on the Face plane will have a circular naked edge there; any other Module with an identically sized circle on the opposite Face will be matched to it automatically. Geometry that is only near the plane but not exactly on it will not contribute to the match, so precision in modelling matters.
Method D cannot help when Module geometry is fully closed. A watertight Brep or mesh - a solid box, for example - has no naked edges at all. Every Face will appear empty and the component will produce no matches. If your Modules are built from closed solids, use Method E instead.
You can scope the search by providing specific Faces to the Source Faces and Target Faces inputs. When left empty, all Faces in the Module list are compared against each other. Limiting the inputs is useful when you have a large Module set and only want to test compatibility between a known subset of Faces.
The output of Method D is a suggestion, not an authoritative Rule set. Always inspect the matched pairs using the Preview Rule and Preview Faces components before connecting the result to Construct Assembly, and add or remove Rules manually to correct any mismatches.
Method E: Suggest from voxels
Suggest Rules From Voxels works like Method D but compares voxelised Face patterns instead of exact geometry. It rasterises each Module at a configurable Voxel Resolution (default 16×16×16 per Module), extracts a layer of voxels at the Face up to a configurable Depth (default 1 voxel layer), and groups Faces whose voxel patterns match. Higher resolution gives finer discrimination but increases computation time; increasing depth captures more of the Module body behind each Face, which helps distinguish Faces that look identical at the Face plane alone. Face geometry does not need to be perfectly watertight or analytically exact - as long as both Faces produce the same raster pattern at the chosen resolution, they are matched. Like Method D, this component outputs Rules directly.
This makes Method E more forgiving than Method D for messy, imported, or scan-derived geometry. It is also the right choice when Module geometry is built from closed solids: a watertight Brep or mesh has no naked edges, so Method D finds nothing on any Face, while the voxel rasteriser still captures the Module body correctly. The trade-off is precision: fine surface details smaller than one voxel cell are invisible to the matcher, and Modules that look compatible at voxel resolution may not fit perfectly at the geometric level.
Both Method D and Method E produce suggestions, not authoritative Rule sets. Always inspect the matched pairs using the Preview Rule and Preview Faces components before connecting the result to Construct Assembly, and add or remove Rules manually where the automatic match is incorrect or incomplete.
2.9 Working with multiple Modules
When a design uses more than one type of Module - different shapes, details, or programme types - mixed together in the same grid, the Solver places each Module according to the Rules you define. You retain control over which Module types are allowed in which Slots.
Concept
The WFC Solver operates on a single flat list of all Modules, a single flat list of all Rules, and a single flat list of Slots. No matter how many Modules you design, everything must be collected, merged and flattened before going into Construct Assembly. Faces and Rules reference Modules by name, so it is the names that tie everything together. The Solver does not care about the order in which Modules appear in the list. Every Slot must explicitly list which Modules it allows - there is no global “allow all” shortcut, so you need to supply the full Module list (or the equivalent Module Name strings) to every Slot that should accept any Module.
Method A: One component per Module
Place one Construct Module component for each Module design, then merge all their outputs into a single flat list using a Merge component. Supply the merged Module list to the Allowed Modules input of Construct Slot so every Slot accepts every Module. Modules cast to Module Names automatically, so you can wire the Module list directly into Construct Slot without extracting names first - or, if you need the name strings elsewhere, use Deconstruct Module to get them explicitly. Create Rules for each Module pair you want to allow as neighbours using any of the methods in section 2.8, then merge all Rule lists before connecting to Construct Assembly. This approach is readable on the canvas and works well for designs with a small, stable set of Modules.
Method B: Data trees
For larger Module sets, Grasshopper data trees are more scalable. Organise your Module inputs - Module Name strings, Grid Boxes, and geometry - into branches so that a single Construct Module component produces all Modules in one tree, one branch per Module. Flatten the tree before connecting to Construct Assembly; it expects a flat list. Pass the flattened Module list directly to Construct Slot (Modules cast to Module Names automatically), or extract the name strings with Deconstruct Module if you need them separately. Define Rules using any of the methods in section 2.8, operating on the flattened Module list or its Faces, then flatten and merge the Rule output before connecting to Construct Assembly.
2.10 Automatic Module rotations
If a Module has a clear directionality - a curved corridor, a structural L-bracket - Module Rotations generates all valid orientations automatically, without modelling each variant by hand. Face logic and Rules update automatically for every new Orientation.
Generating the variants
- Construct the base Module with Construct Module as normal.
- Connect it to Module Rotations. Enable rotations around the Axes that make sense for your design. For the pipe example, all three Axes produce valid variants.
- The output is a flat list of Modules. Module Rotations assigns each variant a
counter suffix:
pipe-0(identity, 0°),pipe-1,pipe-2,pipe-3, and so on. Because the identity rotation is already included aspipe-0, this list replaces the original Module everywhere downstream - do not include both. - Enable Cull Duplicates to remove variants that are geometrically identical after rotation (for example, a symmetric straight pipe produces only two unique orientations along each Axis rather than four).
Generating Rules for all variants
Once Module Rotations produces its output, the variants are fully independent Modules.
pipe-0, pipe-1, pipe-2 and the rest have no
shared identity in the Solver - they are treated exactly like any other
unrelated Module in the library. The Solver has no knowledge that they were derived
from the same base design; it only knows the Rules you supply. This means Rules must
be defined between the individual variant names, not against the original
pipe base name, and must also cover pairs between different
variants (so the Solver can transition from one Orientation to another in the result).
Use any of the methods in 2.8 to define Rules for the variant list. The Module Rotations output is a flat list of ordinary Modules, so every workflow in 2.8 applies without modification.
Wiring the solver
- Pass the full Module Rotations output list (all variants) to the Modules input of Construct Assembly.
- Pass the same list to Construct Slot as the Allowed Modules input so every Slot permits every variant. The Slot accepts Module objects directly and casts them to names automatically.
- Feed the Modules, Slots, and Rules into Construct Assembly, then connect the Assembly to the WFC Solver. Connect the Solver's Assembly output to Materialize Assembly - the Assembly includes all rotation variants, so Materialize Assembly will place each variant at the correct position and Orientation.
Common mistake
Defining Rules against the original base Module Name (pipe) rather than
the rotation variant names (pipe-0, pipe-1, etc.) causes
the Solver to contradict immediately: the Slots list variant names but no Rule
references them. Always define Rules using the Module Rotations output list, not the
original Module.
2.11 Heterogeneous grid
When a design requires Modules of genuinely different physical scales coexisting in the same Envelope, use Heterogeneous Grid. A Homogeneous Grid constrains all cells to the same size; Heterogeneous Grid lets neighbouring Slots have different dimensions, with each distinct Slot dimension requiring at least one matching Module.
Homogeneous vs heterogeneous - the key distinction
A common misconception: a grid is not Heterogeneous simply because its Grid Boxes are non-cubic. A Homogeneous Grid with a Diagonal of (2, 1, 3) produces cells that are wide in X, narrow in Y, and tall in Z - but every cell in the grid is identical. That is still a Homogeneous Grid. One Module size fits the whole Envelope.
A grid is Heterogeneous when neighbouring Slots have different sizes from each other. This only happens when the X, Y, or Z size lists passed to Heterogeneous Grid contain more than one distinct value. If all values in all three lists are identical, the result is the same as using Homogeneous Grid.
In practice: use Homogeneous Grid whenever all your Modules are the same size (even if that size is rectangular rather than cubic). Switch to Heterogeneous Grid only when you genuinely need Slots of different sizes coexisting in the same Envelope.
How the grid dimensions are defined
Heterogeneous Grid takes three lists - one per Axis - rather than counts. Each value in the list sets the size of one column (X), row (Y), or layer (Z). A five-element X list therefore produces five columns, each as wide as the corresponding value.
The recommended way to provide these lists is a Gene Pool component. Gene Pool acts as a compact block of sliders: it stores a list of floats that you can edit individually or all at once, making it easy to set per-column widths without wiring up a separate slider for every column. Any other list source works just as well - Series, Sequence, a panel with numbers, an explicit Merge of values, or any parametric expression that produces a flat list of floats.
Modules with the same name - dimensional invariants
Two or more Modules may share the same name as long as they have different bounding-box dimensions. They are called invariants (or dimensional variants) of the same Module type. The WFC Solver treats them as a single logical type: Rules defined for a name apply to every invariant of that name simultaneously. You define Rules once and all size variants obey them.
Materialize then selects the correct invariant at placement time by matching the Slot's box dimensions to the Module's box dimensions. A Slot that is 2 m wide receives the 2 m-wide invariant; a 1 m-wide Slot receives the 1 m-wide invariant. The Solver itself never sees dimensions - only names.
The invariant design contract
Sharing a name asserts that all invariants are functionally equivalent from the Solver's perspective. This is a strong commitment: the Solver will allow any invariant wherever the name is allowed, without regard for size. If the equivalence assumption is violated, the Solver produces answers that look valid by name but are physically incorrect.
Example 1 - T-junction on the long variant only.
Suppose you name both a short pipe (1 m) and a long pipe (2 m) the
same thing: pipe. The long pipe has enough room along its body
to accommodate a T-shaped branch, so you define a Rule that allows another
pipe to connect to it in the Y Direction. The short pipe has no such branch
- its geometry simply does not support a Y connection. But the Solver
does not know this. It sees the name pipe and applies all Rules
for that name to every invariant. It will happily place the short pipe in a
Slot that requires a Y-Direction neighbour, producing a result that looks
correct in the solution tree but has no physical Face at that Face. The
error is invisible until Materialize places the geometry or you inspect the
result manually.
Example 2 - mismatched Face profiles across sizes. Suppose Module A has a long variant (2 m in X) and a short variant (1 m in X), and Module B similarly has long and short variants. You define a Rule that allows A to connect to B on the +X Face. The Solver reads this as: wherever A appears, B may be adjacent in +X - regardless of actual size. If the long A + long B pairing is geometrically correct but the short A + short B pairing is not (because the short variants have different Face profiles that do not align), the Solver will still place short A next to short B. Again, the error is silent.
The Rule of thumb: name two Modules the same only when every size combination that the Solver could produce is genuinely valid in your design. If any size variant needs a different Rule set - whether because it has extra Faces, fewer Faces, or different Face geometry - it must have its own name.
Module size combinations - the combinatorial explosion
The number of distinct Slot sizes is not the number of different values per Axis; it is the product of how many unique values appear in each Axis list. If the X list contains a unique values, the Y list b unique values, and the Z list c unique values, up to a × b × c different cell sizes can occur and you need a Module variant for each one.
This grows fast. A few examples:
| Unique X sizes | Unique Y sizes | Unique Z sizes | Max distinct cell sizes | Typical scenario |
|---|---|---|---|---|
| 1 | 1 | 1 | 1 | Uniform grid - one Module size, equivalent to Homogeneous Grid. |
| 2 | 1 | 1 | 2 | One wider column in an otherwise uniform grid. Two Module sizes needed. |
| 2 | 2 | 1 | 4 | One wider column and one deeper row. Four Module sizes. |
| 2 | 2 | 2 | 8 | One different value in each Axis. Eight Module sizes. |
| 3 | 3 | 2 | 18 | Three column widths, three row depths, two layer heights. Eighteen Module sizes. |
| 4 | 4 | 4 | 64 | Four distinct values per Axis. Sixty-four Module sizes - impractical to author by hand. |
The most common trap is starting from a uniform grid and adding just one exceptional row in each Direction. Suppose you have a 10×10×10 grid where nine columns are 1 m wide and one is 2 m wide, nine rows are 1 m deep and one is 2 m deep, and all layers are 1 m high. That gives 2×2×1 = 4 distinct cell sizes. Add one exceptional layer height and the count doubles to 8. Add a second exceptional column width or row depth and it doubles again. Because the unique-value counts multiply rather than add, even a small number of irregular values quickly produces a large number of required Module variants.
Keep the number of distinct values per Axis as low as your design allows. If only two widths are genuinely necessary, avoid letting a slider drift to a third value.
Steps
- Use Heterogeneous Grid instead of Homogeneous Grid. Wire three lists of sizes (Gene Pool or any flat list of floats) into the X, Y, and Z inputs. The length of each list sets how many columns, rows, and layers the grid has.
- Count the unique values in each Axis list and multiply them together. That product is the number of distinct Module sizes you need to construct.
- Construct Modules for every distinct cell size. Materialize matches geometry to Slots by comparing box dimensions; any Slot whose assigned Module has no variant with matching dimensions will be left visually empty. The Solver emits a Warning before running if it detects name-dimension mismatches, and Materialize emits a Warning for any path where geometry could not be placed. Use the Audit Assembly component’s Slots Without Fitting Modules output to identify every affected Slot and resolve all issues before running the Solver.
2.12 Weighted Module placement
To bias the distribution of Module types across the grid - toward a pattern, a gradient, or a specific spatial proportion - assign per-Slot Weights. Without explicit Weights, all Modules in a Slot are equally likely. For example: opaque cladding panels dominate the lower floors while glazed panels increase toward the top; or a dense structural Module concentrates at the core while an open Module tends toward the perimeter.
Weight is a per-Module, per-Slot relative multiplier. Each Slot carries its own independent Weight list. A Module with Weight 2.0 in a given Slot is twice as likely to be chosen at that Slot during Observation as a Module with Weight 2.0 in the same Slot. Weights on one Slot have no effect on any other Slot.
What the weight value means
The values are relative multipliers within a single Slot's allowed-Module list.
If a Slot allows Modules [A, B, C] with Weights [4.0, 2.0, 1.0], Module A is
four times as likely as C and twice as likely as B to be observed first at that
Slot. The default Weight is 1.0. Fractional values below 2.0 reduce
a Module's likelihood relative to the others; for example, a Weight of 0.5 makes
a Module half as likely as a neighbour with Weight 1.0. There is no upper bound.
The Weights are normalised per Slot at Observation time; the absolute values do
not matter, only the ratios between them.
Weights must be zero or positive; negative values are not accepted and will
cause an error. A Weight of exactly 0.0 is valid and means the
Module has the lowest possible probability - it will almost never be
chosen during Observation but remains in the allowed set. Construct Slot
silently clamps it to the smallest representable positive value and issues a
Remark. To exclude a Module from a Slot entirely, remove it from the
allowed-Module list rather than setting its Weight to zero.
What weights do not control
- No Weight on Rules. There is no mechanism to make a particular adjacency more or less probable. Weights govern which Module the Solver picks when a Slot has multiple candidates; they do not influence how constraints are propagated afterward.
- Weights do not guarantee occurrence. A high Weight increases the probability that a Module is chosen during Observation, but WFC Propagation can still eliminate it from a Slot as a consequence of choices made elsewhere. When Propagation removes a Module that carries a high Weight, the Solver silently picks from whatever candidates remain, with no diagnostic message. In tightly constrained setups this can be difficult to detect.
- Weights have less influence in heavily constrained grids. Weights only act when a Slot has more than one candidate at Observation time. The more Rules and fixed Slots constrain the grid, the fewer free observations occur, and the smaller the practical influence of the Weight values on the final result. Weights are most visible in loosely constrained, open setups with many Observation steps.
Steps - weighting a single Slot
- Use Construct Slot with the Weights input.
-
Connect a list of floats to Weights. The component pairs
each Weight with the Module Name at the same list index: Weight 0 goes
to the first Module Name, Weight 1 to the second, and so on. This is
called a parallel list - two separate lists where position determines
the correspondence.
For example, if the Module Names input receives [wall,corridor,room] (three items, indices 0-2), then the Weights input must also carry three items in the same order: index 0 is the Weight forwall, index 1 forcorridor, index 2 forroom. A Weight list of [1.0,3.0,1.0] makescorridorthree times more likely than the others at this Slot.
The simplest way to build this on the canvas is with a Panel feeding a Construct Slot, with a second Panel next to it for the Weights - one line per entry in each panel, in the same top-to-bottom order. - If the Weight list is shorter than the Module list, the last value is repeated
for the remaining Modules. This is a convenient shortcut when all remaining
Modules should share the same Weight - for example, a list of
[
4.0,1.0] for five allowed Modules gives the first Module four times the probability, and all others equal Weight of 1.0. - The default Weight is
1.0. Omitting the Weights input is equivalent to supplying all ones.
Steps - weighting the entire envelope
To give each Slot in the Envelope its own Weights, produce a Grasshopper data tree in which branch i contains the Weight list for Slot i. The branch structure must match the Slot list branch-for-branch.
- Start from the Grid Box list you would otherwise pass to Construct Slot.
- For each Grid Box, compute one float per Module - for example, by evaluating an attractor distance at the box centre, or by sampling a Z-height gradient formula.
- Organise these floats as a data tree with one branch per Grid Box, each branch containing one float per Module in the same order as the Module list for that Slot.
- Connect that tree to the Weights input of Construct Slot. The data tree structure must align with the Slot list: branch 0 Weights go to Slot 0, branch 1 to Slot 1, and so on.
Because the Weight list is tied positionally to the Module list, every Slot must share the same Module list if you want to drive all Weights with a single expression. If different Slots allow different Module subsets, use separate Construct Slot nodes or build the tree manually per subset.
Use cases
- Vertical gradient - Evaluate Weights per Slot based on Z position. For example, make glazed cladding tiles increasingly probable toward the top of the Envelope and opaque tiles more probable at the base.
- Proximity-based bias - Increase Weights for certain Modules near specific points or curves in the Envelope, such as concentrating a feature Module around a focal point.
- Random variation - Add slight random variation to Weights to break uniform repetition without a specific gradient.
2.13 Boundary handling
If the outermost Faces of your Envelope must terminate in a deliberate condition - a closed pipe end, a wall Face, a slab edge, or any other intentional edge - you need explicit boundary handling. Without it, outward-facing Faces at the Envelope surface have no neighbouring Slot, so the Solver applies no constraint from that Direction: any Module is valid at an outermost Slot regardless of what Face points outward. Indifferent Faces and typed Faces alike can Face the void freely, producing open pipe ends, exposed wall Faces, or other unintended edge conditions at the grid surface. Boundary handling is not needed to prevent the Solver from failing; it is needed to enforce intentional design behaviour at the edges.
Basic boundary
- Create your main Envelope Grid Boxes using Homogeneous Grid or Heterogeneous Grid.
- Use Add Boundary Layer to generate an additional layer of Grid Boxes around the Envelope. Control which Directions get boundary layers (X±, Y±, Z±) and how many layers deep.
- Define a boundary Module (typically with no geometry, named e.g.
boundary). - Create Slots from the boundary Grid Boxes, allowing only the boundary Module.
- Define Rules connecting the boundary Module’s Faces to interior Modules.
- Merge the boundary Slots with the interior Slots before solving.
Advanced boundary
- Use different boundary Modules on different Faces (e.g.
boundary-top,boundary-side). - Use Are Grid Boxes Boundary to identify which Grid Boxes are on which Face.
- Create multiple boundary layers with increasing depth.
2.14 Constructing Slots from geometry
If your design Envelope follows a non-rectangular shape - a curved surface, a Brep volume, a mesh, a set of curves, or a point cloud - use Grid Boxes From Geometry to derive the Slot positions automatically rather than placing Grid Boxes by hand.
The component maps any Rhino geometry onto a regular grid and returns one Grid Box for each occupied cell. Three coverage modes let you match the geometry type: surface wrap covers only the cells a surface or curve passes through, which is the right choice for façades, shells, and curve networks; volume infill fills only the enclosed interior without an outer skin layer; and surface wrap and infill (the default) captures both together, suiting closed solids where you want a complete volumetric Envelope. For full input details and supported geometry types, see § 4.2.8 Grid Boxes from Geometry in the component reference.
Trimmed Rhino surfaces should be converted to Breps before connecting them - the component works most reliably with closed Breps and meshes near trimmed edges.
Sparse envelopes
The resulting Grid Boxes do not have to fill a rectangular block. The Solver handles sparse Envelopes natively: any cell absent from the grid is automatically disabled and excluded from constraint Propagation, so no gap-filling step is needed before solving.
Surface-derived envelopes: thickening with Add Boundary Layer
When the source geometry is a surface (Fill Method 0), the resulting Envelope is typically only one cell deep - a thin shell that follows the surface curvature. In many designs a single layer is not enough: the Modules cannot form meaningful spatial sequences if there is no depth to propagate through.
The solution is to use Add Boundary Layer to grow the grid outward by one or more layers on each side of the surface. Set the layer count to 1 or 2 and selectively enable only the growth Directions you want (for example, a wall panel system may grow only in the outward normal Direction, while a floor system may grow only upward).
- Run Grid Boxes From Geometry with Fill Method 0 to get the surface-aligned layer.
- Connect the output to Add Boundary Layer. Set Layers to 1 or more. Disable the Directions you do not want to grow into.
- Merge the original surface layer with the new boundary boxes to create the thickened Envelope, or use the combined output directly if Add Boundary Layer returns all boxes.
- Proceed with Construct Slot on the combined box list.
Remember that the extra boundary boxes will need appropriate boundary Modules and Rules, following the same pattern described in 2.13 Boundary handling.
Volume-derived envelopes (Brep or Mesh)
For closed solids use Fill Method 2 (default) to capture both the outer shell and the interior. The result is a volumetric Envelope that the Solver fills completely. To then control what happens at the outer Face of the solid, add a boundary layer around the geometry-derived boxes and define boundary Rules as described in 2.13 Boundary handling.
Curve and point cloud envelopes
Curves produce a one-cell-wide chain of Grid Boxes along the curve's path. This is useful for corridor spines, pipe routes, or any linear structural system. Points each activate the grid cell they fall into - the cell is determined by the Base Plane and Diagonal, so two points within the same cell produce only one Grid Box, and the resulting Box is grid-aligned regardless of where exactly the point sits. Both are inherently sparse and can be solved directly without filling. As with surface-derived grids, use Add Boundary Layer if depth beyond a single cell is needed.
2.15 Fixing Modules in the Envelope
To guarantee that certain positions in the grid always contain a specific Module - a corner element, a structural column, an entry point - construct those Slots as Deterministic by allowing only the desired Module Name. The rest of the grid remains free for the Solver to fill.
Building the envelope with fixed positions
- Identify the Grid Boxes where you want to fix a Module.
- Create Slots from those Grid Boxes, allowing only the desired Module Name.
- Create Slots for the remaining Grid Boxes, allowing all Module Names.
- Merge all Slots and solve.
The Solver treats Deterministic Slots as fixed and propagates their constraints outward.
Updating an existing envelope
When the Envelope already exists and you only need to change certain Slots - tightening constraints in some positions, freeing others, or replacing a fixed Module - you do not need to rebuild the whole Slot list. Remove the original Slots at the positions that changed, construct the updated Slots for those same positions, and append them to the remaining unchanged Slots. Because the Solver accepts Slots in any order and organises them internally, the updated Slots can simply be placed at the end of the merged list.
Placing a Megamodule at a specific position
To place a Megamodule at a known position in the Envelope, you only need to fix one of its individual Modules. Restrict a single Slot to that Module Name and leave the surrounding Slots open with all Module Names allowed. The adjacency Rules between the Megamodule's parts force the neighbouring Slots to resolve deterministically - the Solver has no valid alternative for them - so the full Megamodule emerges without explicitly constraining every position it occupies.
The only requirement is that the Megamodule fits within the available Envelope from the fixed position. If the fixed position is too close to a boundary or another constraint for the remaining parts to fit, the Solver will report a Contradiction.
2.16 Disallowing Rules
Construct Assembly performs set subtraction on its Disallowed Rules and Disallowed Connector Pairs inputs - removing specific unwanted adjacencies from the allowed Rule set without discarding the rest. Use this when automatic suggestion creates pairings that should not exist for design or functional reasons. Rules in the disallowed set that do not exist in the allowed set are silently ignored, so it is safe to supply a broader disallowed set than strictly necessary.
Steps
- Generate your full Rule set using Suggest Rules From Voxels or Suggest Rules From Geometry. Connect it to the Allowed Rules input of Construct Assembly.
- Identify the unwanted adjacency. Create the specific Rule(s) you want to forbid using any Rule construction method and connect them to the Disallowed Rules input of Construct Assembly.
- Alternatively, if you use Connectors, connect unwanted Connector Pairs to the Disallowed Connector Pairs input - Construct Assembly generates the corresponding Rules internally and removes them.
When to use
- Post-suggestion cleanup - Automatic suggestion is generous; remove the few pairings that look wrong in the result.
- Functional constraints - Prevent a window Module from connecting directly to a staircase Module, even though their geometry matches.
- Iterative design - Keep the broad Rule set but exclude specific combinations after reviewing initial results.
2.17 Rule Exclusivity
Automatic Rule suggestion is intentionally broad: it pairs every compatible Face it finds. Some Faces serve a specific design role and should only ever connect in one explicitly defined way - a structural joint that must land on a beam Face, a door opening that can only Face a matching frame Module. The Exclusive Rules and Exclusive Connector Pairs inputs on Construct Assembly let you declare that the Faces referenced by a chosen subset of Rules are exclusive: any other Rule that touches those same Faces is removed from the set, and the exclusive Rules are added.
How it works
Construct Assembly collects the explicit Exclusive Rules and generates Rules from Exclusive Connector Pairs. It then collects all Faces referenced by these exclusive Rules, removes every other Rule that references any of those Faces, and adds the exclusive Rules to the allowed set.
Steps
- Connect your allowed Rules and/or Connector Pairs to Construct Assembly as usual.
- Identify the Faces that need exclusivity - the Faces that must connect in only one specific way.
- Construct the exact Rules you want for those Faces and connect them to the Exclusive Rules input. Alternatively, connect Connector Pairs to the Exclusive Connector Pairs input.
- Construct Assembly removes all other Rules referencing those Faces and adds the exclusive Rules.
When to use
- Megamodule integrity - The Internal Rules produced by Construct Megamodule already define exactly which sub-Module Faces must connect to each other. Feeding them as Exclusive Rules locks those internal Faces against anything else, preventing automatic suggesters from accidentally pairing a sub-Module Face with an unrelated Module. See 2.18 Megamodule construction.
- Structural joints - A column Face that must always meet a beam Module and nothing else.
- Openings and frames - A door or window Face that only pairs with its designated frame Module, never with a generic wall.
- Tighter control than Disallowed Rules - When you want to keep a few specific pairings and remove everything else for those Faces, rather than enumerating what to remove one by one.
2.18 Megamodule construction
Megamodules group adjacent cells - a 2×1×1 structural bay, a tall atrium, any element too large for a single cell - into a single design unit. Because one Module can only occupy one cell, Construct Megamodule generates a set of coordinated sub-Modules and the Rules that lock them together, maintaining the WFC constraint model.
Sub-Modules are named {name}_p0/N, {name}_p1/N, etc.
where N is the total part count. Each sub-Module previews the sibling Grid Boxes
as dashed ghost outlines so the full Megamodule footprint is visible even when
viewing a single part in isolation.
Steps
- Select a group of adjacent Grid Boxes for the Megamodule.
- Connect them to Construct Megamodule with a name and optional geometry.
- The output has three parts:
- Modules - one sub-Module per Grid Box, output as a data tree (one branch per part, flattened by default). Add these to your Module list alongside all other Modules.
- Internal Rules - exclusive adjacency Rules that lock the sub-Modules together. Add these to your Rule list.
- External Faces - the outer boundary Faces available for connecting the Megamodule to other Modules, output as a data tree (one branch per part, flattened by default). Use only these when running Suggest Rules From Geometry or constructing external Rules.
- When generating Rules for the rest of your Module set, pass only the External Faces to any automatic Rule suggester - never the full Face list of the sub-Modules. Internal Faces must not appear in any Rule other than the Internal Rules.
Geometry handling
Every sub-Module carries the full Megamodule geometry so that Face suggestion
components can analyze all external Faces regardless of which sub-Module they
belong to. Only the first sub-Module (_p0) materializes the
geometry - the Materialize component skips geometry output for the remaining
parts to avoid duplication.
Auto-rotation
Enable Rotate X, Rotate Y, or
Rotate Z on the Construct Megamodule component to have the
Construct Assembly automatically generate rotated variants of the entire Megamodule.
Construct Assembly applies the same rotation to all sub-Modules and remaps both internal
and external Rules accordingly. Rotated variants are named with a rotation
suffix (e.g. _z90, _z180, _z90y90).
Protecting internal Rules with Exclusive Rules
The Internal Rules are already correct and complete - the component generates them exclusively. The risk is human error: accidentally running a suggester on all sub-Module Faces instead of only the external ones, or merging Rule lists carelessly, can introduce Rules that reference internal Faces and allow sub-Modules to separate from each other.
The safest approach is to treat Internal Rules as a hard constraint. Connect them to the Exclusive Rules input of Construct Assembly. This removes any other Rule that references an internal Face - regardless of how it got there - and preserves the exact pairings the Megamodule requires. See 2.17 Rule Exclusivity.
2.19 Materializing results
Materialize Assembly converts solved Slots into visible Rhino geometry. It takes a solved Discrete Assembly as input, matches each Slot to the Module it holds, and orients - translates and rotates - that Module’s geometry to the correct position in space.
Inputs
- Assembly - The solved Discrete Assembly (from the WFC Solver’s Assembly output).
Outputs
- Geometry - Placed geometry for each Slot, as a data tree.
- Transforms - The transformation matrix that moves each Module from its definition origin to its Slot position. Matches the Geometry output in structure.
Both outputs share the same data tree structure:
{solutionBranch; moduleIndex; slotIndex}.
The solutionBranch is inherited from the input Slots path (single
solutions start at {0}); moduleIndex is the position of
the Module in your input list; slotIndex is the Slot's position within
that branch. In the common single-solution case, placements of Module 2 would
sit at {0;2;0}, {0;2;1}, and so on. Flattening the
tree gives a plain list of all placed geometry in Slot order.
What Transforms are for
The Transforms output exists for workflows where you want to place geometry that Materialize itself did not produce. Common uses:
- Alternative geometry per Module - Keep a lightweight stand-in on the Module to keep the Grasshopper display fast, then use the Transforms to orient a richer geometry or a detail model at each placed Slot. Wire the Transform into a standard Grasshopper Transform component alongside the geometry you want placed.
- Geometry biased for the suggesters - Face suggesters derive adjacency from the geometry attached to a Module: they look at where Faces, edges, or points sit relative to the cage. You may deliberately place geometry that is offset, simplified, or positioned so that the suggesters pick up the right Faces - even though that geometry looks nothing like the finished piece. Use Transforms to place the actual intended geometry at each Slot independently of what the Solver used.
Edge cases and warnings
- Slot is Contradictory - The Solver failed for that Slot. No geometry is placed and an error is reported. Contradictory Slots mean the solve itself was unsuccessful; they should not appear in well-constrained setups.
- Slot is Non-deterministic - The Slot still holds more than one possible Module (Solver was not run, or Return Mode was set to return partial results). Materialize skips those Slots and reports a warning.
- Module Name in Slot not found in the Module list - The Solver assigned a Module that is not present in the list you fed to Materialize. The Slot is skipped and an error is reported. This typically means the Module list is incomplete or the wrong list is wired in.
- Multiple Modules with the same name - This is intentional and supported: Modules with the same name but different dimensions serve as variants (e.g. rectangular versions of the same element). When a Slot is resolved, Materialize tries every variant and places the one whose box dimensions match the Slot. If more than one variant fits, all matching ones are placed and a remark is added.
- Multiple Modules with the same name and the same dimensions - This is an error. Materialize cannot distinguish between them and stops with an error message identifying the duplicate.
- Module exists but its dimensions do not match the Slot - If no variant fits the Slot dimensions, the Slot is left empty and a warning is issued. If at least one variant fits but others do not, the non-fitting ones are silently skipped and a remark is added only to flag that variants were evaluated.
- Module has no geometry - Materialize still records the placement and outputs a Transform, but nothing is added to the Geometry output. A remark notes the empty placement. This is normal for Empty Modules, which intentionally carry no geometry.
Baking: blocks vs. raw geometry
When you bake the Materialize component directly (right-click → Bake, or via the
standard Grasshopper bake shortcut), it creates Rhino block
instances. For each unique Module, one block definition is added to the
document and every placement becomes a lightweight reference to that definition.
Block names follow the pattern ModuleName_1,
ModuleName_2, etc., incrementing automatically if a
block with that name already exists. This is the recommended
approach for large Envelopes - an Envelope with 10,000 Slots and 8
Module types creates 8 block definitions rather than 10,000
individual geometry objects.
If you need raw geometry without blocks - for example to edit individual placements, run boolean operations, or hand off to a tool that does not support blocks - do not bake the component directly. Instead, wire the Geometry output into a standalone geometry parameter, and bake that parameter. The Geometry output already contains fully transformed copies of the Module geometry; baking from a plain parameter produces ordinary Rhino geometry with no block structure.
2.20 Solver settings
The Solver's four configuration parameters - Seed, Attempt count, Observation limit, and return mode - tune the trade-off between speed, reliability, and result variation. Adjust them when the Solver is too slow for larger grids, when solutions consistently fail, or when results lack variety.
| Parameter | Default | Description |
|---|---|---|
| Random Seed | 42 | Controls the random choices during Observation. Different Seeds produce different results. Set to a fixed value for reproducibility. |
| Max Attempts | varies | Maximum number of solve Attempts. Each Attempt uses a different Random Seed (incrementing from the base Seed). More Attempts increase the chance of finding a valid solution. |
| Max Observations | unlimited | Maximum number of Observation steps per Attempt. Limits computation for very large grids. Set to a lower value to get partial results. |
| Return First | false | If true, stops as soon as the first valid solution is found and returns it. If false, runs all Attempts and returns all successful results. |
Each Attempt uses a successive Seed: Attempt 1 uses the base Seed, Attempt 2 uses base + 1, Attempt 3 uses base + 2, and so on. With a Seed of 0 and 1000 Attempts the Solver explores Seeds 0–999. If you then change the Seed to 1, it explores Seeds 1–1000 - 999 of the same Seeds plus one new one. To explore a genuinely fresh range, advance the Seed by at least the Attempt count: step from 0 to 1000, then 2000, 3000, and so on. A practical workflow: connect a number slider to Random Seed and set its step size equal to Max Attempts. Each slider position then covers a non-overlapping block of Seeds with no repeated territory.
The Seeds output returns the Seed that produced each successful solution. On a difficult grid the Solver may take long to find a solution - if it eventually succeeds on Attempt 500 with Seed 542, that value is returned. Before saving the file, wire that returned Seed back into Random Seed and reduce Max Attempts to 1, so the Solver finds the result immediately on every subsequent open. A returned Seed is only reliable while the setup stays exactly the same: any change to a Rule, Module, Weight, or the Envelope will alter the outcome. See FAQ 1.13.
There are no good or bad Seeds - all Seeds are equivalent; see FAQ 1.43.
2.21 Audit-driven debugging
When the Solver fails or produces unexpected results, run Audit before making any changes. Connect both your input Assembly (from Construct Assembly, before solving) and the Solver's output Assembly (from the WFC Solver, after solving) to separate Audit Assembly instances. Comparing the two Audit reports reveals what the Solver changed and where constraints were violated. The Report output gives a human-readable summary; the individual data outputs give machine-readable lists you can wire into other components for targeted fixes.
Audit covers four areas:
- Envelope - confirms the Slots form a valid sparse grid, reports its X × Y × Z dimensions, and whether it is Homogeneous or Heterogeneous.
- Slots - identifies Slots that allow only geometry-free Modules; Slots that allow unknown Module Names (names not in the Module list); Slots whose candidate Modules all have mismatched box dimensions (those Slots will remain empty after Materialize even if the Solver assigns them); and Slots where a Deterministic assignment would produce duplicate geometry because multiple invariants share the same name and dimensions.
- Modules - reports the full invariant structure per Module name; counts how many Slots each Module is admitted to; flags Module invariants that appear in no Slot, in no Rule, or whose Faces are completely absent from all Rules; lists Modules with and without geometry, mixed-geometry invariant groups, and identical-name-and-dimension duplicates; identifies Modules that only connect to themselves (self-loop-only), which is usually unintentional.
- Rules and Faces - flags Rules that reference unknown or unused Module Names; reports per-Rule occurrence counts and a first-occurrence mask for deduplication; lists Faces not covered by any Rule (these become Indifferent), Faces that are technically in Rules but effectively Indifferent because they accept every possible neighbour, and Faces covered by exactly one Rule (Singly Constrained Faces - useful for diagnosing why results look identical across Seeds); reports whether all Faces in the setup are Indifferent; and flags the Potential Over-Constraint condition, which predicts contradictions when Indifferent Faces are disabled.
Run Audit before Solve whenever anything is not working as expected.
2.22 Visualizing Rules and Faces
A Rule that references the right Face names can still place two Modules in a physically wrong relationship - facing the wrong way, offset, or in a rotation you did not intend - and none of that is visible in the data. Three viewport tools make Rule connections and Face Directions visible, so misconfigurations are immediately apparent.
- Preview Rule - Draws Rule connections in the viewport as lines between Module Faces, with color coding by Axis.
- Face Preview - Draws Face geometry, anchor planes, and Direction arrows for selected Modules.
- Preview Rule In Slots - Positions two Modules according to a Rule at a specific pivot, creating a visual Assembly of what the Rule allows. Also outputs the placed Modules with their rotation flags preserved.
2.23 Grid topology analysis
Grid Boxes are geometrically placed in 3D space, but the Solver works with a discrete grid of integer coordinates. Grid Topology and Neighbor Grid Boxes let you query that discrete structure from Grasshopper, so you can drive Slot construction and Module weighting from grid position and adjacency rather than from raw geometry checks.
Grid Topology
Takes a flat list of Grid Boxes and outputs two things:
- Relative Coordinates - one integer-coordinate point per Grid Box, normalised so the minimum corner of the bounding grid is at the origin. Index-matched to the input list: box 0 → coordinate 0.
- Topology - a data tree of neighbour indices. Branch
{i}contains the indices of all Grid Boxes adjacent to boxi. Enable Diagonal Neighbors to include Face-diagonal and corner adjacency; disable Bi-Directional Topology to list only positive-Direction neighbours (useful for building undirected graphs without duplicates).
Because the Relative Coordinates are index-matched to the Grid Box list, you can use the X, Y, Z components of each coordinate directly as sorting or filtering keys. For example: decompose the coordinates, extract the Z value, remap it to a 0-1 Weight range with Remap Numbers, and wire the result into the Slot Weights to create a vertical density gradient without any geometry intersection.
Neighbor Grid Boxes
Takes Grid Boxes, a set of Focus Indices (the boxes you care about), a Layers count (search radius in grid steps), and per-Axis toggles (X / Y / Z). Returns Neighbor Indices: the flat list of all Grid Box indices that are within the specified layer count of any focus box.
This is an expand-by-layers operation. Provide any starting indices - the result of a coordinate filter, an explicit list of hand-picked positions, or indices produced by another query - set Layers to the desired expansion radius, and the output is every Grid Box within that many steps of the starting set. Use the result to construct a separate Slot list for that region, with a different Module palette, Weight, or determinism setting. For purely vertical adjacency, disable X and Y and leave only Z enabled.
Workflow: inward weight gradient
- Build the Grid Box list and feed it into both Grid Topology and your Slot constructor.
- Decompose the Relative Coordinates; take the X component (or whichever Axis represents depth).
- Remap that value from its actual min-max range to
0.1 - 1.0. - Wire the remapped values as Slot Weights. Slots near one edge get low Weights; Slots near the other get high Weights. The Solver will favour heavier Slots when placing Modules.
Workflow: reopening a region of the solved result
When part of a solved result is not working - a zone is too repetitive, a corner has wrong adjacencies, a floor level looks out of place - you can reopen just that region for re-solving while leaving the rest of the grid locked.
- After the first solve, take the solved Slots from the WFC Solver output. Each is fully Deterministic: exactly one Module Name is allowed.
- Use Grid Topology on the original Grid Box list to get Relative Coordinates. Filter by coordinate value to identify the region to reopen - all boxes at a specific Z level, an X-range column, or any other positional criterion.
- Pass the selected indices into Neighbor Grid Boxes with Layers = 1 (or more) to expand the selection by one ring. This includes the immediate transition Slots, preventing constraint conflicts at the edge of the reopened zone.
- For the expanded selection, construct new open Slots from those Grid Boxes with the full (or broader) allowed Module list - Non-deterministic.
- For every other Grid Box, keep the solved Slots as-is. Those locked Slots act as fixed constraints during the next solve.
- Merge the open Slots with the locked Slots and re-solve. The Solver fills the reopened region while treating every locked Slot as a hard constraint.
Repeating steps 2-6 with larger or different regions lets you refine the result incrementally without starting from scratch.
If the region to identify is defined by boundary membership rather than interior position, Are Grid Boxes Boundary provides the boundary indices directly. For most Envelope tasks - capping pipe ends, enforcing wall Faces at the grid edge - Add Boundary Layer (see 2.13) is the more direct tool.
2.24 Rules from Face Groups
When several Faces across your Module library should all be compatible with each other - all the Faces where corridor pieces join, all the stacking Faces between floor Modules, all pipe openings - collect them into a single list and wire it to both Source Faces and Target Faces of Construct Rules from Faces. The component creates a Rule for every pair of opposing Faces in that list and automatically skips any two that point in the same Direction. One list, one component, every compatible pairing in one step.
Faces from Point
When you want to identify a specific Module Face without counting
Face Indices, place a point on that Face. Faces From Point
looks up which Face occupies that position and returns its
FaceId, ready to use anywhere a Face is expected.
- Place a Rhino point on the Module Face you want to identify.
- Wire the Module list and the point into Faces From Point.
- The output is the
FaceIdfor that Face. Use it wherever a Face is expected.
Rule from Curve
When you want to define which Faces are compatible by drawing directly in the viewport, use Rule From Curve. Draw a curve whose start point sits on one Module Face and end point on another. The component detects which Faces the endpoints land on and creates a Rule for each opposite-Direction pair. A single curve can produce multiple Rules when its endpoints overlap Faces from different Modules.
- Draw curves in Rhino between Module Faces you want to connect.
- Wire the curves and the Module list into Rule From Curve.
- The output is a deduplicated flat Rule list. Merge with any other Rule lists before passing to Construct Assembly.
Other methods
Get Module Faces exposes the six Faces of a Module as
separate named outputs (+X, −X,
+Y, −Y, +Z, −Z).
Merge the equivalent output from each Module to build a role list
manually. This approach gives fine control but requires tracking
which output index corresponds to which Face for every Module in the
library, which becomes error-prone as the Module count grows.
Rule From Curve is usually the better starting point.
2.25 Proto-results workflow
Some designs only make sense as a whole: a pipe network where each Module contributes one segment, a structural frame where beams must meet at joints, a tiled surface where edges must align across boundaries. In these cases the per-Module geometry is intentionally preliminary - skeleton geometry such as centrelines, control points, or boundary curves. It has no value on its own; it becomes the final design only after the Solver has arranged all Modules and the materialized pieces are joined or processed in Grasshopper.
Steps: pipe network
- Design Modules with centreline curves instead of pipe surfaces. For example, a
straight pipe Module contains a line from the centre of its
-XFace to the centre of its+XFace. A corner Module contains a quarter-arc. - Design the Faces so that pipe openings align at Module boundaries - centrelines should start and end at the centre of the Faces.
- Solve the grid normally.
- Materialize to get placed centrelines at every Slot.
- Flatten and join the curves using Grasshopper’s Join Curves component.
- Apply the Pipe component to create tubular surfaces from the joined centrelines.
Other applications
- Conveyor routing - Centrelines become conveyor track surfaces after lofting.
- Structural frames - Skeleton lines become beams after applying cross-sections.
- Wiring or plumbing - Route paths through the grid, then create physical conduits.
- Surface continuity - Place control points at Face boundaries, then create NURBS surfaces across Module boundaries.
2.26 2D grids (floor layouts and panel systems)
For designs that are essentially flat - a factory floor layout, a panel system pattern, a tiling, a 2D game level - collapse one grid dimension to a single cell. Running the Solver in three dimensions for an inherently 2D problem wastes computation and complicates Module design.
Steps
- Use Homogeneous Grid with count = 1 in the Direction you want to collapse. For a plan (XY), set Z count to 1. For a facade (XZ), set Y count to 1.
- Design Modules as flat tiles. Their bounding box depth should match the single-cell dimension. Apply Module Rotations with RotateZ = true to generate all orientations of each tile automatically, without defining separate Modules for each Direction.
- Define Rules only for the four in-plane Directions. The collapsed Axis needs no Rules at all: every cell already sits on the grid boundary in that Direction, so those Faces are outside the solve space. For wrapping (seamlessly tiling) patterns, assign the same Face role to opposing boundary Faces of the Envelope - left and right edges share one role, top and bottom edges share another. For bounded patterns, add a boundary layer instead - see 2.13 Boundary handling.
- Solve and Materialize as usual.
Linear grids (two dimensions collapsed)
Collapsing two dimensions reduces the grid to a single row of cells - a genuinely linear design. Set two of the three Axis counts to 1 and leave only one count greater than 1. Rules are only needed for the two Faces along the single active Axis; the four remaining Face Directions are all boundary Faces and require no Rules.
This is useful for designs that are inherently sequential:
- Conveyor or pipeline segments - each Module is one section of a run; Rules enforce which section types may follow which.
- Corridor or street sequences - a linear arrangement of room or block types with controlled transitions.
- Friezes and border patterns - decorative bands where the pattern repeats or varies along one Axis only.
- Assembly sequences - ordered steps or stages where only left-right (or before-after) adjacency matters.
Common applications (2D)
- Floor layouts - Modules represent zone types (conveyor run, workstation bay, buffer zone). Rules enforce connectivity requirements.
- Panel systems - Modules represent panel types (solid, perforated, access). Rules control edge profile continuity.
- Tile patterns - Modules are tile shapes. Rules enforce edge matching for seamless patterns.
- Game levels - Modules represent terrain types. Rules create coherent maps.
2.27 Sparse grids with intentional gaps
Irregular Envelope shapes - curved boundaries, L-shaped plans, building volumes with courtyards - can be created by starting from geometry directly or by filtering a rectangular grid. Either way, the remaining Grid Boxes do not need to fill a convex volume; the Solver handles any contiguous irregular shape.
From geometry (recommended)
Grid Boxes From Geometry generates Grid Boxes that follow an input shape directly. Set the Fill Method to fill volume (method 1) or surface wrap and fill volume (method 2) for solid shapes such as Breps and meshes. This produces a contiguous, gap-free set of Grid Boxes with no manual filtering needed.
From a filtered rectangular grid
Alternatively, create a full rectangular grid with Homogeneous Grid and remove unwanted boxes using Grasshopper list operations (Cull Pattern, Dispatch, or membership testing against a Brep). This approach gives more direct control over which cells to include.
Be aware of one important edge case: if filtering produces two or more disconnected clusters of Grid Boxes and you then add a boundary layer to the whole set, the layer expands each cluster outward. When clusters are adjacent, these expansions can land on the same grid coordinate, creating two Grid Boxes at the same position - an invalid grid that causes the Solver to fail. To avoid this, either keep the filtered set contiguous (one connected region), or add the boundary layer before filtering and adjust your filter to keep only the inner cells you need.
Boundary handling
Removing Grid Boxes exposes new boundary Faces on the cells that remain. These are handled automatically by the WFC Solver - no extra Rules are needed for them. If you want explicit control over what appears at the Envelope boundary, see 2.13 Boundary handling.
2.28 Rectangular (non-square) Modules
Monoceros does not require cubic cells - each Axis can have its own dimension. To use a 2:1 aspect ratio for structural bays, or panels that are 3 m wide and 1.5 m tall, set the grid diagonal vector to match the desired cell proportions.
Steps
- Choose a diagonal vector with different values per Axis, e.g.
{2, 1, 3}for cells that are 2 units wide, 1 unit deep, and 3 units tall. - Use Homogeneous Grid with this diagonal to generate Grid Boxes.
- Create a separate Module grid: a Homogeneous Grid with the same diagonal vector and counts of 1×1×1. Use that single Grid Box as the Module box. Keep it visually separate from the Envelope grid in the viewport. The Module dimensions will automatically match the cell dimensions.
- When using Module Rotations, rotations that produce Modules with incompatible dimensions will have mismatched bounding boxes. For non-cubic cells, only rotations around an Axis where both perpendicular dimensions are equal produce valid variants (e.g. for a 2×2×3 cell, Z-Axis rotation works because X and Y are equal). Rotations that transpose dimensions also make sense in a Heterogeneous Grid where Slots of both orientations exist - a 2×1×3 Module rotated 90° around Z becomes a 1×2×3 Module, which is valid wherever a Slot of that shape appears in the Envelope (see 2.11 Heterogeneous Grid).
2.29 Combining manual and automatic Rules
Automatic Rule suggestion is convenient but imprecise - it may miss important pairings or include unwanted ones. Manual Rule definition is precise but tedious for large Module sets. Combining both uses automation for the bulk of the Rule set while leaving room to hand-tune the details.
Strategy
- Run Suggest Rules From Voxels to generate the bulk Rule set automatically.
- Create additional explicit Rules for specific pairings the suggestion missed (e.g. a structural Module that must always sit under a floor Module).
- Connect any Rules that should not exist to the Disallowed Rules input of Construct Assembly (e.g. two incompatible aesthetic Modules).
- Connect all Rule lists (automatic + manual) to the Allowed Rules input of Construct Assembly. Duplicate Rules are harmless - Construct Assembly deduplicates internally.
2.30 Restricting Modules to specific regions
In most usual setups, every Slot is constructed with the same Allowed Modules list - the complete set of all Module Names. To make different parts of the Envelope look or behave differently - ground floor different from upper floors, a façade strip different from the interior, one wing of a building different from another - provide a different Allowed Modules list when constructing the Slots for each region. The Solver then picks only from the permitted vocabulary for each Slot.
Steps
- Create the full Grid Box set.
- Partition Grid Boxes into regions using any spatial query: Z-coordinate ranges for floor levels, containment in a Brep volume for a specific wing, distance from a centre point for a radial split, or Are Grid Boxes Boundary for Envelope vs. interior.
- Construct Slots for each region with only the Module Names relevant to
that zone. For example, ground-floor Slots allow
[entrance, shop_unit, lobby]while upper-floor Slots allow[apartment_a, apartment_b, corridor]. - Make sure Rules exist across the region boundary - the Modules that sit
at the interface between two zones must have Rules connecting them to
each other. If
lobbycan sit belowcorridor, define a Rule forlobby:+Zconnecting tocorridor:-Z. - Merge all Slot lists and solve.
Common region patterns
- Floor zoning - Ground floor public programme, upper floors residential or office. Each level gets its own Module palette.
- Core vs. perimeter - Service or structural Modules in the centre; façade Modules around the edge.
- Wings or phases - Two building wings share a grid but use different Module sets, connected only through a shared transition Module at the junction.
- Roof level - Plant room or roof terrace Modules restricted to the top layer.
2.31 Occurrence Count analysis
Occurrence Count reports how many Slots in the solved Envelope contain a given Module Name - useful for fabrication estimates, cost calculations, or verifying that the distribution matches design intent. Run it once per Module you want to inspect, or loop it across all Module Names.
Steps
- Solve the grid and obtain the solved Slots.
- Connect one Module Name and the solved Slots to Occurrence Count. The component outputs a single integer: the number of Slots that resolved to that Module.
- Repeat for each Module Name you care about, or use a Grasshopper loop to process all names at once.
- Display the counts in a Panel, feed them into a chart, or use them as logic inputs (e.g. a value comparator to flag underrepresented Modules).
Only Resolved
By default (Only Resolved = true), only Slots where
the target Module is the sole allowed option are counted. Set it to
false to also count Slots that still allow the target Module
alongside others - useful for inspecting partially solved or pre-solve
Envelopes.
Applications
- Bill of materials - Count how many of each Module type need to be fabricated.
- Distribution analysis - Verify that Weights and Rules produce the intended proportions.
- Seed comparison - Run multiple Seeds and compare counts to find the most balanced result.
2.32 Exporting results for fabrication
To take a Monoceros result outside Grasshopper - for 3D printing, CNC milling, laser cutting, or handoff to another software package - convert the WFC output into a format suitable for downstream processing: meshes, STEP files, DXF unfoldings, or labelled part lists.
Mesh export (3D printing, game engines)
- Materialize the result to get placed geometry.
- If Module geometry is Brep-based, convert to Mesh using Grasshopper’s Mesh Brep component.
- Join all meshes using Mesh Join.
- Bake to Rhino and export as STL, OBJ, or 3MF.
Part list export (fabrication, CNC)
- Use Occurrence Count to count each Module type.
- Use the Materialize Transforms output to extract position and rotation per placement.
- Export placement data as CSV using Grasshopper’s text writing components: columns for Module Name, X, Y, Z, rotation angle.
- Use this CSV for pick-and-place machines, Assembly instructions, or BIM software.
Unfolding (laser cutting, sheet fabrication)
- Materialize the result.
- Use Grasshopper’s Unroll Brep or third-party unfolding plug-ins to flatten Module geometry.
- Add Module Names or labels to each flattened piece for Assembly reference.
- Export as DXF or PDF for the laser cutter or CNC router.
2.33 Auditing an Assembly
Every Assembly produced by Construct Assembly carries an embedded Audit result. To inspect it, connect the Assembly to the Audit Assembly component. Audit Assembly takes a single Assembly input and exposes more than 30 diagnostic outputs covering the Envelope, Slots, Modules, Rules, and Faces.
Recommended audit workflow
- Wire Construct Assembly's output to both the WFC Solver and Audit Assembly in parallel.
- Check the Report output first - it gives a human-readable summary of all findings.
- If the Report mentions errors, use the individual data outputs to identify exactly which Modules, Slots, or Rules are problematic.
- Fix the inputs to Construct Assembly and re-run. The Assembly and its Audit update automatically.
Key diagnostic outputs
- Slots Without Fitting Modules - Slots whose allowed Modules all have mismatched box dimensions. These Slots will appear empty after Materialize Assembly even if the Solver fills them.
- Module Never In Slot - Modules that are not allowed in any Slot. These cannot appear in any result and may indicate a wiring mistake.
- Faces Not In Rules - uncovered Faces that will become Indifferent when indifference is enabled. Connect to Face Preview to visualize them.
- Potential Over-Constraint - true when uncovered Faces exist and indifference is disabled, which almost always causes Solver contradictions.
- Singly Constrained Faces - Faces covered by exactly one Rule. When all Faces are singly constrained, every Seed produces the same result.
- Effectively Indifferent Faces - Faces that appear in Rules but accept every possible opposing neighbour, so they do not constrain the Solver at all.
Common patterns
- If the Solver contradicts immediately, check Potential Over-Constraint and Faces Not In Rules.
- If results look identical across Seeds, check Singly Constrained Faces.
- If some Slots remain visually empty, check Slots Without Fitting Modules.
2.34 Iterative solving with partial results
You can solve an Assembly in stages by limiting the number of observations per Attempt, then deconstructing the partial result, modifying it, reassembling, and solving again. This gives you manual control over regions of the Envelope while letting the Solver fill in the rest.
Workflow
- First pass - partial solve. Set the WFC Solver's Max Observations to a low number (e.g. 20-50% of the total Slot count). The Solver will assign Modules to some Slots and leave the rest Non-deterministic.
- Deconstruct. Connect the Solver's output Assembly to Deconstruct Assembly. This gives you the partially solved Slots (some Deterministic, some still with multiple candidates), along with the expanded Modules and Rules.
- Modify. Edit the Slots from the previous step. For example:
- Reassemble. Feed the modified Modules, Slots, and Rules back into a second Construct Assembly. This produces a new Assembly with the partial solution baked in and the modified constraints applied.
- Second pass - complete solve. Connect the new Assembly to another WFC Solver instance (or the same one with updated inputs). This time, set Max Observations to unlimited. The Solver will respect the already-determined Slots and fill in only the remaining Non-deterministic ones.
- Materialize. Connect the fully solved Assembly to Materialize Assembly to extract geometry.
Tips
- The Solver treats Deterministic Slots (1 allowed Module) as fixed - it never changes them. This is why partial results carry forward correctly.
- You can chain more than two passes. Each pass can have its own Observation limit, Weight adjustments, and Rule modifications.
- Use Audit Assembly after reassembly to verify that your modifications did not introduce inconsistencies (unknown Module Names, orphaned Faces, etc.).
- Use Changed Slots to compare the Slots before and after each solving pass, so you can see exactly which Slots the Solver filled in.
2.35 Marking unused Faces as Terminators
When Require Terminators is enabled on Construct Assembly, every Module Face that can sit against the Envelope boundary must carry a Terminator. Faces covered by explicit Rules or Connectors usually get Terminators placed by hand, but Indifferent Faces (those with no Rule or Connector) are easy to miss. The Used Faces component finds these gaps automatically.
Workflow
- Identify Unused Faces. Place a Used Faces component. Connect your Modules to its M input, your Rules to R, and (if applicable) your Connectors to C. The Unused Faces (UF) output lists every Face that has no Rule or Connector coverage — one branch per Module.
- Create Terminators. Connect the UF output to Construct Terminator. This produces one Terminator per unused Face.
- Merge Terminators. If you already have manually placed Terminators, merge both lists (e.g. with a Merge component).
- Wire into Construct Assembly. Connect the merged Terminators to the Terminators input and enable Require Terminators. Construct Assembly will now accept every Indifferent Face at the boundary without errors.
Why this works
Indifferent Faces already receive automatic adjacency Rules pairing them with every opposing Indifferent Face. Marking them as Terminators simply declares that they may also Face the boundary — which is the natural expectation for Faces that have no typed constraint. Without these Terminators, Require Terminators would reject any Module whose Indifferent Face happens to land on the Envelope edge.
Tips
- Run this pattern before Construct Assembly so the Terminator list is complete on the first solve.
- Use Audit Assembly after to confirm Terminator Faces Missing is empty.
- If you later add Rules or Connectors to previously Unused Faces, Used Faces will update automatically and the Terminator list will shrink accordingly.
See also workflows and FAQs: 2.13 Boundary handling, 2.20 How to allow all indifferent Faces on the boundary, 4.3.5 Used Faces.
Vocabulary
All terms used in Monoceros 3 documentation and component tooltips, listed alphabetically.
- Attempt
- A single WFC solve run, from Canonicalization through cycles of Observation and Propagation. Multiple attempts with incrementing seeds run automatically when the first attempt ends in a Contradiction.
- Axis
- One of the three coordinate axes: X, Y, or Z. Each Face direction belongs to one axis (positive or negative face).
- Canonical
- The tightest consistent starting state of the Envelope, reached after the initial Propagation pass (Canonicalization). Every Slot contains only Modules that are actually achievable given the Rules.
- Canonicalization
- The initial constraint-propagation pass run before the first Observation. It eliminates already-impossible Module assignments from every Slot so the solver starts from the tightest consistent state. See 1.2 The algorithm.
- Changed Slots
- Compares two sets of Slots element-wise and returns the indices of Slots whose allowed Module list has changed. Useful for tracking which parts of the Envelope were affected by a Rule or weight change. See 4.7.3 Changed Slots.
- Connector
- A named, rotation-aware interface placed on a specific Module face. Combines type identity (name + symmetry flags) and placement (module + face + rotation) in one object. All Connectors sharing a name are the same type. Symmetry flags define which in-plane rotations are self-identical.
- Connector Pair
- Declares that two Connector types (by name) can connect across opposing faces. Bidirectional: A → B also allows B → A.
- Contradictory
- A Slot state where no Module can legally occupy it, making the current solve attempt impossible. The solver retries with a different seed up to the configured attempt limit.
- Deterministic
- A Slot state where exactly one Module is allowed. A fully deterministic Envelope means the solve succeeded and can be materialized.
- Direction
- One of the six face orientations: +X, −X, +Y, −Y, +Z, −Z. Combines an Axis and an Orientation. Direction is not a direct Grasshopper parameter — it is expressed through Face Index names.
- Discrete Assembly
- An opaque bundle containing expanded Modules, Slots, merged Rules, and audit results. Produced by Construct Assembly and consumed by the WFC Solver.
- Entropy
- A measure of how many Module candidates remain in a Slot. Low entropy means few options remain; a Slot with all Modules allowed has maximum entropy. The WFC solver always observes the Slot with the lowest entropy first.
- Envelope
- A set of Slots arranged in a valid grid, forming the spatial volume to be filled by the WFC solver. A grid of Grid Boxes becomes an Envelope once the Grid Boxes are converted to Slots. See 4.2 Envelope.
- Face
- One of the six faces of a Module, identified by a FaceId (e.g. module_name:+X). Rules specify which Face pairs may touch. Every Module has exactly six Faces, one in each direction: +X, −X, +Y, −Y, +Z, −Z. See 3.3.2 Face.
- Face Index
- An integer 0–5 identifying one face direction of a Module or Grid Box: ±X = 0/1, ±Y = 2/3, ±Z = 4/5. See 3.3.1 Face Index.
- Grid Box
- The basic spatial cell unit in a Monoceros grid — a box-shaped region that defines the size and position of one cell. See 3.1.1 Grid Box.
- Heterogeneous Grid
- A grid where cells can have different sizes along each axis. Each row along X can have a different width, each column along Y a different depth, and each layer along Z a different height. See 4.2.1 Heterogeneous Grid.
- Homogeneous Grid
- A grid where every cell has the same X, Y, and Z dimensions. The most common starting point for a WFC setup. See 4.2.2 Homogeneous Grid.
- Indifferent Face
- A Face that has no explicit Rule. When indifference is enabled on Construct Assembly, indifferent Faces automatically connect to any other indifferent Face facing the opposite direction on the same axis.
- Megamodule
- A Module that spans multiple adjacent Grid Boxes, treated as a single design element by the WFC solver. Sub-modules are named {name}_p0/N, {name}_p1/N, etc. All parts carry the full geometry for face analysis; only the first part materializes it. Supports auto-rotation (Rotate X/Y/Z) — the Solver expands all parts together.
- Module
- A named design element that carries geometry and six Faces. During WFC solving each Slot starts with all allowed Modules as candidates. See 3.2.1 Module.
- Module Name
- A lowercase string identifying a Module type. Multiple Modules sharing the same name are treated as Variants of the same type. See 3.2.2 Module Name.
- Module Rotations
- Generate rotated variants of a Module around each enabled axis (90°, 180°, 270°), producing up to 24 unique orientations. See 4.5.6 Module Rotations.
- Non-deterministic
- A Slot state where multiple Modules are still possible. Non-deterministic Slots have not yet been resolved by the solver.
- Observation
- The WFC step where the Slot with the lowest entropy is selected and assigned a single Module, chosen at random weighted by Module weights. See 1.2 The algorithm.
- Occurrence Count
- Counts how many Slots in the envelope contain a given Module Name. By default (Only Resolved = true) only Slots where that Module is the sole allowed option are counted; set Only Resolved to false to also include Slots that still allow the target Module alongside others. Useful for bill-of-materials and distribution analysis after solving. See 2.28 Occurrence Count analysis.
- Orientation
- Positive or negative along an axis. Combined with an axis (X, Y, or Z), orientation defines one of the six faces of a Grid Box or Module.
- Propagation
- The WFC step that cascades the consequences of an Observation through the Envelope. After a Slot is assigned a Module, neighboring Slots that can no longer legally host certain Modules have those candidates removed. This cascade continues until the Envelope stabilises. See 1.2 The algorithm.
- Random Seed
- An integer that initialises the pseudo-random number generator used during WFC Observation. The same seed with the same input always produces an identical result. Changing the seed explores a different solution path without altering any rules or weights.
- Rule
- An allowed adjacency between two Module Faces facing opposite directions. Rules are bidirectional: each adjacency only needs to be defined once. See 3.5.1 Rule.
- Slot
- A cell in the Envelope that holds a list of allowed Module candidates and their weights. Before solving, Slots allow multiple Modules; after solving, each holds exactly one Module (deterministic) or none (contradictory). See 3.4.1 Slot.
- Wave Function Collapse (WFC)
- An algorithm that fills a spatial envelope by alternating Observation and Propagation steps until all Slots are deterministic or a contradictory state is reached. See 1.2 The algorithm.
- Weight
- A per-Module probability value stored in each Slot. Higher weight increases the chance of that Module being chosen during Observation. Default weight is 1.0.
- WFC Solver
- The main Monoceros 3 component. Given a Discrete Assembly it runs the Wave Function Collapse algorithm and returns an output Assembly with solved Slot states, along with diagnostics and statistics. See 4.4.3 WFC Solver.
