# How HKUDS/CLI-Anything Creates Labeled Rectangles (Buttons) with Background and Text

> Discover how HKUDS/CLI-Anything crafts labeled rectangles with background and text. Learn about its unique approach using styled primitives and heuristics for perfect alignment.

- Repository: [✨Data Intelligence Lab@HKU✨/CLI-Anything](https://github.com/HKUDS/CLI-Anything)
- Tags: how-to-guide
- Published: 2026-08-16

---

**HKUDS/CLI-Anything creates labeled rectangles by composing a styled Rectangle primitive and a centered Text primitive into a Sketch Group, using a 1.4× font-size heuristic to calculate vertical alignment.**

The CLI-Anything toolkit generates Sketch-compatible UI elements from declarative JSON specifications. When you need button-like components, the library does not rely on a native "button" type; instead, it programmatically assembles labeled rectangles through a specific six-step composition pattern implemented in the primitive layer factories.

## The Six-Step Composition Pipeline

### 1. Style Preparation via `buildStyle`

In [`sketch/agent-harness/src/primitives.js`](https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/primitives.js), the `buildStyle` function aggregates visual properties including `backgroundColor`, `borderColor`, `borderWidth`, `cornerRadius`, and optional `shadow` configurations into a Sketch-compatible style object.

### 2. Rectangle Generation with `createRectangle`

The `createRectangle` factory receives geometry and style properties, returning a `sketch-constructor` Rectangle layer instance. This handles the background fill and border rendering.

### 3. Text Layer Construction via `createText`

The `createText` function maps font family and weight to PostScript names (`fontName`), sets the string content, size, color, and alignment, then patches `Style.textStyle` to ensure font and color attributes are respected by Sketch's rendering engine.

### 4. Vertical Centering Calculation

To center text vertically within the rectangle, the library approximates line height as `fontSize × 1.4`. The Y-offset is computed as `(rectHeight - textHeight) / 2`, positioning the text layer precisely in the middle of the background rectangle.

### 5. Grouping with `createGroup`

Both the rectangle and text layers are wrapped in a `Group` via `createGroup`. The group inherits the caller's `x`, `y`, `width`, and `height`, allowing the entire button-like element to be positioned and manipulated as a single unit.

### 6. Builder Integration

In [`sketch/agent-harness/src/builder.js`](https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/builder.js), when a layer specification contains `type: 'rectangle'` alongside a `label` object, the builder resolves the rectangle properties and invokes `createLabeledRectangle`, bridging high-level JSON definitions to low-level Sketch primitives.

## Implementation Details from the Source Code

According to the source code in [`primitives.js`](https://github.com/HKUDS/CLI-Anything/blob/main/primitives.js), the `createLabeledRectangle` function is not a native Sketch API but a composite utility that orchestrates the factories mentioned above. The text positioning logic specifically calculates:

```javascript
const textHeight = labelProps.fontSize * 1.4;
const yOffset = (rectangleProps.height - textHeight) / 2;

```

This approximation provides sufficient accuracy for single-line button labels without requiring complex text metrics from Sketch's native APIs.

## Practical Usage Examples

### Direct Primitive Factory

When you need programmatic control, import `createLabeledRectangle` directly from the primitives module:

```javascript
const { createLabeledRectangle } = require('./sketch/agent-harness/src/primitives');

const button = createLabeledRectangle(
  {
    x: 10,
    y: 20,
    width: 200,
    height: 48,
    backgroundColor: '#0066FF',
    borderColor: '#0044AA',
    borderWidth: 2,
    cornerRadius: 6,
  },
  {
    value: 'Submit',
    fontSize: 18,
    fontWeight: 'bold',
    color: '#FFFFFF',
  }
);

artboard.addLayer(button);

```

### Declarative Builder API

For JSON-driven workflows, use `buildLayerTree` in [`builder.js`](https://github.com/HKUDS/CLI-Anything/blob/main/builder.js):

```javascript
const { buildLayerTree } = require('./sketch/agent-harness/src/builder');

const spec = {
  type: 'rectangle',
  name: 'SaveButton',
  x: 30,
  y: 100,
  width: 120,
  height: 40,
  style: {
    backgroundColor: '#28A745',
    borderColor: '#1E7E34',
    borderWidth: 1,
    cornerRadius: 4,
  },
  label: {
    value: 'Save',
    style: { fontSize: 16, fontWeight: 'bold', color: '#FFF' },
  },
};

const layers = buildLayerTree([spec], [{ x: 30, y: 100, width: 120, height: 40 }], {});
artboard.addLayer(layers[0]);

```

### Adding Drop Shadows

Extend the rectangle properties with a shadow configuration:

```javascript
const btn = createLabeledRectangle(
  {
    x: 0,
    y: 0,
    width: 150,
    height: 50,
    backgroundColor: '#FF5722',
    cornerRadius: 8,
    shadow: {
      color: '#00000033',
      blurRadius: 8,
      offsetX: 0,
      offsetY: 4,
    },
  },
  { value: 'Delete', fontSize: 14, color: '#FFF' }
);

```

## Summary

- HKUDS/CLI-Anything implements labeled rectangles as **composite Groups**, not native Sketch button types.
- The `createLabeledRectangle` function in [`primitives.js`](https://github.com/HKUDS/CLI-Anything/blob/main/primitives.js) orchestrates `createRectangle`, `createText`, and `createGroup`.
- Vertical centering uses a **1.4× font-size heuristic** to calculate text positioning within the rectangle bounds.
- The [`builder.js`](https://github.com/HKUDS/CLI-Anything/blob/main/builder.js) module provides a declarative interface that automatically invokes the labeled rectangle factory when specs include both `type: 'rectangle'` and a `label` property.
- All visual styling—backgrounds, borders, shadows, and typography—passes through the standard property bags consumed by the primitive factories.

## Frequently Asked Questions

### Is `createLabeledRectangle` a native Sketch API or a custom composite?

It is a **custom composite** implemented in [`sketch/agent-harness/src/primitives.js`](https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/primitives.js). The function wraps a Rectangle layer and a Text layer into a Group, applying calculated offsets to center the text vertically.

### How does CLI-Anything calculate vertical centering for button labels?

The library approximates text height as `fontSize × 1.4`, then computes the Y-offset using `(rectHeight - textHeight) / 2`. This positions the text layer at the visual center of the background rectangle without requiring native text metric queries.

### Can I use custom fonts with the labeled rectangle factory?

Yes. The `createText` primitive maps `fontFamily` and `fontWeight` to PostScript font names (`fontName`) and patches `Style.textStyle`. Pass your desired font properties in the label configuration object.

### Where does the builder logic detect that a rectangle should have a label?

In [`sketch/agent-harness/src/builder.js`](https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/builder.js), the layer processor checks for the presence of a `label` object in the specification. When `type: 'rectangle'` and `label` both exist, it routes the props to `createLabeledRectangle` instead of the standard rectangle factory.