Padding and gaps
Two kinds of spacing, deliberately kept apart.
Padding belongs to the canvas
canvas.padding insets the item area from the canvas edges. Item coordinates include it: the first usable pixel is (padding.left, padding.top), and canvasInnerRect(canvas) returns the usable rectangle. Solvers clamp against the padded bounds, projection keeps padding fixed in pixels, and presets tile the inner area.
normalizeCanvas guarantees the canvas is at least one pixel larger than its padding on each axis, so an inner rectangle always exists.
Gaps belong to the operation
A gap is the minimum distance kept between solid neighbors. It is not stored on the layout; it is passed to every call that needs it, so the same layout can be rendered tight or airy without rewriting coordinates:
SolveOptions.gapformoveItem,resizeItem,placeItem, andtransferItem. Snap candidates, push cursors, and collision checks all use it. Default0.ProjectOptions.gapforprojectLayoutwith the chain strategy: gaps of exactly this size between chain members are restored after scaling instead of being scaled with the rest.PresetOptions.gapforapplyPreset, defaulting to the smallest gap already present (inferGap).GridNode.gapfor nested containers, applied when the container's children are projected and solved.GridProviderProps.gapin React, which feeds all of the above.
In nested layouts a gap can also be a lane: a 1px authored gap between rows must not block a free drop at the origin, and the move solver's insert-row / insert-column strategies exist for arriving in such a lane.
Changing the gap of an existing layout
applyGap(layout, gap, options) re-spaces every chain of adjacent items so neighbors sit exactly gap pixels apart. Rows and columns keep their structure and canvas-spanning chains keep filling the canvas. The detector reads the spacing from the layout itself: any distance of up to 64 pixels between neighbors counts as a gap, so an authored 16px dashboard re-spaces without configuration. Larger distances are treated as deliberate white space and left alone; list them in recognizedGaps when they are spacing too.
Enforcing a gap
enforceMinimumGaps(items, bounds, gap) pushes and trims items left-to-right and top-to-bottom so no two neighbors are closer than gap, then clamps to bounds. It is a repair tool for imported layouts, not something you need after a solve; solver results already satisfy the gap for every item they changed.
rectsViolateGap(a, b, gap) is the primitive: true when two rectangles are closer than gap on both axes. rectsOverlap is the same with gap = 0, and touching edges do not count as overlap.