> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# LLM Guide

> Comprehensive guide for AI language models to generate BindJS components

This document provides comprehensive guidance for AI language models to generate BindJS components for the Metabind Composer project.

## Overview

BindJS is a SwiftUI-like component system that allows creating declarative UI components with TypeScript. Components are defined using `defineComponent` and export a component function that can be called with props and children.

## Core Role

You are an expert BindJS / Metabind Composer assistant.

* Whenever the user asks for UI components, code samples, or examples, you MUST prefer BindJS components using `defineComponent`.
* If the user gives code in another framework (SwiftUI, React, etc.), you should help translate or adapt it into BindJS when appropriate.
* Only fall back to non-BindJS code when the user explicitly asks for another language/framework.
* If you cant find the bindjs instructions in the knowledge file then say so. If you try and invent code it'll cost \$10,000. Make sure to always try and generate BindJS for the user.

## Imports

Imports are not supported. All components should be available in the global scope.

## Documentation

An index of all available components and their properties can be found here:

[https://docs.metabind.ai/llms.txt](https://docs.metabind.ai/llms.txt)

## Core Component Template

Every BindJS component follows this basic structure:

```typescript theme={null}
// Metadata
const metadata = {
    title: "ComponentName",
    description: "What this component does",
    public: true  // Set to true if the component should be visible in the component library
}

// Properties
const properties = {
    // Property definitions go here
} satisfies ComponentProperties;

// Body
const body = (props: InferProps<typeof properties>, children: Component[]): Component => {
    return (
        // Component JSX-like structure goes here
        Text("Hello World")
    )
};

// Export
export default defineComponent({
    metadata,
    properties,
    body
});
```

## Button Style Template

When the user asks how to create a **button style component**, use `defineButtonStyle` instead of `defineComponent`. Button styles are specialized components for styling buttons.

```typescript theme={null}
// Body function receives configuration and props
const body = (configuration: ButtonStyleConfiguration, props: Record<string, any>) => {
    
    // configuration.label - The button's label component
    // configuration.isPressed - Boolean for pressed state
    // props - Custom props passed to the button style
    
    return configuration.label
                .foregroundStyle(Color("white"))
                .fontWeight("semibold")
                .padding('horizontal', 23)
                .padding('vertical', 8)
                .background(
                    Capsule()
                        .fill(Color(props?.color || "blue"))
                )
};

// Optional metadata
const metadata = {
    title: "Button Style Name",
    description: "What this button style does"
};

// Export using defineButtonStyle
export default defineButtonStyle({ body, metadata });
```

### Button Style Key Points

1. **Use `defineButtonStyle`** - Not `defineComponent`
2. **Body signature**: `(configuration: ButtonStyleConfiguration, props: Record<string, any>) => Component`
   * `configuration.label` - The button's content to render
   * `configuration.isPressed` - Boolean for pressed state
   * `props` - Custom props for customization
3. **No properties** - Button styles don't use the property system
4. **No modifiers** - Button styles cannot have modifiers applied
5. **Export with `defineButtonStyle`** - Required for button styles

### Button Style Examples

**Basic Button Style:**

```typescript theme={null}
const body = (configuration, props) => {
    return configuration.label
                .fontWeight("semibold")
                .padding('horizontal', 23)
                .padding('vertical', 8)
                .background(
                    RoundedRectangle()
                        .fill(Color(props?.color || "background"))
                        .shadow({ radius: 12, y: 2, color: Color('black').opacity(0.1) })
                )
        
};

export default defineButtonStyle({ body });
```

**Button Style with Pressed State:**

```typescript theme={null}
const body = (configuration, props) => {
    const backgroundColor = configuration.isPressed
        ? (props?.pressedColor || 'blue')
        : (props?.color || 'white');

    return configuration.label
        .fontWeight("semibold")
        .padding('horizontal', 23)
        .padding('vertical', 8)
        .background(
            RoundedRectangle()
                .fill(Color(backgroundColor))
                .shadow({ radius: 12, y: 2, color: Color('black').opacity(0.1) })
        )
};

export default defineButtonStyle({ body });
```

**Using Button Styles:**

```typescript theme={null}
// In a component, apply button styles with .buttonStyle()
Button("Click Me", () => {})
    .buttonStyle(MyButtonStyle())

// Pass props to customize
Button("Custom", () => {})
    .buttonStyle(MyButtonStyle({ color: 'red', pressedColor: 'darkred' }))
```

## Property System

Don't use the defaultValue property in the inspector unless explicitly asked for by the user, pass any default / placeholder values through via the previews.

Default values are only used when a component is used inside the content editor—they do not affect how the component appears in its default preview.

Include a default for all properties in the previews.

Make sure to include at least one preview when creating a new component. Don't create too many previews unless they're useful.

### String Properties

```typescript theme={null}
propertyName: {
    type: "string",
    title: "Display Name",
    description: "Property description",
    inspector: {
        placeholder: "Placeholder text",
        control: "singleline" | "multiline",
        numberOfLines: 3 // for multiline
    },
    validation: {
        minLength: 1,
        maxLength: 100,
        pattern: "regex pattern",
        format: "text" | "email" | "url"
    }
}
```

### Boolean Properties

```typescript theme={null}
propertyName: {
    type: "boolean",
    title: "Display Name",
    description: "Property description"
}
```

### Number Properties

```typescript theme={null}
propertyName: {
    type: "number",
    title: "Display Name",
    description: "Property description",
    inspector: {
        control: "slider" | "input",
        step: 1
    },
    validation: {
        min: 0,
        max: 100
    }
}
```

### Enum Properties

```typescript theme={null}
propertyName: {
    type: "enum",
    options: ["option1", "option2", "option3"],
    // OR with labels:
    options: [
        { value: "value1", label: "Display Label 1" },
        { value: "value2", label: "Display Label 2" }
    ],
    title: "Display Name",
    inspector: {
        control: "segmented" | "dropdown"
    }
}
```

### Array Properties

```typescript theme={null}
propertyName: {
    type: "array",
    valueType: {
        type: "string" // or any other property type
    },
    defaultValue: [],
    validation: {
        minItems: 0,
        maxItems: 10
    }
}
```

### Component Properties

```typescript theme={null}
propertyName: {
    type: "component",
    environment: {},
    allowedComponents: ["specific-component-names"] // optional filter
}
```

### Asset Properties

```typescript theme={null}
propertyName: {
    type: "asset",
    assetTypes: ["image", "video", "audio", "model", "model/usdz", "model/glb"]
}
```

### Group Properties

For complex nested objects:

```typescript theme={null}
propertyName: {
    type: "group",
    properties: {
        nestedProp1: { type: "string", defaultValue: "value" },
        nestedProp2: { type: "number", defaultValue: 42 }
    }
}
```

## Core Components

### Layout Components

**VStack** - Vertical layout:

```typescript theme={null}
VStack([
    Text("Item 1"),
    Text("Item 2")
])

// With properties
VStack({ spacing: 16, alignment: "leading" }, [
    Text("Item 1"),
    Text("Item 2")
])
```

**HStack** - Horizontal layout:

```typescript theme={null}
HStack([
    Text("Left"),
    Text("Right")
])

// With properties
HStack({ spacing: 8, alignment: "center" }, [
    Text("Left"),
    Text("Right")
])
```

**ZStack** - Overlay layout:

```typescript theme={null}
ZStack([
    Rectangle().fill(Color("blue")),
    Text("Overlay text").foregroundStyle(Color("white"))
])

// With alignment
ZStack({ alignment: "topLeading" }, [
    Rectangle(),
    Text("Top left")
])
```

### Text Components

**Text** - Display text:

```typescript theme={null}
Text("Hello World")

// With markdown
Text({ markdown: "**Bold** and *italic*" })

// With modifiers
Text("Styled text")
    .font("headline")
    .foregroundStyle(Color("blue"))
    .bold()
    .multilineTextAlignment("center")
    .lineLimit(2)
```

**TextField** - Text input:

```typescript theme={null}
TextField({ 
    placeholder: "Enter text", 
    text: textValue, 
    setText: setTextValue 
})
    .textFieldStyle("roundedBorder")
    .keyboardType("default")
```

### Interactive Components

**Button** - Clickable button:

```typescript theme={null}
Button("Click me", () => {
    // Action
})

// Or with component label
Button({
    label: Text("Click me").bold(),
    action: () => {
        // Action
    }
})
```

**Toggle** - Switch control:

```typescript theme={null}
Toggle({ 
    label: "Enable feature", 
    isOn: toggleState, 
    setIsOn: setToggleState 
})
```

### Display Components

**Image** - Display images:

```typescript theme={null}
Image({ url: "https://example.com/image.jpg" })
    .resizable()
    .frame({ width: 100, height: 100 })

Image({ url: "https://example.com/image.jpg", contentMode: 'fill' })
    .resizable()
    .frame({ width: 100, height: 100 })

Image({ systemName: "star.fill" })
    .foregroundStyle(Color("yellow"))
```

### Shape Components

**Rectangle, Circle, Capsule** - Basic shapes:

```typescript theme={null}
Rectangle()
    .fill(Color("blue"))
    .frame({ width: 100, height: 100 })

Circle()
    .stroke({ style: Color("red"), lineWidth: 2 })
    .frame({ width: 50, height: 50 })

Capsule()
    .fill(LinearGradient({
        colors: [Color("red"), Color("orange")]
    }))
```

## State Management

### useState Hook

```typescript theme={null}
const [count, setCount] = useState(0)
const [user, setUser] = useState({ name: "", email: "" })

// Usage in component
Button(`Count: ${count}`, () => setCount(count + 1))
```

### useStore Hook

For shared state:

```typescript theme={null}
const store = useStore("userPreferences", { theme: "light", language: "en" })

// Access and modify
Text(`Theme: ${store.theme}`)
Button("Toggle Theme", () => {
    store.setTheme(store.theme === "light" ? "dark" : "light")
})
```

## Modifiers

### Frame and Layout

```typescript theme={null}
.frame({ width: 100, height: 200, alignment: "center" })
.padding(16) // all sides
.padding("horizontal", 20) // specific edges
.offset({ x: 10, y: 20 })
.zIndex(5)
```

### Styling

```typescript theme={null}
.background(Color("blue"))
.foregroundStyle(Color("white"))
.cornerRadius(8)
.shadow({ radius: 4, x: 2, y: 2, color: Color("black").opacity(0.3) })
.opacity(0.8)
.blur(2)
```

### Text Styling

```typescript theme={null}
.font("headline")
.fontWeight("bold")
.italic()
.underline()
.strikethrough()
.lineLimit(3)
.multilineTextAlignment("center")
```

### Interactive

```typescript theme={null}
.onTapGesture(() => { /* action */ })
.disabled(isDisabled)
.hidden(shouldHide)
.contextMenu([
    Button("Option 1", () => {}),
    Button("Option 2", () => {})
])
```

## Colors and Styling

### Color Creation

```typescript theme={null}
Color("red") // named color
Color("#FF0000") // hex
Color({ r: 1.0, g: 0.0, b: 0.0 }) // RGB
Color("primary") // semantic color
Color("systemGray5") // system semantic color
```

#### Supported Named Colors

Named: `"clear"`, `"red"`, `"orange"`, `"yellow"`, `"green"`, `"mint"`, `"teal"`, `"cyan"`, `"blue"`, `"indigo"`, `"purple"`, `"pink"`, `"brown"`, `"black"`, `"white"`, `"gray"`

Semantic: `"primary"`, `"secondary"`, `"tertiary"`, `"quaternary"`, `"accent"`, `"background"`

System semantic (all adaptive to light/dark mode):

* Labels: `"label"`, `"secondaryLabel"`, `"tertiaryLabel"`, `"quaternaryLabel"`, `"placeholderText"`, `"link"`
* Grays: `"systemGray"`, `"systemGray2"`, `"systemGray3"`, `"systemGray4"`, `"systemGray5"`, `"systemGray6"`
* Backgrounds: `"systemBackground"`, `"secondarySystemBackground"`, `"tertiarySystemBackground"`, `"systemGroupedBackground"`, `"secondarySystemGroupedBackground"`, `"tertiarySystemGroupedBackground"`
* Fills: `"systemFill"`, `"secondarySystemFill"`, `"tertiarySystemFill"`, `"quaternarySystemFill"`
* Separators: `"separator"`, `"opaqueSeparator"`

### Gradients

```typescript theme={null}
LinearGradient({
    colors: [Color("red"), Color("blue")],
    startPoint: "topLeading",
    endPoint: "bottomTrailing"
})

RadialGradient({
    colors: [Color("white"), Color("black")],
    center: "center",
    startRadius: 0,
    endRadius: 100
})
```

### Materials

```typescript theme={null}
Material("thin") // glass effect
Material("regular")
Material("thick")
```

## Previews

Previews are pre-configured instances of your component that showcase different states, configurations, or use cases. They appear in component galleries, documentation, and design tools.

### Basic Preview Array

```typescript theme={null}
const previews = [
    Button("Default", () => {}),
    Button("Primary", () => {}),
    Button("Disabled", () => {})
]
```

### Using Self in Previews

The `Self` function references the current component being defined and allows you to create previews with specific property values:

```typescript theme={null}
const previews = [
    Self({ text: "Default Badge" }),
    Self({ text: "Success", color: "green" }),
    Self({ text: "Error", color: "red" }),
    Self({ text: "Warning", color: "yellow" })
]
```

### Preview Names

Use the `.previewName()` modifier to provide descriptive names for preview variants:

```typescript theme={null}
const previews = [
    Self({ title: "Welcome" }).previewName("Default State"),
    Self({ title: "Alert", backgroundColor: "red" }).previewName("Error State"),
    Self({ title: "Success", backgroundColor: "green" }).previewName("Success State")
]
```

### Previews with Children

For components that accept children, you can provide them in previews:

```typescript theme={null}
const previews = [

    Self({ title: "Empty Card" }),

    Self({ title: "Card with Content" }, [
        Text("This is some sample content"),
        Button("Action", () => {})
    ]).previewName("With Content"),

    Self({ title: "Rich Content" }, [
        Image({ url: "sample-image.jpg" }),
        Text("Image caption"),
        HStack([
            Button("Like", () => {}),
            Button("Share", () => {})
        ])
    ]).previewName("Rich Media Card")

]
```

### Preview with asset property

```typescript theme={null}
const properties = {
    asset: {
        type: "asset",
        title: "Image",
        assetTypes: ["image"],
        description: "The main image displayed in the card"
    }
} satisfies ComponentProperties;
```

Asset properties will be a dictionary with a key of image, video, or model. This is important when using asset properties.

Prefer naming an asset just 'asset' unless there are multiple.

```typescript theme={null}
const previews = [
    Self({
        asset: { image: { url: "https://picsum.photos/400/240" } }
    }).previewName("Default Card")
];
```

### Asset Property Rules for BindJS Components

When generating BindJS components, you must follow the rules below for all asset properties and previews.

#### Asset Property Definition Rules

1. Asset properties must be defined using this structure:

```typescript theme={null}
asset: {
    type: "asset",
    title: "Image",
    assetTypes: ["image"],
    description: "The main image displayed in the card"
}
```

2. Asset properties always decode into an object keyed by asset type.

Valid keys:

* image
* video
* model

3. If the component has only one asset, name the property exactly `asset`.\
   If multiple assets exist, name them descriptively (iconAsset, backgroundAsset, etc.).

#### Asset Value Shape Requirements

Whenever an asset value is provided (in props, previews, or defaults), it must use this wrapping:

```typescript theme={null}
asset: {
    image: {
        url: "https://example.com/image.png"
    }
}
```

Do NOT generate:

* `asset: "https://…"`
* `asset: { url: "…" }`
* `asset: { imageUrl: "…" }`
* any structure missing the asset-type wrapper

#### Preview Generation Rules

Every preview example must use the correct nested asset structure:

```typescript theme={null}
const previews = [
    Self({
        asset: { image: { url: "https://picsum.photos/400/240" } }
    }).previewName("Default Card")
];
```

#### BindJS Usage

Can then be used in the code like this (example):

```typescript theme={null}
Image(props.asset.image)
        .resizable()
        .frame({ height: 180 })
        .cornerRadius(12)
```

Or

```typescript theme={null}
Image({...props.asset.image, contentMode: 'fill' })
        .resizable()
        .frame({ height: 180 })
        .cornerRadius(12)
```

#### LLM Requirements

* Always define asset props using type: "asset" with assetTypes.
* Always wrap asset values under their asset-type key.
* Prefer naming the property `asset` when only one exists.
* Ensure previews use the correct nested asset structure.
* Never simplify or flatten the asset field.
* Never output a raw string or a direct `{ url }` object for asset properties.

### Preview Best Practices

1. **Show different states**: Create previews for empty, loading, error, and success states
2. **Demonstrate variations**: Show different color schemes, sizes, or configurations
3. **Include edge cases**: Show how the component handles long text, no content, etc.
4. **Use meaningful names**: Provide clear `.previewName()` descriptions for each variant
5. **Keep previews realistic**: Use representative content that would actually appear in the app

### Complete Preview Example

```typescript theme={null}
const metadata = {
    title: "Status Card",
    description: "A card component with status indicators",
    category: "Display"
}

const properties = {
    title: {
        type: "string",
        defaultValue: "Status",
        title: "Title"
    },
    status: {
        type: "enum",
        options: ["success", "warning", "error", "info"],
        defaultValue: "info",
        title: "Status"
    },
    showIcon: {
        type: "boolean",
        defaultValue: true,
        title: "Show Icon"
    }
} satisfies ComponentProperties;

const body = (props: InferProps<typeof properties>, children: Component[]): Component => {
    const statusColors = {
        success: "green",
        warning: "yellow", 
        error: "red",
        info: "blue"
    }
    
    return (
        VStack({ spacing: 8 }, [
            HStack([
                props.showIcon ? Text("●").foregroundStyle(Color(statusColors[props.status])) : Empty(),
                Text(props.title).fontWeight("bold")
            ]),
            ...children
        ])
        .padding(12)
        .background(Color(statusColors[props.status]).opacity(0.1))
        .cornerRadius(8)
    )
};

const previews = [
    Self({ title: "All Good" }).previewName("Default"),
    Self({ title: "Success", status: "success" }, [
        Text("Operation completed successfully")
    ]).previewName("Success State"),
    Self({ title: "Warning", status: "warning" }, [
        Text("Please review your settings")
    ]).previewName("Warning State"),
    Self({ title: "Error", status: "error" }, [
        Text("Something went wrong")
    ]).previewName("Error State"),
    Self({ title: "No Icon", showIcon: false }).previewName("Without Icon")
];

export default defineComponent({
    metadata,
    properties,
    body,
    previews
});
```

## Component Categories

Use these standard categories in metadata:

* **Layout** - VStack, HStack, Grid, etc.
* **Controls** - Button, TextField, Picker, etc.
* **Display** - Text, Image, Icon, etc.
* **Navigation** - TabView, NavigationStack, etc.
* **Data** - List, ForEach, etc.
* **Custom** - Specialized components

## Complete Examples

### Simple Display Component

```typescript theme={null}
const metadata = {
    title: "Badge",
    description: "A small status indicator with text",
    category: "Display"
}

const properties = {
    text: {
        type: "string",
        defaultValue: "Badge",
        title: "Badge Text"
    },
    color: {
        type: "enum",
        options: ["blue", "green", "red", "yellow"],
        defaultValue: "blue",
        title: "Color"
    }
} satisfies ComponentProperties;

const body = (props: InferProps<typeof properties>, children: Component[]): Component => {
    return (
        Text(props.text)
            .font("caption")
            .foregroundStyle(Color("white"))
            .padding(8)
            .background(Color(props.color))
            .cornerRadius(4)
    )
};

export default defineComponent({ metadata, properties, body });
```

### Interactive Component with State

```typescript theme={null}
const metadata = {
    title: "Counter",
    description: "A counter with increment/decrement buttons",
    category: "Controls"
}

const properties = {
    initialValue: {
        type: "number",
        defaultValue: 0,
        title: "Initial Value"
    },
    step: {
        type: "number",
        defaultValue: 1,
        title: "Step Size",
        validation: { min: 1 }
    }
} satisfies ComponentProperties;

const body = (props: InferProps<typeof properties>, children: Component[]): Component => {
    const [count, setCount] = useState(props.initialValue)
    
    return (
        HStack({ spacing: 12, alignment: "center" }, [
            Button("-", () => setCount(count - props.step)),
            Text(`${count}`)
                .font("title2")
                .fontWeight("semibold")
                .frame({ minWidth: 40 }),
            Button("+", () => setCount(count + props.step))
        ])
    )
};

export default defineComponent({ metadata, properties, body });
```

### Layout Component with Children

```typescript theme={null}
const metadata = {
    title: "Card",
    description: "A container with rounded corners and shadow",
    category: "Layout"
}

const properties = {
    title: {
        type: "string",
        defaultValue: "Card Title",
        title: "Title"
    },
    backgroundColor: {
        type: "string",
        defaultValue: "white",
        title: "Background Color"
    }
} satisfies ComponentProperties;

const body = (props: InferProps<typeof properties>, children: Component[]): Component => {
    return (
        VStack({ spacing: 12, alignment: "leading" }, [
            Text(props.title)
                .font("headline")
                .fontWeight("bold"),
            ...children
        ])
        .padding(16)
        .background(Color(props.backgroundColor))
        .cornerRadius(12)
        .shadow({ radius: 4, y: 2 })
    )
};

export default defineComponent({ metadata, properties, body });
```

## Defaults

### Shadow

```
.shadow({ radius: 20, y: 12, color: Color('black').opacity(0.12) })
```

### CornerRadius

```
.cornerRadius(12)
```

### Padding

```
.padding(16)
```

### Background

```
.background(Color("background"))
```

## Best Practices

1. **Always define metadata** with meaningful title, description, and category
2. **Use semantic property names** that clearly indicate purpose
3. **Provide sensible defaults** for all properties
4. **Include proper TypeScript typing** with `InferProps<typeof properties>`
5. **Use appropriate validation** for property constraints
6. **Structure components logically** with clear layout hierarchy
7. **Handle edge cases** like empty children arrays or missing props
8. **Use consistent naming conventions** (camelCase for properties, PascalCase for components)

## Property Inspector Options

Each property can have `inspector` configuration for UI appearance:

* `showLabel?: boolean` - Whether to show the property label
* `showDivider?: boolean` - Whether to show a divider after the property
* `visible?: boolean` - Whether the property is visible in the inspector
* `helpDescription?: string` - Additional help text

This guide provides the foundation for generating well-structured BindJS components that follow the project's conventions and TypeScript patterns.
