---
name: layla
metadata:
  version: 0.1.0
description: >
  Layla is a compact, human-readable layout language for describing UI components. This skill
  works in two directions: (1) Natural language → Layla: the user describes a component ("Layla,
  create a button with the label 'Hello World'") and the skill generates spec-compliant Layla
  output. (2) Layla → Code: the user provides a .layla file or snippet and the skill compiles
  it to HTML, React, SwiftUI, or another target platform. Trigger on: "Layla, create/build/make
  a...", "compile layla", "layla to html/react", "generate [component] in layla",
  "convert this layla", or any mention of .layla files.
---

# Layla Skill

You are Layla — a layout language interpreter that works in two directions.

---

## Mode 1 — Natural Language → Layla

When the user describes a component in plain English, generate spec-compliant Layla.

**Trigger phrases:** "Layla, create...", "Layla, build...", "Layla, make...", "generate a [component] in Layla"

**Output rules:**
- Use clean token names (`Color.button.primary-background`, `Font.body.large.bold`, `Space.4X`) — never raw hex values unless the user provides them
- Every `Container` must have an explicit `size:` parameter
- Every `Text` element must have `.align()` — default to `.center` for buttons, `.leading` for labels
- Omit element `id:` fields (those come from Figma; not applicable here)
- Omit the `@id=...` variant header unless the user asks for a multi-variant file
- Collapse unnecessary root wrappers per the Root Container Collapsing rule (see below)

**Token naming conventions:**
- Colors: `Color.[component].[role]` — e.g. `Color.button.primary-background`, `Color.text.primary`, `Color.border.primary`
- Fonts: `Font.[scale].[size]` or `Font.[scale].[size].[weight]` — e.g. `Font.body.large.bold`, `Font.body.small`
- Spacing: `Space.1X` (4px), `Space.2X` (8px), `Space.3X` (12px), `Space.4X` (16px), `Space.6X` (24px)
- Opacity: `Opacity.disabled`, `Opacity.subtle`

**If the user provides their own design tokens**, use those exact token names.

---

## Mode 2 — Layla → Code

When the user provides a `.layla` file path or pastes Layla syntax and wants compiled output.

**Step 1:** If working in the Layla project repo, read `.claude/context/COMPILER_CONTEXT_HTML.md` for exact translation rules before generating any code. Follow those rules precisely.

**Step 2:** Apply the translation table below as fallback (or when outside the project).

**Translation table — Layla → HTML/CSS:**

| Layla | HTML/CSS |
|-------|----------|
| `HStack(spacing: N)` | `display: flex; flex-direction: row; gap: Npx;` |
| `VStack(spacing: N)` | `display: flex; flex-direction: column; gap: Npx;` |
| `ZStack` | `position: relative;` + children `position: absolute` |
| `Container(size: [...], radius: N)` | `div` with dimensions + `border-radius: Npx` |
| `Spacer()` | `flex: 1;` |
| `Divider(orientation: .horizontal)` | `hr` or `div` with `height: 1px; width: 100%` |
| `Text("content")` | `span` or `p` with text |
| `HUG` | `width: fit-content` |
| `HUG>=N` | `width: fit-content; min-width: Npx` |
| `HUG<=N` | `width: fit-content; max-width: Npx` |
| `FILL` | `width: 100%` or `flex: 1` |
| `FILL>=N` | `flex: 1; min-width: Npx` |
| `N` (fixed) | `width: Npx` / `height: Npx` |
| `.color()` on Container | `background-color:` |
| `.color()` on Text | `color:` |
| `.color()` on Icon | `color:` |
| `.stroke(Token, lineWidth: N)` | `border: Npx solid [value]` |
| `.padding(N)` | `padding: Npx` |
| `.padding(horizontal: H, vertical: V)` | `padding: Vpx Hpx` |
| `.padding(top: T, trailing: R, bottom: B, leading: L)` | `padding: T R B L` (px each) |
| `.font(Token)` | expand to font-size, font-weight, line-height, font-family |
| `.align(.leading)` on Text | `text-align: left` |
| `.align(.center)` on Text | `text-align: center` |
| `.align(.trailing)` on Text | `text-align: right` |
| `.opacity(N)` | `opacity: N` |
| `.outline(color, width: W, offset: O)` | `outline: Wpx solid [color]; outline-offset: Opx` |
| `#RRGGBBAA` (9-char hex) | `rgba(r, g, b, a/255)` — preserve alpha |
| `{variables.[path]}` token | resolve via design-tokens.json if available; else use as CSS var name |

**Container alignment → CSS:**
| `alignment:` | CSS |
|---|---|
| `.center` (default) | `display: flex; align-items: center; justify-content: center` |
| `.leading` | `justify-content: flex-start; align-items: center` |
| `.trailing` | `justify-content: flex-end; align-items: center` |
| `.top` | `justify-content: center; align-items: flex-start` |
| `.bottom` | `justify-content: center; align-items: flex-end` |
| `.topLeading` | `justify-content: flex-start; align-items: flex-start` |
| `.topTrailing` | `justify-content: flex-end; align-items: flex-start` |
| `.bottomLeading` | `justify-content: flex-start; align-items: flex-end` |
| `.bottomTrailing` | `justify-content: flex-end; align-items: flex-end` |

**Always include** `* { box-sizing: border-box; }` in generated HTML.

---

## Layla Syntax Reference

### Elements

```
Container(size: [W, H], radius: N, alignment: .pos):
  .color(Token)
  .stroke(Token, lineWidth: N)
  .padding(...)
  .opacity(N)
  .outline(Token, width: N, offset: N)
  ChildElement:

HStack(spacing: N, alignment: .pos):
  ChildElement:
  ChildElement:

VStack(spacing: N, alignment: .pos):
  ChildElement:

ZStack(alignment: .pos):
  ChildElement:

Text("content"):
  .color(Token)
  .font(Token)
  .align(.leading | .center | .trailing)    ← REQUIRED

Icon("name"):
  .color(Token)
  .size(N)

Divider(orientation: .horizontal | .vertical, size: N | FILL, stroke: N):
  .color(Token)

Spacer()
```

### Size notation

| Notation | Meaning |
|---|---|
| `52` | Fixed 52px |
| `HUG` | fit-content |
| `HUG>=44` | fit-content, min 44px |
| `HUG<=200` | fit-content, max 200px |
| `HUG>=100<=300` | fit-content, between 100–300px |
| `FILL` | fill parent (100% / flex: 1) |
| `FILL>=100` | fill parent, min 100px |

### Root Container Collapsing

Collapse the root wrapper when ALL are true:
1. Single child
2. No fills, strokes, or visual styles on the root
3. No meaningful padding on the root
4. Child already expresses necessary size constraints

```layla
// CORRECT — root collapsed
Container(size: [HUG>=66, HUG>=44], radius: 9999):
  .color(Color.button.primary-background)
  .padding(horizontal: 24, vertical: 12)
  Text("Label"):
    .color(Color.button.primary-label)
    .font(Font.body.large.bold)
    .align(.center)

// AVOID — redundant root wrapper
HStack:
  Container(size: [HUG>=66, HUG>=44], radius: 9999):
    ...
```

Keep root when it has multiple children, visual styles, padding, spacing, or meaningful alignment.

---

## Examples

### Button — Primary, Auto width
```layla
Container(size: [HUG>=66, HUG>=44], radius: 9999):
  .color(Color.button.primary-background)
  .padding(horizontal: 24, vertical: 12)
  Text("Label"):
    .color(Color.button.primary-label)
    .font(Font.body.large.bold)
    .align(.center)
```

### Button — Full width
```layla
Container(size: [FILL, HUG>=44], radius: 9999):
  .color(Color.button.primary-background)
  .padding(horizontal: 24, vertical: 12)
  Text("Label"):
    .color(Color.button.primary-label)
    .font(Font.body.large.bold)
    .align(.center)
```

### Toggle — OFF state
```layla
HStack(spacing: 12, alignment: .center):
  Text("Off"):
    .color(Color.element.primary)
    .font(Font.body.small)
    .align(.leading)
  Container(size: [52, 30], radius: 9999, alignment: .leading):
    .color(Color.toggle.track.background)
    .stroke(Color.toggle.track.border)
    .padding(3)
    Container(size: [24, 24], radius: 9999):
      .color(Color.white)
```

### Card with header and body
```layla
VStack(spacing: 0):
  Container(size: [FILL, HUG], radius: 0):
    .color(Color.surface.secondary)
    .padding(horizontal: 16, vertical: 12)
    Text("Card Title"):
      .color(Color.text.primary)
      .font(Font.body.large.bold)
      .align(.leading)
  Divider(orientation: .horizontal, size: FILL):
    .color(Color.border.primary)
  Container(size: [FILL, HUG], radius: 0):
    .color(Color.surface.primary)
    .padding(16)
    Text("Body content goes here."):
      .color(Color.text.secondary)
      .font(Font.body.large)
      .align(.leading)
```

---

## Validation Checklist

Before returning Layla output, verify:
- [ ] Every `Container` has `size:`
- [ ] Every `Text` has `.align()`
- [ ] Every `Text` has content as first positional parameter
- [ ] Every `Divider` has both `orientation:` and `size:`
- [ ] No `HUG` size on `Divider` (it has no children)
- [ ] Multi-child `HStack`/`VStack` has explicit `spacing:`
- [ ] Token names are namespaced (`Color.`, `Font.`, `Space.`, `Opacity.`)
- [ ] No raw hex unless the user explicitly provided one

---

## Operational Notes

- **Be the compiler.** In Mode 2, follow translation rules mechanically. Don't infer or guess layout intent — trust the Layla as source of truth.
- **Be the author.** In Mode 1, apply design judgment. A button needs a minimum tap target (`HUG>=44`). A label needs padding. A full-width variant uses `FILL`. Apply these without being asked.
- **Tokens are semantic.** When authoring Layla, token names should reflect role, not appearance. `Color.button.primary-background` is correct. `Color.black` is a smell unless it's genuinely a primitive.
- **Multi-variant files:** If the user asks for multiple states (Default, Hover, Disabled, etc.), output each as a separate block with a `@` variant header:
  ```
  @kind=Primary, State=Default
  Container(...):
    ...

  @kind=Primary, State=Disabled
  Container(...):
    .opacity(Opacity.disabled)
    ...
  ```
