Arrange

POST /boards/:id/arrange lays out cards that already exist, and any card write accepts a layout to arrange what it adds. The default, justified, fits rows flush on both edges at each picture's true aspect ratio. For placing things yourself, cards carry x, y, w, h, z, rotation, a group_id, and a section_header flag.

Placing cards is half of an API that works. The other half is that what lands looks composed rather than spilled.

Automatic

curl -X POST https://clusters.soleilpictures.com/api/v1/boards/$BOARD/arrange \
  -H "Authorization: Bearer undefined…" \
  -H "Content-Type: application/json" \
  -d '{ "layout": "justified" }'

Omit card_ids to arrange the whole board, or pass a subset to tidy part of it. The same layout works on adding cards and on import, so a batch can land arranged instead of needing a second call.

The layouts

column · grid · justified · masonry · row

justified — the default. Rows of equal height, each picture at its true aspect ratio, flush on both edges. There are no holes in it, which is why it is the right answer for photographs.

┌────────┐┌───┐┌─────────┐
│        ││   ││         │
└────────┘└───┘└─────────┘
┌─────┐┌──────────┐┌─────┐
│     ││          ││     │
└─────┘└──────────┘└─────┘

masonry — columns of equal width, balanced by height, ordered by colour so the board reads as a deliberate palette sweep rather than as arrival order. Leaves a ragged bottom edge, which is the trade for never cropping anything.

grid — one uniform cell for everything, each card centred in its cell. The right answer for mixed kinds — an image beside a PDF beside an audio clip — where a shared cell reads as a clean matrix. For photographs of different shapes it leaves a hole around every portrait, which is what justified fixes.

row and column — a single line, cross-axis centred.

Knobs

FieldMeaning
gapSpace between cards. Default 24.
widthThe width the block is solved against. Omit it and a roughly square block is chosen from the number of items — a canvas has no edges, so there is no container to infer one from.
row_heightTarget row height. justified only.
columnsColumn cap. grid and masonry only.
dry_runCompute everything, write nothing.
card_idsArrange a subset. At most 1000 per call.

Two things worth knowing. justified resizes cards — fitting a row to a width is a resize, and it is the only layout that does. And a named layout arranges the whole batch including cards that carried their own x and y: "lay these out as rows" and "put this one at x=40" are contradictory, and the one you asked for by name wins.

By hand

Every card carries the full geometry:

FieldMeaning
x, yPosition, in canvas units
w, hSize
zStacking. Higher is in front; fractional values are fine
rotationDegrees
group_idMembership of a group
section_headerRender as a full-width heading

z was readable but not writable until now — you could see which of two overlapping cards was on top and had no way to swap them.

Groups

A group is how a board says these belong together: a labelled outline round a set of cards, which then move as one.

curl -X POST https://clusters.soleilpictures.com/api/v1/boards/$BOARD/groups \
  -H "Authorization: Bearer undefined…" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Costume — Act II", "shape": "box" }'

The full set:

EndpointWhat it does
GET /boards/:id/groupsThe groups on a board
POST /boards/:id/groupsCreate one
PATCH /boards/:id/groups/:groupIdRename or restyle it
DELETE /boards/:id/groups/:groupIdUngroup — removes the group, never its cards

Pass the returned id as group_id on any card. shape is box (one rectangle round everything) or hug (following each card). Deleting a group ungroups; it never deletes the cards — there is no undo on an HTTP call, and a group holding forty cards must not be a way to lose forty cards.

Section headings

A card with section_header: true becomes a full-width heading, and if the board is published it renders as an <h2> in the article. Add sub for a line underneath. This is what turns a wall of references into something with a shape somebody else can read.

Frequently asked questions

How do I make a dump of images look like a moodboard?

Pass layout when you import or add them, or call POST /boards/:id/arrange afterwards. The default, justified, gives rows of equal height flush on both edges, with every picture at its real aspect ratio.

Can I see where things would land before moving anything?

Yes. Pass dry_run and the response contains the computed positions with nothing written, so you can compare two layouts before touching a board.

Will arranging move my cards somewhere else on the canvas?

No. The block is re-anchored on its own current top-left, and pushed clear of any cards it is not moving, so tidying part of a board cannot bury the rest.

How do I say that a set of cards belongs together?

Create a group with POST /boards/:id/groups and pass its id as group_id on each card. A group draws a labelled outline round its cards and moves them as one.

Machine-readable: /docs/api/arrange.md · /llms.txt