Mental model
Gridla has three ideas. Everything else is a consequence of them.
1. A layout is data
A GridLayout is a canvas and a list of items in canvas-relative pixel coordinates. There are no classes, no hidden state, no ids you did not choose. It serializes to JSON as-is, diffs with any structural comparison, and stores anywhere. data on an item is yours and passes through every function untouched.
2. Solvers are pure functions over that data
moveItem, resizeItem, placeItem, and transferItem take a layout plus an intent and return a SolveResult. The result is always a complete, independent copy. When the request cannot be honored, accepted is false and layout equals the input, so you never hold an invalid layout. The strategy names the rule that produced the result; the solver page lists them in the order they are tried.
Because solvers are pure, "preview during drag" and "commit on release" are the same call. Paint result.layout on every pointer move; keep the last accepted result on release; paint the previous layout to cancel.
3. Rendering is a projection
A layout is authored at one canvas size and rendered at another. projectLayout maps the authored layout onto the rendered size while keeping its structure: rows and columns stay rows and columns, fixed-size items keep their pixels, gaps stay exact, free space scales.
Solvers operate on the rendered layout, because that is what the pointer is over. After a commit, the rendered layout becomes the new source: it is a valid layout in its own right, and projecting it back onto the same size is the identity. This is exactly what GridProvider does; the vanilla quickstart does it by hand in a dozen lines.
What follows from this
- No DOM in the core. Nothing in
gridlareads an element, listens to an event, or schedules a frame. The core runs in Node and in workers. The React adapter is one consumer of it; a vanilla, Vue, or Svelte adapter is the same amount of code. - Nested layouts are the same model, applied recursively. A container's children live in the container's own layout;
flattenLayoutprojects each container into the rectangle its parent gave it. See nesting. - Everything is inspectable. Because results carry the strategy and the full next layout, a debug overlay is a
JSON.stringifyaway.onTraceinSolveOptionsreports every solve for logging. - Constraints are per item, options are per call.
minW,sizeMode, andpolicytravel with the item;gap,snapDistance, andsnapare passed to each solver call. That keeps the layout portable and the behavior tunable.
Next
- Coordinate systems: canvas, inner, root, and viewport coordinates and how to convert between them.
- Solver behavior: the ordered strategy lists.