# Monoceros > Monoceros 3 is a discrete assembly plug-in for Grasshopper / Rhino by Ján Pernecký. It fills a spatial Envelope with discrete Modules according to user-defined Rules using the Wave Function Collapse (WFC) algorithm. It provides an innovative and fast solution to the architectural problem of discrete aggregation for purposes of design, architecture and urban planning. ## Key Concepts - **Module**: The fundamental design element. Carries a name, optional geometry, and a Grid Box defining its cell size and pivot. Each Module has exactly six Faces (one per face: +X, -X, +Y, -Y, +Z, -Z). Modules are placed into Slots during solving. When geometry comes from referenced Rhino document objects, the Module captures each piece's display color, layer name, and linetype name at construction time. These attributes are preserved through rotations and baking - the original objects do not need to exist at bake time. - **Slot**: One cell in the Envelope. Holds the list of Module Names allowed to occupy it and a per-Module weight for each candidate. States: deterministic (1 allowed Module), non-deterministic (2+ allowed), contradictory (0 allowed), allow-all (unresolved, empty list + zero Total Modules Count, filled by Construct Assembly with the full final Module set). - **Rule**: Defines an allowed adjacency between two Module Faces. Holds a source Face and a target Face facing opposite directions (e.g. wall:+X -> corner:-X). Rules are bidirectional for equality. Each adjacency only needs to be defined once. - **Face**: Uniquely identifies a specific face on a specific Module. Combines a Module Name and a Face Index (0-5 mapping to +X, +Y, +Z, -X, -Y, -Z). Opposite faces always have indices that sum to 5. - **Envelope**: A collection of Slots forming the spatial domain to be solved. Created by converting Grid Boxes into Slots via the Construct Slot component. - **Grid Box**: The basic spatial cell unit -- a box-shaped region defining the size and position of one cell. Multiple Grid Boxes form a grid. Grid Boxes carry only geometry (size and position); Slots additionally carry allowed Module lists and weights. - **Connector**: A named, rotation-aware interface placed on a specific Module Face. Combines type identity (name + symmetry flags) and placement (FaceId + rotation) in one object. All Connectors sharing a name are the same type. Symmetry flags define which in-plane rotations {0°, 90°, 180°, 270°} are self-identical. Connectors generate Rules automatically when combined with Connector Pairs. The Connector data type does not support viewport preview - preview is provided by the producing component. - **Connector Pair**: Declares that two Connector types (by name) can connect across opposing Faces. Bidirectional: declaring A→B also allows B→A. - **Terminator**: A boundary-facing marker placed on a specific Module Face. Declares that the marked face is allowed to sit against the envelope boundary when Require Terminators is enabled on Construct Assembly. Created with Construct Terminator (from a Face or Module) or Terminator from Point (from a viewport click). Terminators carry no name, rotation, or symmetry. String format: `"Terminator@moduleName:faceIndex"` (e.g. `"Terminator@pipe:+X"`). - **Assembly (Discrete Assembly)**: An opaque bundle containing expanded Modules, Slots, merged Rules, and audit results. Produced by Construct Assembly and consumed by the WFC Solver. Replaces the manual Module Rotations → rule merging → audit wiring pattern. ## Workflow A typical Monoceros 3 workflow follows these steps: 1. **Define a Grid** -- Use Homogeneous Grid or Heterogeneous Grid to create Grid Boxes. 2. **Construct Modules** -- Define each Module with a name, Grid Box, and optional geometry. Set rotation flags (Rotate X/Y/Z) if rotation variants are desired. 3. **Define Rules** -- Create explicit Rules (from Face pairs, Module pairs, or geometry suggestion) and/or define Connectors for rotation-aware Rule generation. 4. **Construct Slots (Envelope)** -- Create Slots from Grid Boxes, optionally specifying which Modules are allowed in each Slot and their relative weights. If the Allowed Module Names input is left unconnected, the Slot becomes allow-all and Construct Assembly resolves it to the full final Module set automatically. 5. **Add Boundary** -- Optionally add boundary Grid Boxes, convert to boundary Slots, and merge with interior Slots. 6. **Construct Assembly** -- Feed Modules, Slots, Rules, Connectors, Connector Pairs, and optionally Terminators into Construct Assembly. This expands rotation variants, generates connector-based rules, removes disallowed rules, enforces exclusive rules, applies indifference, deduplicates, audits, and packages everything. Disallowed Rules/Connector Pairs remove specific adjacencies; Exclusive Rules/Connector Pairs remove all other adjacencies referencing the same Faces. Enable Require Terminators to enforce boundary coverage -- every Module Face that may touch the outer edge must have a Terminator. 7. **Solve** -- Connect the Assembly to the WFC Solver. The Solver returns an output Assembly with solved Slot states. 8. **Materialize** -- Use Materialize Assembly to extract geometry from the solved Assembly, Slot to Module to place Module geometry into solved Slots directly, or Deconstruct Assembly to access Modules, Slots, and Rules. ## Components Monoceros 3 provides Grasshopper components in the Monoceros 3 tab, organized into seven categories. ### Main (6) - **Construct Assembly** (Assembly) -- Expand rotation variants (with face-permutation-based rule remapping: only variants with the same rotation are paired, since the spatial neighborhood rotates as a rigid unit), resolve allow-all Slots by filling them with the full final Module set (uniform weights, dimension-filtered; a single summary Remark reports how many Slots were resolved and to how many Modules), deduplicate Allowed Connector Pairs by value equality (cross-referenced pair lists often contain exact duplicates; dropping them up front saves significant computation in the pair rule generator), generate connector-based rules, remove disallowed rules, enforce exclusive rules, apply indifference, merge all rule sources, audit, and package into a Discrete Assembly. Rejects duplicate Modules with the same name AND same dimensions (true duplicates); same-name Modules with different dimensions are valid (rotation variants). Previews explicit rules as lines between original module face centers (rotation variants are mapped back via inverse permutation). Inputs include Allowed Rules, Disallowed Rules, Exclusive Rules, Connectors, Allowed Connector Pairs, Disallowed Connector Pairs, Exclusive Connector Pairs, Require Terminators, Terminators, and Indifference. Exposure: primary. - **Deconstruct Assembly** (DeAssembly) -- Extract all authored inputs from a Discrete Assembly: Modules, Slots, Connectors, Allowed/Disallowed/Exclusive Connector Pairs, Rules, Disallowed Rules, Exclusive Rules, Indifference, Terminators, and Require Terminators. Exposure: primary. - **WFC Solver** (Solver) -- Run Wave Function Collapse. Takes a Discrete Assembly as its sole data input. Returns an output Assembly with solved Slot states. Exposure: tertiary. - **Materialize Assembly** (Materialize) -- Extract placed geometry from a solved Discrete Assembly. Takes an Assembly as input, produces geometry. Only deterministic Slots (exactly one allowed Module) are materialized; non-deterministic and contradictory Slots are skipped with a Warning - run the Solver first to collapse the Assembly. When multiple Module variants share a name but have different dimensions, the component selects the variant whose dimensions match the Slot. Baked geometry preserves the color, layer, and linetype captured at Module construction time. Exposure: quarternary. - **Audit Assembly** (Audit) -- Analyze a Discrete Assembly for consistency and errors. Takes a Discrete Assembly as its sole input. More than 30 diagnostic outputs. Exposure: quarternary. - **Sample Geometry** (SampleGeo) -- Create Module candidates by sampling input geometry into Grid Box cells. Voxelizes input geometry at specified resolution, intersects with each Grid Box, clips geometry to box bounds, and assembles Modules with unique names. Exposure: septenary. ### Connector (8) - **Connector from Face** (ConnFromFace) -- Create named interfaces on Module Faces with symmetry flags and rotation. Inputs: Connector Name, Face (list of FaceId), Face Rotation (accepts 0-3 or 0/90/180/270), four symmetry flags, All Modules (optional, for viewport preview). 8 inputs total. A Module may be wired directly into the Face input - it is cast to a wildcard face that expands in-component into the module's six explicit faces, producing one Connector per face. Output is flattened. Formerly "Construct Connector". - **Connector from Point** (ConnFromPt) -- Create one Connector per Module Face matched by a Point3d tag. Inputs: Connector Name, Modules, Point Tag, Face Rotation, four symmetry flags. 8 inputs total. Uses the same point-in-face matching as Faces from Point and the same validation as Connector from Face. Zero matches raise a Warning; multiple matches emit a Remark and produce one Connector per match. Output is flattened by default. Exposure: primary. - **Deconstruct Connector** (DeconConn) -- Deconstruct a Connector into connector name, rotation, module name, and face id. The inverse of Connector from Face. Exposure: secondary. - **Construct Connector Pair** (ConnPair) -- Declare which Connector types can connect. Takes single items: Source Connector (item) + Target Connector (item) produces one Connector Pair (item). Use Grasshopper's cross-reference to make multiple pairs. - **Suggest Connectors from Geometry** (SuggestConGeo) -- Find matching Faces from an exemplar Connector by geometry with rotation detection. - **Suggest Connectors from Voxels** (SuggestConVox) -- Same as above but using voxelized geometry. - **Construct Terminator** (ConstructTerm) -- Create Terminators from a Face or Module. A Module wired into the input is expanded to all six faces, producing one Terminator per face with a Remark. Optional All Modules input for viewport preview. Exposure: primary. - **Terminator from Point** (TermFromPt) -- Create one Terminator per Module Face matched by a Point3d tag. Uses the same point-in-face lookup as Faces from Point. Zero matches raise a Warning; multiple matches emit a Remark. Exposure: primary. ### Envelope (8) - **Homogeneous Grid** (HomoGrid) -- Generate a regular grid of uniform cells. - **Heterogeneous Grid** (HeteroGrid) -- Generate a grid where cells along each axis can have different sizes. - **Add Boundary Layer** (AddBound) -- Surround an Envelope with additional layers of Grid Boxes. - **Are Grid Boxes Boundary** (AreBoxesBound) -- Identify which Grid Boxes sit on the outer boundary of an Envelope. - **Deconstruct Grid Box** (DeconGridBox) -- Extract center plane, diagonal dimensions, and axis intervals from a Grid Box. - **Neighbor Grid Boxes** (Neighbors) -- Find Grid Boxes adjacent to a given set of focus cells. - **Grid Topology** (Topology) -- Extract discrete grid coordinates and adjacency map of an Envelope. - **Grid Boxes from Geometry** (GeoGrid) -- Generate Grid Boxes covering the shape of input geometry for non-rectangular Envelopes. ### Module (6) - **Construct Module** (ConstModule) -- Construct a Module from a name, Grid Box, and optional geometry. When geometry references Rhino document objects, the Module captures each piece's display color, layer name, and linetype name for baking. - **Deconstruct Module** (DeconModule) -- Extract name, Grid Box, geometry, validity, and Faces from a Module. - **Module Rotations** (ModuleRot) -- Generate up to 24 rotated variants with optional voxel-based deduplication. - **Cull Duplicate Modules** (CulDupModule) -- Remove duplicate Modules by voxel comparison. Optionally remaps Rules. - **Construct Megamodule** (Megamodule) -- Create a multi-cell Module from adjacent Grid Boxes with auto-generated internal Rules. Supports auto-rotation (Rotate X/Y/Z). Sub-modules named `{name}_p0/N`, `{name}_p1/N`, etc. All parts carry full geometry for face analysis; only the first materializes it. Outputs Modules and External Faces as data trees. - **Deconstruct Megamodule** (DeconMegamodule) -- Extract Grid Boxes, internal Rules, and external Faces from Megamodule sub-Modules. ### Face (6) - **Get Module Faces** (ModFaces) -- Extract the 6 individual Faces from a Module. - **Analyze Face** (AnalyzeFace) -- Analyze Face properties including geometry, direction, and Rule/Connector usage. - **Compare Faces** (CompFaces) -- Compare two Faces for identity, Module membership, and direction relationship. - **Faces from Point** (FacesPoint) -- Detect Module Faces at a point location. - **Used Faces** (UsedFaces) -- Filter Module Faces by Rule and Connector coverage. Outputs used Faces (referenced by at least one Rule or Connector) and unused Faces (no reference). Wire unused Faces into Construct Terminator to mark uncovered Faces as boundary-safe when using Require Terminators. - **Preview Faces** (FacesPreview) -- Visualize Faces with geometry, anchor planes, and direction indicators. ### Rule (8) - **Construct Rules from Faces** (RuleFromFaces) -- Create Rules from all valid opposite-direction combinations between two Face lists. - **Construct Rules from Modules** (RuleFromModules) -- Build Rules from source and target Module Name lists with six directional target inputs. - **Deconstruct Rule** (DeconRuleFaces) -- Extract source and target Faces from a Rule. - **Suggest Rules from Geometry** (RulesSuggest) -- Analyze Face geometry and output Rules for all matching pairs. - **Suggest Rules from Voxels** (RulesSuggestVox) -- Voxelize Modules and output Rules for all face pairs with matching voxel face patterns. - **Are Rules Equal** (AreRulesEq) -- Compare two Rules for equality (bidirectional). - **Rule from Curve** (RuleFromCurve) -- Create Rules from curves drawn between Module Faces. - **Preview Rule** (RulePreview) -- Display Rules as lines connecting Faces for visual verification. ### Slot (7) - **Construct Slot** (SlotConstruct) -- Create a Slot from a Grid Box with optional allowed Module Names and optional weights. If Allowed Module Names is unconnected, the Slot is created in an "allow all" state (empty list) and will be resolved to the full final Module set by Construct Assembly; Weights are then ignored. If Allowed Module Names is connected but Weights is left unconnected or empty, every allowed Module gets a uniform weight of 1.0. Every Slot is created with AllModulesCount = 0 - Construct Assembly stamps it with the size of the final Module set so Slots only carry the allowed-count pre-Assembly and the full "allowed / total" ratio post-Assembly. Duplicate Module Names in the same branch are handled automatically: if all duplicates share the same weight, they are deduplicated with a Remark; if weights differ, an Error is raised. - **Deconstruct Slot** (DeconSlot) -- Extract Grid Box, allowed names, weights, determinism flag, contradiction flag, and entropy. - **Slot Pattern** (Pattern) -- Find a Slot sub-pattern inside an existing Slot envelope. - **Changed Slots** (ChngSlt) -- Identify which Slots changed between an original list and one or more new Slot lists. - **Occurrence Count** (OccurrCount) -- Count how many Slots contain a given Module Name. Useful for fabrication estimates and distribution analysis. Counts only deterministic Slots by default. - **Slot to Module** (SlotToMod) -- Place Module geometry into solved Slots. Takes a flat list of Modules and a tree of solved Slots. By default only deterministic Slots (exactly one allowed Module) are materialized; set Only Deterministic to false to also place geometry for every allowed Module in non-deterministic Slots. Contradictory Slots are always skipped. Supports baking to Rhino as shared block definitions. Exposure: tertiary. - **Preview Rule in Slots** (PreviewRule) -- Preview a Rule by placing modules into deterministic Slots with co-located Modules for visualization. Outputs Source/Target Slots and Source/Target Modules. ## Common Issues 1. **"World state is contradictory"** -- The solver found a Slot with zero allowed Modules during propagation. Your Rules are too restrictive for the Envelope and Module set. Fix: add more Rules, add an empty Module (no geometry) to fill leftover spaces, increase Max Attempts, or use Audit to check for orphaned Faces. 2. **Solver cannot find a solution** -- The Rule set may be inherently contradictory. Common causes: a Module with no valid neighbour on one face, boundary Modules without Rules to interior Modules, Envelope too small, or conflicting weighted constraints. Use Audit to diagnose. Simplify first. 3. **What makes a good Module** -- The most important principle is "exciting middle, boring edges": put interesting content (walls, surfaces, objects) in the center of the Module, not at the edges. Faces should show only cross-sections, never complete surfaces. Module size should be approximately half the smallest semantic object (e.g. 1.5m Modules for 3m rooms). Module geometry should not touch the Grid Box faces (interferes with Suggest Faces). Modules contain parts of objects, not whole objects - a room is not a Module. Multiple Modules can share identical geometry but carry different names and Rules. Keep metadata separate from Modules; distribute it during Materialize. When designing systems with multiple independent spatial layers (roads, greenery, structure), design each system's Modules independently and bridge them with interface Modules. 4. **How to create an empty Module** -- Use Construct Module with a name like "empty" and a matching Grid Box. Do not connect geometry. Define Rules connecting its Faces to other Modules. Multiple empty Modules with different names can serve different boundary/interior roles. 5. **Zero-weight Module still appears** -- Zero weight does not remove a Module from the allowed set during propagation. If all other options are eliminated, the solver must use it. To prevent a Module in a zone, remove it from the Slot's Module Names list entirely. 6. **Module shows red in viewport** -- The Module is invalid. Check for reserved characters in the name (:, ->, #, newlines) or a degenerate Grid Box (zero volume). 7. **Same seed gives different results after changes** -- Expected. Any change to inputs (Modules, Rules, weights, Envelope size) changes the solver's decision sequence. Even small changes cascade into different results. 8. **Solver fails with larger Envelopes** -- Constraint chains grow longer and more likely to contradict. Add more flexibility (more Rules, empty Modules, more Module types), increase Max Attempts, or use a multi-scale approach. 9. **How to handle boundaries** -- Monoceros has no implicit boundary. Use Add Boundary Layer to generate Grid Boxes, create Slots with boundary Modules, define Rules connecting boundary to interior Faces. 10. **Weights are a Slot property, not a Module property** -- The same Module can have weight 5.0 in one Slot and 0.0 in another. Weights are specified per-Slot on Construct Slot, enabling attractor-based gradients and regional frequency control. 11. **Common Module design mistakes** -- (a) Making one room = one Module: a Module contains a part of a room, not a whole room. Whole-object Modules lose the combinatorial variety WFC produces. (b) Expecting empty space automatically: the solver fills every Slot. Include explicit empty Modules (no geometry) with Rules. (c) Confusing Monoceros with growth algorithms like WASP: WASP grows aggregates incrementally from a seed; Monoceros fills a fixed Envelope all at once via constraint propagation. Different paradigms. 12. **Indifference rule explosion** -- Indifference rule count grows quadratically: for M modules with unused faces, up to 3 x M² rules are generated. With rotation variants, M can be 24x the original module count. Example: 10 modules with all rotations = 240 variants = up to 172,800 indifference rules. Fix: add explicit Rules or Connectors to cover more faces - each covered face is excluded from the indifferent set. Note: terminator-to-boundary rules (the synthetic rules linking Terminator-marked faces to the boundary module when Require Terminators is on) do NOT count as "covering" a face for indifference purposes - a face covered only by terminator rules still receives indifference rules. Only explicit Rules and Connector-generated Rules suppress indifference for a face. Construct Assembly warns when indifference generates more than 10,000 rules. 13. **"Some modules lack adjacency rules on non-flat axes"** -- The Solver validates before running that every Module has at least one Rule on each non-flat axis in both directions (as low-side and high-side neighbor). A gap would leave the solver with an empty adjacency mask on that axis, making the world unsolvable. Fix: add Rules or Connectors covering the reported Module faces, or enable Indifference for uncovered faces. 14. **Require Terminators on flat (2D/1D) grids** -- When the grid has extent 1 in one or more dimensions (e.g. a 10x10x1 grid for a floor layout), Construct Assembly automatically skips boundary wrapping, Terminator Rules, and self-adjacency on those flat axes. You do not need Terminators for flat-axis faces. The Audit component also skips flat-axis faces in the Terminator coverage check. ## Licensing Monoceros 3 has four license tiers. All tiers use the same plugin -- the tier is determined by your Gumroad purchase email. - **Free** -- No purchase required. Full functionality on any envelope size, but the WFC Solver component is rate-limited to a limited number of runs per fixed time window (windows are aligned to UTC clock boundaries). Each solver invocation (regardless of the internal "Max Attempts" setting) counts as one run. Once the cap is hit, the solver shows a "limit reached" message and displays when the next run becomes available. - **Annual** -- Yearly subscription, unlimited solver runs, 7-day offline grace period. - **Edu** -- Discounted annual license for students and educators, 7-day offline grace period. - **Lifetime** -- One-time purchase, unlimited solver runs permanently, 1-year offline grace period. All tiers share a hard limit of 16,370 distinct Module names (each rotation variant counts as a separate name). The WFC Solver component also has a mandatory `Run` boolean input (default `false`). The solver only executes when `Run = true`, so upstream slider changes cannot accidentally burn through your run budget. Connect a Boolean Toggle or a Button component. License validation requires an internet connection. Licenses are cached locally so the plugin works offline for the grace period. After that, it falls back to Free mode until it can reach the server again. On first launch, the plugin may show a registration dialog inviting you to enter your email. Registration is separate from licensing -- it is for product updates and can be skipped. When a subscription ends, the plugin falls back to Free mode (WFC Solver runs rate-limited per fixed time window). Definitions and settings are preserved. Lifetime licenses never expire. ## Further Reading For the complete reference including 47 FAQ answers, tips, workflow strategies, 30 step-by-step example workflows, full data type specifications, and detailed component input/output parameters, see: - Complete LLM reference: https://www.monoceros.tools/llms-full.txt ## Links - Documentation: https://www.monoceros.tools/monoceros-v3-manual/ - Examples: https://www.monoceros.tools/monoceros-v3-manual/workflows.html - FAQ: https://www.monoceros.tools/monoceros-v3-manual/faq.html - Download: https://www.food4rhino.com/app/monoceros