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:

  1. Applies padding (paddingTop, paddingBottom, paddingHorizontal)
  2. Iterates through layers, calling intrinsicSize() for each child
  3. Computes x based on alignItems (left, center, right)
  4. Increments cursorY by height + gap for 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:

  1. Gathers intrinsic sizes of all children
  2. Recursively lays out any nested groups
  3. Computes startX and effective gap based on justifyContent
  4. Outputs each child's final x/y position

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 explicit width/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:


Summary

  • vertical-stack provides automatic top-to-bottom stacking with alignItems for horizontal control
  • horizontal-stack enables left-to-right distribution with justifyContent and alignItems for precise alignment
  • absolute (default) preserves exact x/y coordinates without computation, ideal for pre-designed layouts
  • All three modes are mutually exclusive via the type field in the layout descriptor
  • The implementation resides in sketch/agent-harness/src/layout.js with 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →