0027. 0027 — A Stack is the auto layout container, read as a kind
Status: accepted 2026-10-29. Builds on 0008.
Context
Section titled “Context”“Add auto layout” becomes “Wrap with stack”: a Stack is a first-class element on the canvas — inside a frame or free — that lays its children out like flexbox. Two shapes were possible:
- A new
Stackcomponent in motion-core, with its own schema and registry row. - The container that already exists — a rectangle
ShapewithautoLayout— read as a Stack.
Decision
Section titled “Decision”Option 2. A Stack is a clip whose autoLayout is set; layoutKind(clip) in
packages/motion-core/src/motion/layout/stack.ts is the one place that says so, with a row per
direction: horizontal and vertical are Stack, grid is Grid. Labels, Layers icons, the
inspector section and the actions all read that kind; nothing stores it.
- No migration. Every auto layout container ever saved is a Stack the moment it is read.
- One visual model. Fills, per-side strokes, corners, opacity, blend, effects and clip content
are the
Shapeprops the renderer, the inspector sections and codegen already handle. A new component would have had to copy each of them or forward toShape. - Cross-axis stretch is a new
Align.Stretch: children that hug the cross axis take the line (CSSalign-items: stretch); fixed children keep their size. - Wrap with stack always wraps. The selection becomes the children of a new Stack, even when it is one clip that already has children. “Remove stack” unwraps: the children keep the boxes the layout gave them and move to the Stack’s parent, the Stack is deleted.
- Free elements. Wrapping free elements on the canvas merges them into one free element node whose doc holds the Stack; that node follows the Stack’s hugged size after every edit.
Rejected
Section titled “Rejected”- A
kind: 'stack'field written on the clip: a second source of truth next toautoLayout, and every old container would need a write to show as one. - A
Stackcomponent: see above — a fork ofShapefor one extra field.