Vertical-Stack, Horizontal-Stack, and Absolute Layout Modes in HKUDS/CLI-Anything: A Complete Guide
CLI-Anything's layout engine provides three mutually exclusive positioning strategies—vertical-stack, horizontal-stack, and absolute—that determine how child layers are calculated and rendered inside a container.
The HKUDS/CLI-Anything repository includes a lightweight layout engine in sketch/agent-harness/src/layout.js that computes layer positions based on a layout descriptor. Each descriptor's type field selects one of three layout modes, giving developers declarative control over UI arrangement without manual coordinate calculations—or full control when needed.
Vertical-Stack Layout Mode
The vertical-stack layout places children top-to-bottom inside their container. This mode functions similarly to CSS flexbox with flex-direction: column.
How It Works
In layoutVerticalStack() (located in sketch/agent-harness/src/layout.js), the engine:
- Applies padding (
paddingTop,paddingBottom,paddingHorizontal) - Iterates through
layers, callingintrinsicSize()for each child - Computes
xbased onalignItems(left,center,right) - Increments
cursorYbyheight + gapfor each subsequent child
Configuration Options
| Property | Type | Description |
|---|---|---|
paddingTop / paddingBottom |
number | Vertical padding inside the container |
paddingHorizontal |
number | Left and right padding |
gap |
number | Space between stacked children |
alignItems |
string | Horizontal alignment: left, center, right |
Code Example
const verticalLayout = {
type: 'vertical-stack',
paddingTop: 20,
paddingHorizontal: 10,
gap: 8,
alignItems: 'center',
};
const layers = [
{ type: 'text', value: 'Title', fontSize: 24 },
{ type: 'spacer', height: 12 },
{ type: 'text', value: 'Subtitle', fontSize: 14 },
];
const result = computeLayout(layers, verticalLayout, 300, 400);
// Each layer receives calculated y; x is centered within 300px container
Primary use-case: Stacking rows of UI elements—lists, form fields, vertically arranged icons, or any sequential content flow.
Horizontal-Stack Layout Mode
The horizontal-stack layout arranges children left-to-right, with distribution control via justifyContent and cross-axis alignment via alignItems.
How It Works
The layoutHorizontalStack() implementation:
- Gathers intrinsic sizes of all children
- Recursively lays out any nested groups
- Computes
startXand effective gap based onjustifyContent - Outputs each child's final
x/yposition
Configuration Options
| Property | Type | Description |
|---|---|---|
paddingHorizontal / paddingLeft / paddingRight |
number | Horizontal padding |
gap |
number | Space between children |
justifyContent |
string | Distribution: start, center, end, space-between |
alignItems |
string | Vertical alignment: top, center, bottom |
Code Example
const horizLayout = {
type: 'horizontal-stack',
paddingHorizontal: 16,
gap: 12,
justifyContent: 'space-between',
alignItems: 'bottom',
};
const layers = [
{ type: 'text', value: '←', fontSize: 18 },
{ type: 'text', value: '→', fontSize: 18 },
];
const result = computeLayout(layers, horizLayout, 400, 100);
// Children spread across 400px width with equal distribution
Primary use-case: Toolbar buttons, icon rows, navigation elements, or any set of components sharing a common baseline.
Absolute Layout Mode (Default)
The absolute layout preserves the exact x and y coordinates specified in each layer's definition. No automatic stacking calculations occur.
How It Works
In layoutAbsolute() (source: sketch/agent-harness/src/layout.js), the engine:
- Maps each layer to
{ x: layer.x || 0, y: layer.y || 0, ... } - Resolves intrinsic size via
intrinsicSize()or uses explicitwidth/height - Recursively processes groups without applying additional layout math
Key Characteristics
- No padding, gap, or alignment properties apply
- Each child controls its own position
- Groups are still recursively processed for nested structure
Code Example
const absoluteLayout = { type: 'absolute' };
const layers = [
{ type: 'text', value: 'Fixed', x: 50, y: 30, fontSize: 16 },
{ type: 'text', value: 'Positioned', x: 150, y: 70, fontSize: 16 },
];
const result = computeLayout(layers, absoluteLayout, 500, 200);
// Positions taken verbatim; no stacking computation
Primary use-case: Precise graphic designs where layer positions are pre-defined—hand-crafted Sketch artboards, complex visual compositions, or imported design files.
Quick Comparison: Choosing the Right Layout Mode
| Mode | Positioning | Manual Coordinates | Best For |
|---|---|---|---|
| vertical-stack | Automatic, top-to-bottom | Not required | Lists, forms, vertical content flows |
| horizontal-stack | Automatic, left-to-right | Not required | Toolbars, button groups, icon rows |
| absolute | Manual, exact coordinates | Required | Complex designs, imported artboards, pixel-perfect control |
Core Implementation Files
The layout engine is implemented across three key files in the HKUDS/CLI-Anything repository:
sketch/agent-harness/src/layout.js— ContainslayoutVerticalStack(),layoutHorizontalStack(),layoutAbsolute(), and the maincomputeLayout()entry pointsketch/agent-harness/src/builder.js— Demonstrates layout engine invocation during Sketch file constructionsketch/agent-harness/README.md— JSON spec examples using all three layout modes
Summary
- vertical-stack provides automatic top-to-bottom stacking with
alignItemsfor horizontal control - horizontal-stack enables left-to-right distribution with
justifyContentandalignItemsfor precise alignment - absolute (default) preserves exact
x/ycoordinates without computation, ideal for pre-designed layouts - All three modes are mutually exclusive via the
typefield in the layout descriptor - The implementation resides in
sketch/agent-harness/src/layout.jswith clear separation between strategies
Frequently Asked Questions
Can I nest layout modes inside each other?
Yes. The engine recursively processes groups, so a vertical-stack can contain child groups that use horizontal-stack or absolute internally. Each group's layout is computed independently before being positioned by its parent.
What happens if I omit the type field in a layout descriptor?
The engine defaults to absolute layout mode, preserving any explicit x and y coordinates. This ensures backward compatibility and predictable behavior when no stacking is requested.
Does justifyContent work in vertical-stack mode?
No. justifyContent is specific to horizontal-stack. For vertical distribution control, use paddingTop, paddingBottom, and gap. The property sets are intentionally separated to match their respective directional semantics.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →