GridGroup
A GridGroup arranges objects in regular patterns — rows, 2D grids, rectangular borders, and curved arcs. It is anchorless: there is no central object, just a pattern laid out around the group’s own center. This is the tool for repeated furniture: classroom desks, auditorium seating, a row of lockers.
The four patterns, laid out around the group's own center — no anchor: rows and grids share one orientation, border slots face inward, arc slots tilt along the curve.
with scene.GridGroup(sparsity=0.5) as classroom:
chair = scene.AddAsset("a dark wooden dining chair")
classroom.place_grid(6 * chair, cols=3)
place_row(objects)
Lays objects out in a single row along the X axis, evenly spaced.
place_grid(objects, cols)
Fills a 2D grid row-major: objects are placed left-to-right, wrapping to a new row every cols objects.
| Parameter | Type | Description |
|---|---|---|
objects | list | Objects to arrange. |
cols | int | Number of columns; rows are added as needed. |
place_rectilinear(width1, width2, depth1, depth2)
Arranges objects along the four sides of a rectangular border, leaving the middle open — a ring of seats around a meeting space, or chairs lining the walls.
| Parameter | Type | Description |
|---|---|---|
width1 | list | Top row (runs along X). |
width2 | list | Bottom row (runs along X). |
depth1 | list | Left column (runs along Z). |
depth2 | list | Right column (runs along Z). |
place_arc(objects, towards=None)
Lays objects out in one or more curved rows, like theatre seating. With towards set, the arc curves around that target: rows are measured outward from the target’s boundary, and every object turns to face it — chairs gathered at a fireplace, an audience facing a lectern. Without a target, objects face the group’s own center.
| Parameter | Type | Default | Description |
|---|---|---|---|
objects | list | required | Objects to arrange. |
towards | object | None | If set, the arc wraps this target and each object faces it. |
fireplace = scene.AddAsset("a brick fireplace with a glowing fire")
fireplace.set_location(0, -fireplace.get_aabb()[0, 1], -2.4) # rest on the floor
with scene.GridGroup(sparsity=0.4) as seating:
chair = scene.AddAsset("a dark wooden dining chair")
seating.place_arc(8 * chair, towards=fireplace)
scene.bind(fireplace)
scene.bind(seating)
The rows work like a theatre’s seating bank. The block is wide and shallow — few rows, long ones — with the front row the shortest and each row behind it holding more (the eight chairs above split 3 + 5). Seats across the whole bank share one linear pitch, so they fall on exact lateral columns, with alternate rows offset by half a pitch — a brick pattern that lets sightlines pass between the seats in front. Rows are gently bowed lines rather than circles around the target: each row’s curvature center sits well behind the focal point, so the wings pull toward it without ever wrapping around it, and the bank stands far enough back that no seat turns more than ~40° off the central axis. Every seat still faces the focal point individually. sparsity widens the seat-to-seat gap and the row-to-row gap.
One subtlety worth knowing: the arc’s geometry is computed when the group compiles. If a RoomGroup later repositions the group or the target, the room re-aims every arc object at the target’s final position automatically — positions stay frozen with the group, but the facing always ends up correct.
Parameters: sparsity and randomness
GridGroup(sparsity=..., randomness=...) accepts two layout controls, both in [0, 1], both deterministic under the scene seed.
sparsity — the gap between objects, as a fraction of their size. 0 packs them edge-to-edge; higher values open up space between them:
randomness — jitters the spacing and the facing so the arrangement looks organic instead of mechanical. 0 gives perfectly uniform gaps and exact formation facings; higher values introduce controlled variation. It works at any sparsity (positions wander and each object turns slightly off its row or arc facing, even in a tightly packed grid):
with scene.GridGroup(sparsity=0.5, randomness=0.9) as g:
chair = scene.AddAsset("a dark wooden dining chair")
g.place_grid(9 * chair, cols=3)
Rotational variation here is deliberately tame (up to about ±14° at randomness=1.0, versus ±30° for the anchored groups’ jitter dial, AroundGroup) — a grid should loosen, not dissolve; rows still read as rows.
Compilation
A GridGroup is deterministic: its layout is fully determined by the pattern (plus the seeded dials above), so compilation skips overlap and proportion optimization entirely, and the group freezes immediately.
Next: every arrangement so far still floats in empty space — RoomGroup gives it walls, doors, windows, and a floor plan to land on.