# Manifest (fluxlay.yaml)

The manifest file defines your wallpaper's identity, permissions, and capabilities.

## Full Schema

```yaml title="fluxlay.yaml"
# Required fields
schemaVersion: 1 # Manifest schema version (currently only 1 is supported)
name: string # Display name
slug: string # Unique URL-safe identifier (lowercase, numbers, hyphens)
version: string # Semantic version (e.g., "0.1.0")
kind: web | video | image # Bundle kind

# Conditionally required: when kind is video / image
source: string # Path to the media file (relative to project root)

# Optional
description: string # Brief description

# Optional: Shell commands
shell:
  <command-id>:
    run: string # Command to execute
    reason: string # Why this command is needed
    required: # Required programs
      - string

# Optional: Network access
network:
  - origin: string # URL origin (e.g., "https://api.example.com")
    reason: string # Why access is needed

# Optional: Permissions the wallpaper requests
permissions:
  - keyboard # e.g. required when subscribing to global key events via useKeyboard

# Optional: Custom properties
properties:
  <property-id>:
    type: number | range | color | boolean | text | select | multi-select | image | file | font
    label: string # Label shown in the UI
    # `default` differs per type (image / file have no default)
    default: any
    # Per-type additional fields (see the "properties" section below)
```

## Fields

### schemaVersion

The manifest schema version. Currently only `1` is supported, and it is required. Manifests without `schemaVersion`, or with an unsupported version, fail validation.

### name

The display name shown in the gallery and desktop app. Can contain any characters.

### slug

A unique identifier used in URLs and the store. Must match the pattern `[a-z0-9-]+`. Cannot be changed after the first publish.

### version

A semantic version string. Each publish must use a version that hasn't been published before.

### kind

Bundle kind. Determines the behavior of `fluxlay publish` / `fluxlay build`.

| Value   | Meaning                                                                                                                                                         |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `web`   | Interactive wallpaper built with React/Vite. Built via `vite.config.ts`; the contents of `dist/` are bundled.                                                   |
| `video` | Single-video wallpaper. The `.mp4` / `.webm` file pointed to by `source` is bundled, and the HTML is generated dynamically by the desktop app at delivery time. |
| `image` | Single-image wallpaper. The `.png` / `.jpg` / `.jpeg` / `.webp` / `.gif` file pointed to by `source` is bundled, and the HTML is generated dynamically.         |

### source

Required when `kind` is `video` or `image`. A relative path from the project root to the media file. Not used for `web` kind.

### description

A brief description of the wallpaper. Shown in the store listing.

### shell

Declares shell commands the wallpaper can execute. Each entry is keyed by a command ID used in the SDK (`useShell("command-id")`).

| Field      | Type       | Required | Description                                                                               |
| ---------- | ---------- | -------- | ----------------------------------------------------------------------------------------- |
| `run`      | `string`   | Yes      | The shell command string. Supports multi-line with `\|`.                                  |
| `reason`   | `string`   | No       | Human-readable explanation. Shown to users for approval.                                  |
| `required` | `string[]` | Yes      | Programs the command depends on. Must be present (use `[]` if there are no dependencies). |

### network

Declares external origins the wallpaper needs to access. Declared origins are added to the wallpaper's CSP `connect-src` / `img-src` / `media-src` / `font-src` so the wallpaper can reach them via `fetch`, `<img>` / `<video>` / `<audio>`, and web fonts. They are NOT added to `script-src`, so loading external scripts is still forbidden.

| Field    | Type     | Required | Description                           |
| -------- | -------- | -------- | ------------------------------------- |
| `origin` | `string` | Yes      | URL origin (scheme + host).           |
| `reason` | `string` | Yes      | Why access is needed. Shown to users. |

`origin` must be a pure origin in `<scheme>://<host>[:<port>]` form:

- Scheme must be one of `https` / `http` / `wss` / `ws`
- No path, query, or fragment (`/`, `?`, `#`) — trailing slash is not allowed
- No wildcards (e.g. `*.example.com`) — list each origin explicitly

OK: `https://api.example.com`, `https://api.example.com:8080`, `wss://stream.example.com`
NG: `https://api.example.com/v1` (path), `https://*.example.com` (wildcard), `api.example.com` (no scheme)

> 💡 **Tip**: If `fetch` to a declared origin still fails with an `Access-Control-Allow-Origin` error, see [Fetch External APIs (CORS workaround)](/en/studio/developer/how-to/development/fetch-external-api.md). `proxiedFetch` routes the request through the host process and bypasses browser CORS.

### permissions

Declares the permissions the wallpaper requests. Anything that touches global desktop input or OS resources must be listed here; APIs that require an undeclared permission are rejected by the backend with HTTP 403.

```yaml title="fluxlay.yaml"
permissions:
  - keyboard
  - ime-input
```

| Value       | Purpose                                                                                                                                                                                                                                              |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `keyboard`  | Required when subscribing to global keyboard input via `useKeyboard`. Every keystroke on the desktop — including text typed into other apps — flows to the wallpaper, so it is gated explicitly.                                                     |
| `ime-input` | Required when receiving IME-composed text (e.g. Japanese / Chinese / Korean) via `useImeInput`. Only text directed at the wallpaper's own proxy window is delivered — input typed into other apps is never seen — so it is separate from `keyboard`. |

Duplicate entries and unknown values fail validation.

### properties

Defines custom properties (variables) for the wallpaper. End users can customize the wallpaper through sliders, color pickers, toggles, and dropdowns in the Fluxlay app settings UI. Each entry is keyed by a property ID used in the SDK (`useProperties()`).

| Type           | UI Control               | `default` Type | Additional Fields                                                                                                                               |
| -------------- | ------------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `number`       | Stepper / numeric input  | `number`       | `min` / `max` / `step` (all optional)                                                                                                           |
| `range`        | Slider                   | `number`       | `min` / `max` required, `step` optional. `min <= default <= max`                                                                                |
| `color`        | Color picker             | `string`       | None. `default` must be a hex color: `#rgb`, `#rrggbb`, or `#rrggbbaa`                                                                          |
| `boolean`      | Toggle switch            | `boolean`      | None                                                                                                                                            |
| `text`         | Text input               | `string`       | `maxLength` (positive integer, optional) / `placeholder` (string, optional)                                                                     |
| `select`       | Dropdown                 | `string`       | `options: [{value, label}]` required (1 or more). `default` must match one of the `options` values                                              |
| `multi-select` | Checklist / multi-select | `string[]`     | `options` required. `min` / `max` (selection count bounds, non-negative integers) optional. Every element of `default` must appear in `options` |
| `image`        | File picker (image)      | (none)         | `accept` (array of MIME patterns, e.g. `["image/png"]`) / `maxBytes` (positive integer) optional. Has no `default`                              |
| `file`         | File picker              | (none)         | `accept` / `maxBytes` optional. Has no `default`                                                                                                |
| `font`         | Font selector            | `string`       | `sources` (array of `system` and/or `google`) required. `category` (`sans-serif` / `serif` / `monospace` / `display` / `handwriting`) optional  |

#### Notes

- The legacy `type: string` has been removed. Use `select` for dropdowns and `text` for free-form text input.
- When `font.sources` includes `google`, the manifest must also declare a `network` entry to allow Google Fonts requests.
- `image` / `file` values are exposed to the SDK as a local absolute path string (or `null` when unset).

## Examples

### Web wallpaper (React/Vite-based)

```yaml title="fluxlay.yaml"
schemaVersion: 1
name: System Dashboard
slug: system-dashboard
version: 0.2.0
kind: web
description: A live wallpaper displaying system information and weather.

shell:
  system-info:
    run: macchina
    reason: Displays system information in a styled format.
    required:
      - macchina
  weather:
    run: curl -s "https://wttr.in/?format=3"
    reason: Fetches current weather information.
    required:
      - curl

network:
  - origin: https://wttr.in
    reason: Used to fetch current weather information.

permissions:
  - keyboard # Declared when the wallpaper reacts to global key input (e.g. WASD)

properties:
  particleCount:
    type: number
    label: Particle Count
    default: 100
    min: 10
    max: 500
    step: 10
  themeColor:
    type: color
    label: Theme Color
    default: "#ff6b35"
  showClock:
    type: boolean
    label: Show Clock
    default: true
  animationStyle:
    type: select
    label: Animation Style
    default: wave
    options:
      - value: wave
        label: Wave
      - value: spiral
        label: Spiral
  brightness:
    type: range
    label: Brightness
    default: 0.8
    min: 0
    max: 1
    step: 0.05
  customLogo:
    type: image
    label: Custom Logo
    accept:
      - image/png
      - image/jpeg
    maxBytes: 1048576
```

### Video wallpaper

```yaml title="fluxlay.yaml"
schemaVersion: 1
name: My Video Wallpaper
slug: my-video-wallpaper
version: 0.1.0
kind: video
source: ./background.mp4
description: A fullscreen looping video wallpaper.
```

### Image wallpaper

```yaml title="fluxlay.yaml"
schemaVersion: 1
name: My Photo Wallpaper
slug: my-photo-wallpaper
version: 0.1.0
kind: image
source: ./photo.png
description: A still-image wallpaper.
```
