Centinadocs

Constraints — per-axis resize anchors

How an absolutely-positioned child responds when its parent box resizes. Horizontal: Left · Right · Left and right · Center · Scale; vertical: Top · Bottom · Top and bottom · Center · Scale. Anchors are CSS-native: the choice changes what is stored and emitted — real right: insets, calc(50% ± o) + translate: -50%, percentages — and the browser reflows children on any parent resize, including indirect ones (a fill-width parent resized by its grandparent, a fit box re-hugging, a grid track change). No anchor = Left/Top = the default behavior, unchanged.

Try it. Draw a box, draw a child near its right edge, select the child, click the right pin in the Display section's diagram, select the box, drag its east handle. The child holds its distance to the right edge; hold ⌘ mid-drag and it stops following ("raw resize").

Which nodes can be constrained

Children of an absolute-mode box, and flex/grid children opted out of the flow via the Absolute checkbox. Any node type. Top-level boxes on the canvas have no parent edge to pin to; children participating in a flex or grid flow belong to that flow instead.

SelectionRow treatmentHint
Absolute child of a boxEnabledvalue tooltips
Flow child of flex/gridGreyed (never hidden)"Constraints need absolute position — … Check Absolute above to pin it." (non-box selections are pointed at dragging out of the flow instead)
Top-level box on the canvasGreyed"Constraints need a parent box — a box on the canvas has no edges to pin to."
Mixed contextsGreyedcombined hint

The feature surface

Inspector

A constraints row in the Display section — the outer half of the positioning story the Absolute checkbox starts: two icon-fronted dropdowns (the leading pin glyph tracks the value) beside a pin diagram. Position fields morph to the stored fact — X/Y (left/top/both), R/B (inset), C (center offset), % (scale share) — so the inspector never shows a stale number. A "both" axis reads Auto in W/H (the extent is browser-derived from the two insets); a Scale axis owns its dimension as a percentage and parks the Fit/Fill toggles.

Canvas

Dashed accent pin lines from a selected child to its anchored parent edges. Non-default anchors draw at rest (a deliberate fact deserves standing ink); every axis draws while the constraints row is being edited; a hovered diagram pin previews its would-be line at half strength. Lines stop 3px shy of the child (annotation ink never strikes the subject's outline) and 1px inside the parent's padding edge. Center is an interior tick composing to a +; Scale is both lines at half strength with the share riding the leading line.

While resizing

Resizing the parent needs no extra step — the browser reflows anchored children per their pins. Holding ⌘/Ctrl while resizing is raw resize: the long-standing snap bypass (canvas guides, and the spacing-token size magnet) also suspends constraint solving — children hold their rects live, with a "Constraints off" badge when the box has anchored children. Resizing an anchored child works in its anchored terms: a west drag on a right-anchored child grows it leftward while its right inset holds still.

When anchors clear

Anchors clear automatically when the context that gave them meaning ends: detaching a child to the canvas root, joining a flex/grid flow, toggling Absolute off, wrap/unwrap, reparenting via an agent, copying a node as a clipboard root. Wrapping a selection in a hugging box transfers the selection's anchors to the new box.

Interaction reference

Inspector

AffordanceTriggerEffectHistory / cancel
H/V dropdownpick a modeaxis re-anchors, visually still (the value converts so nothing moves); dims normalize (percent↔fixed)one entry "Constraints"
Edge pin (diagram)clickthat edge becomes the axis anchor; clicking the sole active pin is a no-opone entry
Edge pinshift-clickcombines with the opposite pin into Left-and-right / Top-and-bottom; shift-clicking a lit member removes itone entry
Center +clickH and V center, one batched writeone entry
Scaledropdown onlyposition and size become percentages (diagram reflects it as a dashed tie — no fake pin affordance)one entry
R/B/C/% fieldtype/scrubwrites the stored value directly"Move", scrub-coalesced
W/H on a Scale axistype/scrubwrites the percent share"Resize", scrub-coalesced

Canvas / resize

AffordanceTriggerEffectHistory / cancel
Parent resizedrag any handlebrowser reflows anchored children per their pinsone coalesced step; Esc rolls back box + children
⌘ held during parent resizelive, per framechildren hold their rects; release re-solves against the current sizesame step; Esc rolls back everything
Shift+corner scaleduring resizesubtree scales uniformly; anchors scale their px values, percent shares are invariantone step
Move / nudge an anchored childdrag / arrowsthe stored field moves (inset shrinks, offset shifts, percentages convert through the parent size)one coalesced step
Reparent into an absolute boxdrop / layers dragmodes preserved, values recomputed in the new parentone step

Agents (MCP)

update_styles accepts layout.constraints: {h?, v?}{mode, inset?|offset?|pct?} per axis, null clears; omit the value to anchor at the current spot (keep-still conversion), pass it to place the anchor. x/y on an anchored axis convert to the anchored field automatically; percent dims validate against a Scale axis; move_nodes converts positions the same way and strips anchors on reparent. Reads ride the whole layout object in get_node_info.

Known limits (by design)

  • Rotated children convert through their bounding-box measurements — the approximation every pin path accepts.
  • Duplicating a scale-axis child skips the usual +10px paste offset on that axis (percent geometry has no parent size at clone time); the copy lands atop the source on that axis.
  • Wrap/unwrap strip anchors from children (hug-wrap transfers them to the box); preserving them through union-wrap is a possible later polish.
  • Website import parks right/bottom/percent geometry in Other styles (raw CSS) rather than mapping it onto constraints — mapping it is the natural fidelity follow-up.