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 ↓ ZIP
A ZIP archive containing three bare-minimum Grasshopper definitions.
Puzzle ↓ ZIP
Interlocking puzzle-piece modules that can only connect one way. ZIP archive with a Grasshopper definition.
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 Multi-cell Modules
- 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
- 2.36 Converting Monoceros 1 or 2 projects to Monoceros 3
- Vocabulary
- 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 Multi-cell Modules
- 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
- 2.36 Converting Monoceros 1 or 2 projects to Monoceros 3
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 Cells From Geometry to convert it into Cells.
- 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.
- Detect Rules with Detect 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 an Assembly from the Solver's Assemblies output (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 Detect Rules From Geometry so that only Modules with matching physical Faces are paired. Module geometry may protrude outside the Cell: 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 it to Allowed Modules Weights on Construct Slot alongside Allowed Module Names. 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 Solver Modules across all Slots. Each allowed Orientation counts separately: a single-Cell Module with Full rotation takes 24. Each Cell of a Multi-cell Module also counts separately in each Orientation: a two-Cell Module with Full rotation takes 48.
Concept
The full Monoceros workflow uses six things:
- A Module - the design element the Solver places, carrying optional geometry. A single-Cell Module has six Faces; a Multi-cell Module has numbered external Faces.
- Rules - allowed adjacencies between Faces. A Rule is ultimately between two Faces that point in opposite Directions on the same Axis (for example
+Xand-X). Rule-creation components may also emit non-opposing pairs, which Construct Assembly expands into opposing-Face Rules via rotation variants. 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 Cells with a grid component and then convert each Cell 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 when Run is True and returns solved Assemblies. A complete solution assigns one Module to every Slot. If every Attempt contradicts, it returns a representative Contradictory Assembly with the Contradictory output set to true.
- 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 Cells and Envelope Slots always have identical dimensions, which the Solver requires. - Create a Module Cell - 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 Cell. 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.5, 0, 0}to{-9.5, 0, 0}. 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 Cell 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 Cell here is identical in size to the Module's Cell. - Construct Slots - Use Construct Slot with all Cells 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. Indifference is enabled by default, so uncovered Faces pair freely; turn it off if they must not pair. The component packages everything into a Discrete Assembly.
- Solve - Connect the Assembly to the WFC Solver and set Run to True, for example with a Boolean Toggle. The Solver runs Wave Function Collapse and returns solved Assemblies.
- Materialize - Connect the Solver's Assemblies 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 Rotational Freedom value (0 None, 1 X, 2 Y, 3 Z, 4 Full) directly on Construct Module — pick it on the integer input or from its right-click menu. Construct Assembly will automatically expand it into all valid rotation variants and generate the corresponding Rules. For finer control (for example custom deduplication), use the dedicated Module Rotations component described below. Note that any two perpendicular Axes already generate all 24 orientations, so the options are single-Axis (4 rotations) or Full (24); there is no two-Axis setting.
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 set Rotational Freedom to 4 (Full) for the pipe example. The variants keep the Module Name (pipe, L-pipe) with a rotation index each, and already include the identity rotation, so the rotation output replaces the original Module on the Modules input of Construct Assembly, which merges the variants back into one Module per name with those orientations. 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.
Define the disallowed Rule once against the authored Module. Construct Assembly applies it to every allowed Orientation. 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 an option when the Solver cannot find a complete solution. 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 returns a Contradictory Assembly. Adding an empty Module loosens the constraints where a void is permitted. The resulting layout will contain gaps, so whether this helps depends on the design intent.
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.
For direct boundary control, enable Require Terminators on Construct Assembly and provide Terminators for Faces allowed at the edge; see 2.35. Another solution for the pipe example is to add a surrounding layer of boundary Slots filled with empty Modules whose Rules allow them next to the side Faces of pipe Modules, but not their pipe-end Faces. Every pipe end must then connect inside the Envelope. 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).
- Optionally set Slot Priorities (default 1.0) to resolve higher-priority Slots first. This is the per-Slot control of solve order. Set Remove Unused Connectors (default false) to free Faces occupied by unpaired Connectors so they can become Indifferent.
- For boundary control, supply Terminators and enable Require Terminators (default false). Clean up (default false) trims impossible rotations and unreferenced Modules and Rules; the Solver performs this cleanup automatically.
- 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 and set Run to True. The Solver reads Modules, Slots, and Rules from the Assembly directly.
- After solving, use Materialize Assembly to extract placed geometry from an Assembly in the Solver's Assemblies output. Alternatively, use Deconstruct Assembly to retrieve the authored Modules and Rules and the narrowed Slots, or Dissolve Assembly to inspect the expanded Modules, Slots, Explicit Rules, and Indifferent Rules.
The WFC Solver takes a Discrete Assembly as its 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 Construct Connector. Give each Connector a name (e.g.
"pipe_end","flat_wall"), set its symmetry flags, and specify its Face; wiring a whole Module creates one Connector per Face. 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 Match Connectors By Geometry or Match Connectors By Voxels to derive Connectors by matching a prototype Connector to Module Faces. Detect Connectors From Voxels needs no prototype: it groups Faces by voxel fingerprint and outputs both Connectors and Connector Pairs for opposite-Direction matches.
- Declare which Connector Names can connect using Construct Connector Pair. Its Source Connector Names and Target Connector Names inputs accept lists of names or Connector objects. It produces every source-target combination as a deduplicated flat list.
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 Dissolve Assembly to inspect the expanded Rule set, including Connector-generated and Indifferent Rules. Deconstruct Assembly returns the authored inputs; Audit Assembly provides diagnostic outputs.
- 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 Cell alone, so the Module is spatially valid with no geometry. - Leave Allowed Module Names on Construct Slot unconnected to allow every fitting Module, including
empty, or list names explicitly to restrict a Slot. - 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 ofemptythat 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, omit
emptyfrom the Allowed Module Names 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 Cell, 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 Cell. 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 Cell 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 Cells 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 Cell 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 Cell 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 Cell 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 Cell 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.
By default (Cross Match = true), the component cross-matches: every item in the Source list is tested against every item in the Target list, producing all valid combinations. If you feed three source Faces and four target Faces, you get up to twelve Rules, not three. This is the common use case: allow all listed Faces to connect to all listed Faces. For strictly one-to-one pairing (first source with first target, second with second, and so on), set Cross Match to false.
Both opposing and non-opposing Face pairs are emitted. A non-opposing Rule (e.g. A:+X → B:+Y) is a Connector-symmetry hint that Construct Assembly expands into opposing-Face Rules using rotation variants.
Method B: 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 C: Suggest from geometry
Detect 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 have the same Face dimensions and their sets of local-space points are identical within tolerance (order-independent); there is no opposing-Direction filter, and non-opposing matches are Connector-symmetry hints expanded by Construct Assembly. 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 C 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 D instead.
Detect Rules From Geometry takes a flattened Modules list and compares its external Faces. To limit the search, pass only the subset of Modules you want to compare.
The output of Method C 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 D: Suggest from voxels
Detect Rules From Voxels works like Method C but compares voxelised Face patterns instead of exact geometry. It rasterises each Module at a configurable Voxel Dimension (default 16×16×16 per Module), with Precision (default 48 rays per Cell), Inner Depth (default 0.05) and Outer Depth (default 0.05). Both depths are fractions of Module depth along the Face normal: Inner Depth scans inside the Cell, while Outer Depth scans outside it (0.0 is flush with the Face). Higher resolution or Precision can distinguish finer details at greater computation cost; greater Inner Depth captures more of the Module body behind each Face. Face geometry does not need to be perfectly watertight or analytically exact - as long as both Faces produce the same voxel pattern at the chosen resolution, they are matched. Like Method C, this component outputs Rules directly.
This makes Method D more forgiving than Method C 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 C 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 Cell are invisible to the matcher, and Modules that look compatible at voxel resolution may not fit perfectly at the geometric level.
Both Method C and Method D 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 and Growth Solver operate 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 Solvers do not care about the order in which Modules appear in the list. Leave Allowed Module Names on Construct Slot unconnected when a Slot should allow every Module whose Cell dimensions fit. Supply names only when you need to restrict a Slot; Weights supplied without names are ignored with a Remark.
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. Leave Allowed Module Names on Construct Slot unconnected so every Slot accepts every fitting Module. To restrict Slots, wire the relevant names or Modules to Allowed Module Names; Modules cast to Module Names automatically. 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, Cells, 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. Leave Allowed Module Names on Construct Slot unconnected to admit every fitting Module, or wire a restricted list of names or Modules. 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. Set Rotational Freedom to 4 (Full) for the pipe example; the component defaults to Full.
- The output is a flat list of Modules. Every variant keeps the Module Name (
pipe) and carries a rotation index that says which of the 24 cube orientations it is; the unrotated variant (rotation index 0) comes first. Because the identity rotation is already included, this list replaces the original Module downstream - do not include both, or Construct Assembly reports the repeated name. - Cull Duplicates is enabled by default. It removes variants that are geometrically identical after rotation.
- Optionally filter the list (for example with List Item or Cull Pattern) to keep only the orientations you want. Keep the unrotated variant: Construct Assembly merges the others onto it.
How Construct Assembly reads the variants
Rotations are a property of the Module. Construct Assembly merges the same-name variants back into one Module named pipe whose allowed orientations are exactly the rotation indices that arrived, together with the Rotational Freedom the Module was authored with. The Solver then places pipe only in those orientations. The Module's tooltip shows the preset ((rot Z)) or, for any other set, the count ((rot 2/24)), and the rotation arcs show on the Faces perpendicular to each Axis whose quarter-turn is allowed.
Two Modules that share a name but are not rotation variants of one source Module (for example two separately constructed Modules both named pipe) are still an error.
Generating Rules for all variants
Rules, Connectors and Slots name the Module, not its variants: define them against pipe and its unrotated Faces, exactly as for a Module with a Rotational Freedom set on Construct Module. Construct Assembly rotates them together with the Module for every allowed Orientation. Use any of the methods in 2.8 on the unrotated Module.
Wiring the solver
- Pass the full Module Rotations output list (all variants you keep) to the Modules input of Construct Assembly.
- Allow
pipein the Slots, either by leaving Allowed Module Names unconnected or by passing its name or Module to that input. - Feed the Modules, Slots, and Rules into Construct Assembly, then connect the Assembly to the WFC Solver and set Run to True. Connect the Solver's Assemblies output to Materialize Assembly, which places each Module at the correct position and Orientation.
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 Cells 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.
Unique names for authored Modules; shared names for rotation variants
Each authored Module needs a unique name, including when two Modules have different Cell dimensions. Construct Assembly accepts repeated names only for rotation variants of one source Module from Module Rotations; it merges those variants into one Module with the allowed orientations.
In a Heterogeneous Grid, construct a separately named Module for each distinct Cell size and define its Rules. An allow-all Slot receives only Modules whose Cells fit its dimensions.
Naming Modules of different sizes
Names identify authored Modules. Construct Assembly rejects two separately authored Modules with the same name, regardless of their dimensions. Use distinct names and Rules for distinct sizes or Face behaviour.
Example 1 - T-junction on the long Module only. Name a 1 m pipe pipe-short and a 2 m pipe pipe-long. Give pipe-long the Rule for its T-shaped branch in the Y Direction; do not give that Rule to pipe-short if its geometry has no such branch. The distinct names let you specify different allowed Slot lists and Rules.
Example 2 - different Face profiles across sizes. Give the long and short versions of Modules A and B separate names. Define the +X Rule for the size pairs whose Face profiles actually fit. A Rule for the long pair does not automatically admit the short pair.
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 separately named Module 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 separately named Modules.
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 a uniquely named Module for every distinct Cell size, with its own Rules. Allow-all Slots receive only fitting Modules; Construct Assembly reports an Error if any such Slot has no fit. For manually specified names, Construct Assembly warns when a Module has no fitting allowed Slot. An unfitting Slot causes a Contradiction during solving, and Materialize reports an Error if no variant matches its dimensions. Use Audit Assembly's Slots Without Fitting Modules output to find affected Slots.
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 1.0 in the same Slot. A Weight covers the Module and all its rotation variants. 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 1.0 reduce a Module's likelihood relative to the default; 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.
A Weight of 0 or less is a hard constraint: Construct Slot removes the Module from that Slot entirely and the Solver never considers it there (a Remark reports how many Modules were removed); this is equivalent to removing the Module from the allowed-Module list. Removing every listed Module this way is an Error, not an allow-all Slot. To keep a Module available as a last resort while making it very unlikely, use a small positive Weight (e.g. 0.001) instead of 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 Allowed Module Names and Allowed Modules Weights inputs.
- Connect a list of floats to Allowed Modules 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. For example, if Allowed Module Names receives [
wall,corridor,room], then Allowed Modules Weights can receive [1.0,3.0,1.0] to makecorridorthree times more likely than the others at this Slot. More Weights than names is an Error. Use matching Panels to keep the lists in the same order. - If the Weight list is shorter than the Module list, the last value is repeated for the remaining Modules, both for a flat list and for per-branch lists. For example, [
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 Allowed Modules Weights 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 Cell list you would otherwise pass to Construct Slot.
- For each Cell, 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 Cell, each branch containing one float per Module in the same order as the Module list for that Slot.
- Connect that tree to Allowed Modules Weights on 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 Cells using Homogeneous Grid or Heterogeneous Grid.
- Use Add Boundary Layer to generate additional Cells around the Envelope. Set Layers (default 1), Diagonal Neighbors (default false), and the six Direction inputs Include +X, Include +Y, Include +Z, Include -X, Include -Y, Include -Z (all default true).
- Define a boundary Module (typically with no geometry, named e.g.
boundary). - Create Slots from the boundary Cells, 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 Cells Boundary to identify which Cells are on which Face.
- Create multiple boundary layers with increasing depth.
- For direct boundary control, create Terminators with Construct Terminator or Terminator From Point, connect them to Terminators on Construct Assembly, and enable Require Terminators (default false). Each non-flat boundary Direction needs a Terminator; flat-Axis Faces of a 2D Envelope do not. Terminators are ignored with a Warning when Require Terminators is off. See 2.35.
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 Cells From Geometry to derive the Slot positions automatically rather than placing Cells by hand.
The component maps Rhino geometry onto a regular grid and returns one Cell for each occupied Cell. Populate Method has three values: 0 Surface Wrap marks Cells whose boxes overlap the surface; 1 Fill Volume marks Cells whose centres lie inside a closed volume; 2 Surface Wrap + Fill Volume (default) combines them. Interior Only (default false) keeps Fill Volume Cells strictly inside a Mesh, Surface or Brep, without the Surface Wrap Cells. For full input details and supported geometry types, see § 4.2.8 Cells 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 Cells 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 (Populate Method 0, Surface Wrap), 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 Cells From Geometry with Populate Method 0 (Surface Wrap) 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 Boundary Layer Cells from Add Boundary Layer to create the thickened Envelope. Its output excludes the original Cells.
- Proceed with Construct Slot on the combined Cell list.
Remember that the extra boundary Cells 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 Populate Method 2 (Surface Wrap + Fill Volume, the 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 Cells and define boundary Rules as described in 2.13 Boundary handling.
Curve and point cloud envelopes
Curves produce a one-Cell-wide chain of Cells 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 Cell, 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 Cells where you want to fix a Module.
- Create Slots from those Cells, allowing only the desired Module Name.
- Create Slots for the remaining Cells, 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 multi-cell Module at a specific position
To place a multi-cell Module at a known position in the Envelope, restrict a single Slot to that Module Name and leave the surrounding Slots open with all Module Names allowed. The lock Rules binding the Module's Cells force the neighbouring Slots to resolve deterministically - the Solver has no valid alternative for them - so the whole Module emerges without explicitly constraining every position it occupies. Which Cell lands on the fixed Slot is up to the Solver; constrain more Slots if you need a specific one there.
The only requirement is that the Module 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 Cells 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 Detect Rules From Voxels or Detect 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.
Disallow and Indifference
Disallowed Rules take priority over Indifference-generated Rules. Construct Assembly applies indifference first, then removes disallowed Rules from the combined set. If indifference generates a Rule that matches a disallowed entry, the disallow wins and the Rule is removed.
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
- Multi-cell Module integrity - needs no wiring: the lock Rules binding a Module's Cells are engine-internal, and its internal Faces are never exposed, so a suggester cannot reach them. See 2.18 Multi-cell Modules.
- 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 Multi-cell Modules
A Module occupies one grid Cell per Cell it is given. Give Construct Module several adjacent Cells - a 2×1×1 structural bay, a tall atrium, any element too large for a single Cell - and it becomes one Multi-cell Module that the Solver places as one rigid body.
There are no sub-Modules and no generated part names. The Cells are held together by lock Rules the engine synthesizes during the Assembly build; they are engine-internal and never appear in your Rule list.
Steps
- Select a group of adjacent Cells.
- Connect them to Construct Module with a name and optional geometry.
- The output is one Module. Add it to your Module list like any other.
The footprint must be one Face-connected chunk. Cells touching only along an edge or a corner are not bound to each other and would come apart at solve, so the build rejects them. Two Cells at the same grid position are rejected too.
Each Cell keeps the size of the Cell it came from, so a Multi-cell Module can span a heterogeneous grid - a 2m bay beside a 3m one. Construct Module reconstructs the footprint from the Cells and says which arrangement it rejected when they do not form a grid.
Faces
A Multi-cell Module exposes only the Faces its own footprint does not cover,
numbered per Direction in spatial Cell order: +X0, +X1, +X2, and so on. A
single-Cell Module has one Face per Direction, still spelled +X..-Z, and the
plain integers 0-5 still work.
A bare +X means the whole side - every Cell of the Module exposing that
Direction - and +X0 means the first of those Cells. On a single-Cell Module
that is the same physical Face. On a Multi-cell Module they differ: big:+X
caps or constrains every Face on that side at once, big:+X1 only the second
one.
Because the internal Faces are not exposed at all, there is nothing to filter before running an automatic Rule suggester - Deconstruct Module and Module Faces report the externally visible set directly.
Geometry handling
The geometry attaches to the Module once. Materialize Assembly emits it exactly once per placed instance, from whichever Cells of that instance are inside the Envelope.
Auto-rotation
Set Rotational Freedom (0 None, 1 X, 2 Y, 3 Z, 4 Full) on Construct Module to have Construct Assembly generate rotated variants of the whole body. Rotated variants are anonymous: each carries the authored Module Name plus a rotation index, not a name suffix.
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 - A solved Discrete Assembly from the WFC Solver's Assemblies 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.
- Modules - The Module placed in each Slot, oriented to the Slot position.
All three outputs use the data tree path {assemblyIndex; slotIndex}. The assemblyIndex is the index of the Assembly when several Assemblies are wired; slotIndex identifies the placed Slot. A single solution uses paths {0;0}, {0;1}, and so on. A Multi-cell Module appears once per placed instance, on its anchor Slot. Flattening the tree gives a plain list of 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 - Connector and Rule suggesters derive adjacency from the geometry attached to a Module: they look at where Faces, edges, or points sit relative to the Cell. 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. Materialize skips it and reports a Warning.
- Slot is Non-deterministic - The Slot still holds more than one possible Module, for example after a limited-Observation solve. Materialize skips it and reports a Warning.
- Module Name in Slot not found in the Assembly - The Slot references a Module that is absent from the Assembly. Materialize skips the Slot and reports an Error.
- Rotation variants with the same name - Construct Assembly merges rotation variants of one source Module under its name. Materialize places the first variant that fits the Slot dimensions.
- Repeated authored Module Names - Construct Assembly rejects separately authored Modules with the same name before they reach Materialize.
- Module exists but its dimensions do not match the Slot - If no variant fits the Slot dimensions, Materialize reports an Error and produces no placement for that Slot.
- Module has no geometry - Materialize still outputs a Transform and a Modules entry, but no Geometry and no Remark for that placement. This is normal for Empty Modules.
- Nothing is placed - Materialize reports a Warning with counts of Slots, Modules, Contradictory Slots, and skipped Non-deterministic Slots.
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 Random Seed, Max Attempts, Max Observations, and Return first inputs control its search and outputs. Set Run to True to execute the solve.
| 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 | processor cores + 1 | 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 | true | If true, returns the lowest-Seed fully collapsed Attempt found (or the lowest-Seed partial Attempt if none fully collapses). If false, runs all Attempts and returns all successful results, sorted by Seed. |
| Run | false | Set to True to run the Solver. |
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 for each returned Assembly, including a representative Contradictory result if every Attempt contradicts. 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.14.
There are no good or bad Seeds - all Seeds are equivalent; see FAQ 1.44.
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 an Assembly from the Solver's Assemblies output (after solving) to separate Audit Assembly instances. Comparing the two Audit reports shows how the Slot states changed. The Report output gives a human-readable summary; the individual data outputs give lists you can wire into other components. Enable Diagnose Resolution (default false) on the unsolved Assembly to run a Deterministic diagnostic solve (Seed 0); Resolution then reports which Slots were observed, propagated, or unresolved, including Observation order.
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, and Slots whose candidate Modules all have mismatched Cell dimensions. An unfitting Slot produces a Contradiction during solving; add a fitting Module variant or change the Slot's Cell dimensions.
- Modules - counts how many Slots admit each Module; flags Modules that appear in no Slot or Rule, or whose Faces are absent from Rules; lists Modules with and without geometry; and identifies Modules that only connect to themselves. Separately authored Modules must have unique names.
- Rules and Faces - flags Rules that reference unknown or unused Module Names; reports per-Rule occurrence counts, Rules Never Firing, 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. Viewport tools make Rule connections and Face Directions visible.
- Preview Rule - Draws cubic Bezier curves between Face centres: solid for direct Rules and dashed for rotation-expanded Rules.
- Preview Faces - Draws Face rectangles, anchor planes and Direction arrows, coloured by Direction (+X red, +Y green, and so on); Get Module Faces also previews each Face Direction on a Module.
- 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 settings preserved.
- Preview Connector - Draws Connector arrows, labels, and rotation indicators; with Connector Pairs, it draws Bezier curves between compatible Faces.
2.23 Grid topology analysis
Cells are geometrically placed in 3D space, but the Solver works with a discrete grid of integer coordinates. Grid Topology and Neighbor Cells 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 Cells and outputs two things:
- Relative Coordinates - one integer-coordinate point per Cell, normalised so the minimum corner of the bounding grid is at the origin. Index-matched to the input list: Cell 0 → coordinate 0.
- Topology - a data tree of neighbour indices. Branch
{i}contains the indices of all Cells adjacent to Celli. 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 Cell list, you can use the X, Y, Z components of each coordinate directly as sorting or filtering keys. For example, remap Z values and apply different Allowed Modules Weights to specific Modules within each Slot to create a density gradient. To change solve order instead, wire the remapped values to Slot Priorities on Construct Assembly.
Neighbor Cells
Takes Cells, Cell Indices (the focus Cells), Layers (default 1), and Include X, Include Y, and Include Z (all default true). Returns Neighbor Indices: a sorted flat list of nearby Cell indices within the specified layer count, excluding the input indices.
Provide starting indices from a coordinate filter, an explicit list, or another query, then set Layers to the desired radius. Merge Cell Indices with Neighbor Indices to include both the focus Cells and their neighbours when constructing Slots for a region with different allowed Modules or Weights. For vertical adjacency, disable Include X and Include Y and leave Include Z enabled.
Workflow: inward weight gradient
- Build the Cell 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. - For each Slot, use the remapped value as the Weight of one allowed Module and a different value for another Module on Allowed Modules Weights. This changes their relative likelihood within that Slot. To resolve high-value Slots first instead, wire the values to Slot Priorities on Construct Assembly.
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 retaining the Module Names elsewhere.
- After a complete solve, connect the Solver's Assemblies output to Deconstruct Assembly and use its Slots output. Each solved Slot is Deterministic: exactly one Module Name is allowed.
- Use Grid Topology on the original Cell list to get Relative Coordinates. Filter by coordinate value to identify the region to reopen - all Cells at a specific Z level, an X-range column, or any other positional criterion.
- Pass the selected indices into Neighbor Cells 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.
- Merge the selected focus indices with Neighbor Indices. For that combined selection, construct new open Slots from those Cells with the full (or broader) allowed Module list - Non-deterministic.
- For every other Cell, keep the solved Slots as-is. These Slots retain the solved Module Name, but not its Orientation: rotation variants may be chosen again during the next solve.
- Merge the open Slots with the retained Slots and re-solve. The Solver fills the reopened region while keeping the Module Names in the retained Slots.
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 Cells Boundary provides the boundary indices directly. For Envelope tasks using a boundary layer, see 2.13.
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 Faces in that list: opposing pairs become direct Rules, and non-opposing pairs (including two Faces pointing the same Direction) are Connector-symmetry hints that Construct Assembly expands through rotation variants. 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 endpoint Face pair; non-opposing pairs are Connector-symmetry hints expanded into opposing-Face Rules by Construct Assembly. 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 Faces by Direction as named outputs (+X, −X, +Y, −Y, +Z, −Z). Merge equivalent outputs to build groups manually. Group Faces By Voxels instead groups external Faces with identical voxel fingerprints into Face Groups branches; wire each branch to both Source Faces and Target Faces of Construct Rules From Faces. Rule From Points cross-references Source Points and Target Points on Module Faces to create Rules, alongside the curve-based method above.
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. Set Rotational Freedom to 3 (Z only) on Construct Module or Module Rotations to generate in-plane orientations 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 Cells do not need to fill a convex volume; the Solver handles any contiguous irregular shape.
From geometry (recommended)
Cells From Geometry generates Cells that follow an input shape directly. Set Populate Method to Fill Volume (1) or Surface Wrap + Fill Volume (2) for closed Breps and meshes. Fill Volume selects Cells whose centres lie inside the volume; the combined method also includes surface Cells.
From a filtered rectangular grid
Alternatively, create a full rectangular grid with Homogeneous Grid and remove unwanted Cells using Grasshopper list operations (Cull Pattern, Dispatch, or membership testing against a Brep). This approach gives more direct control over which Cells to include.
If filtering produces disconnected clusters, pass the whole filtered Cell set to one Add Boundary Layer component. It grows one occupancy mask and outputs only the added Cells. Merge that output with the filtered input Cells.
Boundary handling
Removing Cells 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 Cells.
- Create a separate Module grid: a Homogeneous Grid with the same diagonal vector and counts of 1×1×1. Use that single Cell 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 Detect 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 setups, leave Allowed Module Names on Construct Slot unconnected so every Slot admits every Module that fits its Cell. 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 restricted Allowed Module Names list for each region. The Solver then picks only from the permitted Modules for each Slot.
Steps
- Create the full Cell set.
- Partition Cells 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 Cells 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. Wire a list of Module Names to get one Count per name.
Steps
- Solve the grid, connect the Solver's Assemblies output to Deconstruct Assembly, and use its Slots output.
- Connect the Module Names you want to count and the solved Slots to Occurrence Count. The component outputs one Count per Module Name.
- Use the full Module Name list to count all Modules at once; no loop component is required.
- 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.
The WFC Solver right-click Export Project… item writes the authored setup as a portable Monoceros project file, JSON with inline OBJ geometry. It contains no solved Slot states or Random Seed. Use the methods below to export results.
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 Audit Assembly. It has two inputs, Assembly and Diagnose Resolution (default false), and 47 diagnostic outputs covering the Envelope, Slots, Modules, Rules, Faces, and resolution.
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.
- On an unsolved Assembly, enable Diagnose Resolution and inspect Resolution for observed, propagated, and unresolved Slots and their Observation order. Check Rules Never Firing for authored Rules that cannot apply.
- 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 Cell dimensions. These cause a Contradiction during solving; add a fitting Module variant or change the Slot's Cell dimensions.
- Module Variant Never In Slots - Module variants 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 Preview Faces 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 a Slot has no fitting Module, check Slots Without Fitting Modules and correct the allowed Modules or Cell dimensions.
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 an Assembly from the Solver's Assemblies output to Deconstruct Assembly. This gives you narrowed authored Slots (some Deterministic, some still with multiple candidates), along with the authored Modules and Rules. A Deterministic Slot retains the source Module Name, but not its solved Orientation.
- 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, each boundary-facing Module Face on a non-flat Axis needs a Terminator, and at least one Terminator is required in each Direction. Faces on a flat Axis, such as the front and back of a 2D Envelope, need no 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.
Workflow
- Identify Unused Faces. Place a Used Faces component. Connect your Modules to its M input, your Rules to R, your Connectors to C, and any existing Terminators to T. The Unused Faces (UF) output lists every Face without Rule, Connector, or Terminator 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. Check that each required boundary Direction has at least one Terminator.
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.6 Used Faces.
2.36 Converting Monoceros 1 or 2 projects to Monoceros 3
Monoceros 1 and 2 ship a Convert to v3 component on a new Monoceros 3 ribbon tab. Drop it onto the wire that crosses from your legacy definition into Monoceros 3 and it produces v3 Modules, Rules, and Slots that you wire into Monoceros 3's Construct Assembly. The conversion is one-shot and reversible — the original definition stays untouched, the converter sits on top of it, and you can delete the converter to fall back to the legacy Solver at any time.
Prerequisites
- Install Monoceros 3 from the Yak Package Manager or monoceros.tools. Monoceros 1, 2, and 3 are independent
.ghaplug-ins and load side-by-side in the same Rhino session. - Update the legacy plug-in to the build that includes the Monoceros 3 ribbon tab. Earlier releases of Monoceros 1 and 2 do not contain the converter.
- Restart Rhino so Grasshopper picks up both plug-ins. When v3 is detected, every legacy component shows a yellow remark "Monoceros 3 is installed…" pointing at the converter.
Steps
- Open your existing Monoceros 1 or 2 definition.
- From the Monoceros 3 ribbon tab on the legacy plug-in (not the v3 tab), drop a single Convert to v3 component onto the canvas.
- Wire your legacy Modules, Rules, and Slots into the converter's three inputs. The converter needs all three together so it can resolve cross-references (multi-Cell Rule indices into Modules, typed-Rule names into Connectors, and so on).
- Wire the converter's outputs into Monoceros 3's Construct Assembly:
- From v1: five outputs — v3 Modules, Rules, Connectors, Connector Pairs, Slots.
- From v2: three outputs — v3 Modules, Rules, Slots. v2 has no typed Rules, so no Connectors or Connector Pairs are emitted.
- Wire Construct Assembly into the v3 WFC Solver, set Run to True, and continue through the v3 pipeline.
How the type translation works
- Slots. Box, allowed Module Names, Weights, and allow-all flag transfer 1:1 from v2; v1 Slots reconstruct the Box from the legacy
BasePlane,RelativeCenter, andDiagonal. The v3-only original allow-all flag takes its default. - Single-Cell Modules. Rebuilt with the same Box and geometry. In v3, Rotational Freedom defaults to 0 (None); set it to 1-4 on a converted Module to enable rotation variants.
- Megamodules (v1 only). Converted to a single v3 Multi-cell Module whose footprint is the original Cell set. The engine synthesizes the lock Rules during the Assembly build, so no extra Rules are emitted.
- Explicit Rules. 1:1 cast from both v1 and v2. A v1 Megamodule Rule index is re-targeted to the corresponding numbered Face of the converted Multi-cell Module.
- Typed Rules (v1 only). Each typed Rule becomes a v3 Connector with all symmetry flags set to
true(matching v1's untyped behaviour). Unique Connector type names are emitted asConnectorPair(name, name)so any Face taggedTconnects to any other Face taggedT, preserving v1 semantics. - Indifference. v1's
"indifferent"typed Rule converts to a v3 Connector / ConnectorPair pair named"indifferent". v3 also has a separate Indifference flag on Construct Assembly (default on) that auto-pairs Unused Faces. The converter raises a Remark whenever it sees Indifferent Rules so you can choose:- Strict v1 parity — turn the v3 Indifference flag off. Only the Faces explicitly marked Indifferent in v1 will accept any neighbour.
- Modern v3 behaviour — leave the flag on. v3's auto-indifference covers any unused Face in addition to the converted ones, which is usually what you want for a fresh project but more permissive than v1's strict model.
- Reserved characters. v3 reserves
:,->,@,#, and newline in Module and Connector Names. Names containing these are sanitised (->becomes_to_, others become_). The converter logs a Remark naming both the original and rewritten name. If two distinct legacy names sanitise to the same v3 name, the converter does not auto-rename — rename one of them in your legacy definition before converting.
What is not converted
- Discrete Assembly. The converter emits the ingredients (Modules, Rules, Slots, optionally Connectors and Pairs) and leaves the Assembly itself to v3's Construct Assembly. This means new v3 features — Terminators, indifference toggles, exclusive Rules, Audit, rotation expansion — all flow into your converted definition automatically as v3 evolves.
- Terminators. v1 and v2 expressed strict-boundary semantics through the built-in
OutModule. v3 uses explicit Terminators authored against Module Faces. After conversion, add Terminators in v3 if you need strict boundary enforcement — see 2.35 Marking unused Faces as Terminators. - v1's
Emptyreserved name. v3 has no reserved Module Names:OutandEmptyare ordinary Module Names. Use a Module without geometry for a Slot that may Materialize as empty; see 2.6 Empty Module.
After converting
The converted definition runs in v3 with v1/v2 behaviour. To take advantage of v3 features, layer them on top:
- Set Rotational Freedom to 1-4 on individual Modules to enable rotation variants.
- Add Terminators and toggle Require Terminators on Construct Assembly for strict boundary control.
- Replace typed Rules (v1) with Connectors authored directly against Module Faces — converted Connectors are a drop-in replacement and easier to reason about.
- Use v3's Audit and Used Faces components to spot orphaned Faces, missing Rules, or Modules unreachable from the boundary.
See also: FAQ entries on converting from Monoceros 1 or 2, 2.18 Multi-cell Modules, 2.3 The Assembly workflow.
Vocabulary
All terms used in Monoceros 3 documentation and component tooltips, listed alphabetically.
A single WFC solve run, from Canonicalization through cycles of Observation and Propagation. Additional Attempts with incrementing Seeds run when the first Attempt does not fully collapse, or when Return first is off.
One of the three coordinate Axes: X, Y, or Z. Each Face Direction belongs to one Axis (positive or negative Face).
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.
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.
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.
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.
Declares that two Connector types (by name) can connect across opposing Faces. Bidirectional: A → B also allows B → A.
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.
A Slot state where exactly one Module is allowed. A fully Deterministic Envelope means the solve succeeded and can be materialized.
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.
An opaque bundle containing expanded Modules, Slots, merged Rules, and Audit results. Produced by Construct Assembly and consumed by the WFC Solver.
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 selects the highest Slot Priority band, then the Slot with the lowest Entropy within that band.
A set of Slots arranged in a valid grid, forming the spatial volume to be filled by the WFC Solver. A grid of Cells becomes an Envelope once the Cells are converted to Slots.
See 4.2 Envelope.
An external Face of a Module, identified by a FaceId (e.g. module_name:+X). Rules specify which Face pairs may touch. A single-Cell Module has six Faces, one in each Direction. A Multi-cell Module has numbered external Faces per Direction (for example +X0 and +X1).
See 3.3.2 Face.
An integer 0–5 identifying one Face Direction of a Module or Cell: +X = 0, +Y = 1, +Z = 2, −X = 3, −Y = 4, −Z = 5.
See 3.3.1 Face Index.
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 Cell.
Places Modules one Slot at a time from a Discrete Assembly, extending along the frontier of placed Modules. Slots can settle empty; it returns the grown Assembly, Report, Settled, Placed, and Empty.
See 4.4.2 Growth Solver.
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.
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.
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.
A Module that spans several adjacent Cells and is placed as one rigid body. Give Construct Module more than one box; the geometry attaches once and materializes once per placed instance. Externally visible Faces are numbered per Direction (+X0, +X1, ...). Supports auto-rotation via a Rotational Freedom value (0 None, 1 X, 2 Y, 3 Z, 4 Full) — the whole body rotates together. Previously a separate Megamodule type.
A named design element with optional geometry and external Faces. A single-Cell Module has six Faces; a Multi-cell Module has numbered external Faces. During WFC solving each Slot starts with its allowed Modules as candidates.
See 3.2.1 Module.
A name identifying an authored Module. Separately authored Modules need unique names; only rotation variants of one source Module share its name.
See 3.2.2 Module Name.
Generate variants using one Rotational Freedom value: 0 None, 1 X only, 2 Y only, 3 Z only, or 4 Full (up to 24 orientations).
See 4.5.4 Module Rotations.
A Slot state where multiple Modules are still possible. Non-deterministic Slots have not yet been resolved by the Solver.
The WFC step where a Slot in the highest Slot Priority band with the lowest Entropy is selected and assigned a single Module, chosen at random weighted by Module Weights.
See 1.2 The algorithm.
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.31 Occurrence Count analysis.
Positive or negative along an Axis. Combined with an Axis (X, Y, or Z), Orientation defines one of the six Faces of a Cell or Module.
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.
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.
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.
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.
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.
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.
The main Monoceros 3 component. Given a Discrete Assembly and Run set to True, it runs Wave Function Collapse and returns solved Discrete Assemblies on Assemblies, along with diagnostics and statistics.
See 4.4.5 WFC Solver.
