Skip to content

Layout ​

Divides a region into a grid of cells with even gaps, from numbers you can animate.

Category: Utility Menu path: Utility > Layout

Ports ​

PortTypeDirectionDescription
cells_inpointsinputOptional. Another Layout's cells. Wire it and this grid divides ONE of those cells — Split Cell picks which — and passes every other cell through, so its outputs hold the whole layout so far. Leave it unwired and the grid divides the composition
cellspointsoutputOne point per cell, at the cell's centre, carrying cellSize (the cell's width and height as a Vec2). DrawInstances and CloneToPoints with Cell Fit read that column as each instance’s box
cellRectsshapeoutputThe same cells as rectangles, in the same order, each path carrying cellIndex. Draw them, round them, measure them

cells and cellRects are the same set of cells in two forms, not two different results. Use cells (points, each carrying cellSize) to place content into — one image, shape or clone per cell — or to hand to another Layout. Use cellRects (a shape, one rectangle per cell) to draw the boxes.

Parameters ​

ParamTypeDefaultDescription
columnstrack list1How the width divides. A bare number is a share; px pins; driven grows a port
rowstrack list1How the height divides
guttervec216, 16The gap between columns, and between rows. Linked by default. Drivable via gutter_in (E)
gutterModeenumCollapseGutters — what the gaps do while a track collapses. Collapse: a track takes its gap with it as it leaves, so an expand-to-full lands on the frame. Fixed: gaps never move (CSS Grid behaviour)
cellscalar0Split Cell — which incoming cell to divide, counting from 0 in reading order. Only shown once cells_in is connected
sizeModeenumCompWhat the region is: Comp / Fixed / Fit Tracks. Hidden when cells_in is wired — the region is then the cell being split
sizevec2comp sizeThe region, in Fixed mode only
paddingvec20, 0Inset from the region's edges, applied to both ends of each axis, before any track. Drivable via padding_in (E)

Expose Channels ​

Press E on the node and it grows two input ports:

PortTypeOverrides
gutter_invec2gutter
padding_invec2padding

Wire a Constant, an Oscillate, a Measure size, or any vec2 in and that value beats the param while the wire is connected — the gutter can breathe with an oscillator, or the padding can follow a measurement. Turning E off removes the ports and whatever was wired to them.

Track sizes are driven a different way: set a track's unit to driven and the node grows a port for that track alone (Col 2 Size, Row 1 Size, …). The two mechanisms are independent — E on with a driven column shows both sets of ports. See Driven tracks below.

How It Works ​

A new Layout starts with one column and one row: one cell filling its region. Add columns and rows to subdivide it. Existing saved layouts keep their track lists.

Shares and pinned tracks ​

Columns and rows are each edited by a track editor: a proportion bar showing the tracks at their real relative sizes with the gutter to scale, and a row of chips beneath it, one per track.

A chip holding a bare number is a share — a relative weight, with no unit, because a ratio has none. 1 2 1 is three columns where the middle one is twice as wide as its neighbours. Shares divide whatever space is left after everything fixed comes off.

A px suffix pins a track to that many pixels and draws its segment dashed. 240px 1 1 gives you a 240-pixel sidebar and two equal columns filling the rest: pinned tracks take their pixels off the top, and the shares split what remains. You can mix them freely — 1 240px 1 is a fixed centre column between two equal flanks.

Chips behave like any other numeric field: click the number to type one, or drag it to scrub. Clicking the unit cycles that track through share → pixels → driven; pinning a track seeds it with the width it already had, so nothing jumps. + appends a share track and − removes one — the selected chip, or the last if you have not picked one. An axis always keeps at least one track, so − greys out at the final one. A chip's right-click menu does the same removal, and is also where Edit as Text lives.

Dragging a divider ​

Drag the divider between two segments and those two tracks trade space. Nothing else in the grid moves.

That is the only rule that can make that promise. Shares are relative, so every track's width depends on the running total — growing one track by "pushing the rest along" would resize tracks you never touched. Trading between the pair keeps their total constant, which keeps everyone else exactly where they were, and keeps the drag down to a two-value edit — which matters when the drag is also creating a keyframe.

Two special cases:

  • A divider next to a pinned track edits that track's pixel value instead. The share beside it absorbs the difference on its own.
  • A divider next to a driven track does not drag at all. Its size comes from a port, so there is nothing here to trade.

The whole drag is one undo step.

Driven tracks ​

Cycle a chip's unit to driven and that track takes its size from an input port instead of its stored number. The node grows the port for that track alone — Col 2 Size for the second column, Row 1 Size for the first row — and the chip and its bar segment take the app's driven colour.

Wire a Measure node's width into it and the column fits its content.

Adding or removing a track on a keyframed list applies to every keyframe, not just the one at the playhead. A new track is inserted at size 0 everywhere else, which changes nothing about how those frames render — a zero track has no area and its gutters collapse — but it keeps the track counts equal, which is what lets the list interpolate at all. Without it the counts differ and the layout hard-swaps halfway between the two keyframes. The practical effect is that a track you add mid-animation grows in from nothing rather than appearing at full size.

Change the track back to a share or pixels, or remove it, and the port goes with it — along with whatever was wired to it, in the same undo step. Removing a track ahead of a driven one renumbers the ports after it and carries their connections along, so deleting column 1 never silently unwires column 3.

A driven track with nothing wired falls back to its stored number, read as pixels.

Typing a whole list ​

Right-click the track block and pick Edit as Text to type the whole axis on one line: 1 2 1, or 1 240px 1. It is the fastest way to set up a grid, or to paste one. Invalid text reverts and writes nothing.

The region ​

sizeMode decides what is being divided.

  • Comp — the composition frame. The grid fills the screen.
  • Fixed — the size you type. Use this to lay out a panel smaller than the frame, then move it with a Transform2D.
  • Fit Tracks — the opposite direction: the region is whatever the tracks add up to, plus the gutters and the padding. Only available when every track is pinned, because a share has nothing to be a share of.

The region is always centred on the origin, so a Transform2D downstream moves the whole grid as a unit.

With another Layout's cells wired in, none of this applies: the region is the cell being split, wherever it is. sizeMode and size disappear from the panel.

Gutters: Collapse or Fixed ​

Shares are relative, so growing one track never reaches full width. A column at share 9 against two at share 1 still only takes nine elevenths of the space being shared — and 99 against two 1s still only takes 99 parts in 101. You can get close, but you never arrive.

Reaching full width means animating the others to zero. That is also the honest reading of what is happening on screen: the other columns are leaving. The Gutters setting decides what their gaps do.

Collapse (the default) — a track takes its gap with it. Three equal columns in a 1200px region with a 24px gutter are 384px each; animate the outer two to zero and the middle one ends up exactly 1200px — not 1152, one gutter short on each side with 48px left to pop on the final frame. The move is smooth and it lands.

The same rule holds anywhere in the grid. A middle column leaving takes exactly one gap with it, so its two neighbours close up with a single gutter between them — the same layout you would get by deleting the column. And a track only counts as leaving when it is small next to its siblings: a nested Layout that splits a 100px cell into four 7px rows with a 24px gutter is a small grid, not four tracks on their way out, and it draws the 24px gutter you typed. The hand-off is eased, so the survivors' edges swell into the last of the move rather than stepping.

Fixed — gaps never move. A track at zero still emits no cells, but the gutters on either side of it stay where they were; the survivors stop one gutter short. This is CSS Grid's behaviour, and the right one when a small track is a design decision rather than a departure — a 4px pinned column drawn as a divider rule, say, which Collapse would otherwise read as a track that is nearly gone and narrow the gaps beside it.

Layouts that are not an even grid ​

Designs like this are common and they are not grids — the two columns divide at different heights:

┌─────────┬─────────┐
│         │         │
│         │    B1   │
│   A1    ├─────────┤
│         │    B2   │
│         ├─────────┤
├─────────┤    B3   │
│   A2    │         │
└─────────┴─────────┘

Split, then split again. A Layout with another Layout's cells wired in divides one of those cells and passes the rest through, so a chain of Layouts reads as the design does out loud:

  1. Layout A — columns 1 1, rows 1. Two halves.
  2. Layout B — wire A.cells → B.cells_in, Split Cell 0, rows 87 13. The left half is now two cells; the right half passes through.
  3. Layout C — wire B.cells → C.cells_in, Split Cell 2, rows 65 20 15. The right half is now three.
  4. C.cellRects → DrawShape. That is the whole layout — five cells.

Those row numbers are the design: 87/13 and 65/20/15 are the proportions you would read off a reference. Drag a divider in A and everything downstream follows, because A stays the single source of where the halves are. Nest as deep as you like — every Layout's cells is the whole layout so far, and the last one holds all of it.

Counting Split Cell. Cells are numbered in reading order — top row left to right, then the next row — through the whole stream the node receives. After B splits the left half into two, the right half is cell 2, not 1. Select the upstream Layout and its cellRects outline shows you the cells; count them the way you would read them.

A Split Cell past the end, or points that are not a Layout's cells (a Grid, say — they carry no cell size), splits nothing: the input passes through unchanged and the status console says why.

Independent branches ​

Use Cell's Selected to feed just one cell into a child Layout. With Split Cell 0, the child emits only that cell's pieces. Keep Cell's Remaining stream for other branches, then append the finished branches with MergePoints. See Cell's A/B/C/D example for two independent splits and exactly ten final cells. This does not change serial Layout splitting: a child receiving the whole stream still passes unsplit cells through.

Cell order and identity ​

Cells come out in reading order: the whole first row left to right, then the second row, and so on — and, when Layouts are nested, the split cell's pieces sit where the cell was. cellRects uses the same order, and each rectangle carries its position in that order as cellIndex.

Every cell also carries a stable identity that is not its position. A top-level cell's identity is its row and column, so adding a fourth column leaves the first three theirs. A cell made by splitting is keyed off the cell it came from, so adding a split elsewhere in the chain, or a row to this one, leaves every existing piece its identity too. Anything downstream that varies per cell — a random colour, a DrawInstances palette pick, a time offset — does not re-roll just because the layout changed around it.

Generic MergePoints assigns new sequential ids when combining branches. Changing an earlier branch’s count may therefore change later ids; it also preserves slot order, not automatic reading order. The stable-identity guarantee above is for Layout/Cell streams before that merge.

What a split cell passes on ​

A cell made by splitting inherits every attribute the cell it came from carried — a color or a shapeIndex written on the half you split, with PointAttributes between the two Layouts, reaches every piece. The one thing this grid always writes itself is cellSize: the pieces are being placed afresh here.

Usage Examples ​

Basic: draw the grid ​

Layout → DrawShape. Set Columns to 1 1 1 and Rows to 1 1 for a 3×2 grid, then wire cellRects into DrawShape's shape input. Add RoundCorners between them for a bento look — Layout deliberately has no corner radius of its own, because RoundCorners already does that job and two places to set the same number drift apart.

Basic: a sidebar and a content area ​

Set columns to 280px 1 and rows to 1. The sidebar stays 280px at any comp size; the content area takes the rest. Animate the 280px to 0px and the sidebar slides away, gutter and all.

Creative: the split-screen that resizes ​

Two columns, 1 1. Keyframe them to 3 1 and the divider slides across while both halves resize — one move, two numbers.

Basic: the bento — media in every cell ​

Layout.cells → DrawInstances.points_in, with your images, videos or whole effect chains connected into DrawInstances' palette input, and fitMode set to Fill. Every cell fits its own box: a wide cell shows a wide crop and a tall one a tall crop, each cropped against its own aspect rather than one shared cell size. Set a cornerRadius on DrawInstances for rounded tiles, and selectionMode = Point Index if you want cell k to take source k rather than cycling.

Because the cells re-emit at every frame, animating the track sizes re-crops the content as the tiles resize — the whole bento move in one keyframe pair.

Creative: shatter an image into tiles ​

Fill the cells with one image, then animate the gutter from 0 upwards. The image breaks apart into tiles that drift away from each other. At gutter 0 it is seamless; there is no other way to get this in the app.

Basic: a bento with one feature tile ​

Two Layouts. A: columns 2 1, rows 1 — a wide left cell and a narrow right one. B: A.cells → B.cells_in, Split Cell 1, rows 1 1 — the narrow column becomes two stacked tiles. B.cells → DrawInstances and you have a feature tile beside two small ones, every tile fitting its own box.

To put the feature on the right instead, change A's columns to 1 2 and B's Split Cell to 0. Nothing downstream re-rolls: each piece keeps its identity.

Creative: text that reflows with its cell ​

B.cells → Cell (Split Cell 0, the feature tile) then Cell.size → Text.boxSize_in and Cell.center → Transform2D.position_in. Keyframe A's columns from 2 1 to 1 2 and the headline rewraps as its tile narrows — see Cell.

Creative: expand one cell to full frame ​

Three columns, 1 1 1. Keyframe the outer two to 0 — the middle one grows to fill the entire region, landing exactly on the frame. This is the move Gutters: Collapse exists for.

The two collapsing columns stop producing cells the moment they reach zero. Their contents leave with them: there is no box left for a consumer to fill, so nothing is drawn where they were. Cells are only numbered by cellIndex, which closes up when they go — but each surviving cell keeps its identity, so a Draw Instances palette set to Random does not reshuffle as a neighbour collapses.

Tips ​

  • Keying a track list keys the whole list. It is one parameter with one keyframe diamond — the one beside the Columns or Rows label, not one per chip — exactly like a gradient or a curve. You cannot key one column alone, but you rarely need to: the columns you are not animating just hold the same value across both keys. Once the list has a keyframe, editing a chip, dragging a divider or editing the list as text updates or adds a keyframe at the playhead, even with Auto-Key off, just like other Properties fields. For example, key 1 5 1, move the playhead, then change the second chip to 1 to animate to 1 1 1.
  • Changing the track count pops rather than tweens. Two lists of different lengths hold rather than interpolate, because a cell that does not exist at one end has nothing to interpolate to. Animate a track to zero instead of deleting it.
  • Padding is per side. padding of 40 takes 40px off each end of the axis, so an 800px region has 720px of tracks.
  • Negative numbers clamp to zero. They are not an error, they just do nothing.
  • A zero track emits no cells. A column or row at zero has no area, so its cells are not written at all rather than written flat. That is what makes animating a track to zero remove its contents from the frame.
  • The track editor draws full gutters. Its proportion bar shows the tracks and the gutter you typed; it does not follow the Collapse fade, which only exists between keyframes in the render.
  • Fit Tracks is greyed out while any track is a share. Pin them all, or pick another mode.
  • A driven gutter does not redraw the proportion bar. The track editor scales its gaps from the gutter param; when gutter_in is wired the render uses the wired value and the bar keeps showing the param's. The Gutter row itself shows the driven indicator.

Limits in this version ​

  • No merged cells inside one grid. A cell that spans two columns is two Layouts: split the frame into the rows you want, then split the cells that need columns. That reads as the design does, and it tweens — a track animates; a span would pop.
  • Nothing published. Driving another layer's Transform2D from a cell is not wired up yet; Cell does it within a layer.
  • A driven track's port is not read yet. The port exists, and wiring it is saved with the project, but the engine still resolves the track to its stored number. The value arrives with the next release.
  • Cell — extract Selected/Remaining cells, or read one cell as values: size a text box or a Rectangle, park something on its centre
  • DrawShape — draw the cellRects output
  • RoundCorners — round the rectangles; Layout has no radius of its own
  • DrawInstances — put images or video into the cells; each one fits its own cell's box
  • CloneToPoints — stamp a shape into every cell using cells
  • Grid — an evenly spaced point distribution, when the cells are all the same size and you do not need gutters
  • Measure — size something, then pin a track to it, or wire its size into padding_in
  • Oscillate — a breathing gutter, wired into gutter_in
  • Transform2D — move the whole grid