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

# Getting Started

> Create, build, and test your first Vision extension in under 5 minutes.

## Create a New Extension

First, log in to your Vision account:

```bash theme={null}
vision login
```

Then scaffold a new extension:

```bash theme={null}
vision init
```

Interactive mode asks for a name, description, which targets you want (editor panel, OBS layer, interactive page), and whether to include server functions. A ready-to-go project is created in seconds, including initial extension registration.

***

## Project Structure

```
my-extension/
  package.json
  tsconfig.json
  vision.config.json    # Extension metadata
  src/
    admin.tsx            # Editor panel (settings UI)
    layer.tsx            # OBS overlay output
    interactive.tsx      # Live controls (optional)
  server/                # Only if server functions enabled
    schema.ts            # Database schema
    functions.ts         # Server functions (queries, mutations, actions)
```

Each `src/` file is an independent entry point. You only need to include the targets your extension uses. The `server/` directory is created when you opt into server functions during `vision init`.

***

## Fonts

You can preload Google Fonts for the extension via `vision.config.json`:

```json theme={null}
{
  "name": "my-extension",
  "description": "My Vision extension",
  "targets": ["editor", "layer"],
  "server": false,
  "fonts": ["Inter", "Space Mono"]
}
```

For custom local fonts, add files under `public/` and register them with `localFont`:

```tsx theme={null}
import { Text, Vision, localFont } from "@1upvision/sdk";

const scoreFont = localFont({
  src: "/fonts/Orbitron-Bold.woff2",
  family: "Orbitron",
  fallback: ["sans-serif"],
});

function Overlay() {
  return <Text content="GOAL!" style={{ ...scoreFont.style, fontSize: 64 }} />;
}

Vision.render(<Overlay />, { target: "layer" });
```

`localFont` accepts paths like `/fonts/MyFont.woff2` (recommended) and also
normalizes `./public/fonts/MyFont.woff2` to the same output path.

When you run `vision dev` or build for upload, files from `public/` are copied to
`dist/` automatically, so local fonts are shipped with your extension.

***

## Write Your First Extension

Here's a minimal extension with a settings panel and an OBS overlay:

### Editor Panel — `src/admin.tsx`

The settings UI streamers see in the overlay editor.

```tsx theme={null}
import {
  Vision,
  CompactView,
  Text,
  Toggle,
  TextField,
  useExtensionStorage,
} from "@1upvision/sdk";

function Settings() {
  const [storage, setStorage] = useExtensionStorage();

  return (
    <CompactView title="My Extension">
      <Text content="Configure what shows on stream." variant="muted" />
      <Toggle
        label="Visible"
        checked={storage.visible ?? false}
        onChange={(checked) => setStorage({ ...storage, visible: checked })}
      />
      <TextField
        label="Display Text"
        placeholder="Enter text..."
        value={storage.text ?? ""}
        onChange={(value) => setStorage({ ...storage, text: value })}
      />
    </CompactView>
  );
}

Vision.render(<Settings />, { target: "editor" });
```

### OBS Layer — `src/layer.tsx`

What viewers see on stream. Input components like toggles and text fields render as display-only here.

```tsx theme={null}
import { Vision, Text, useExtensionStorage } from "@1upvision/sdk";

function Overlay() {
  const [storage] = useExtensionStorage();

  if (!storage.visible) return null;

  return <Text content={storage.text ?? ""} variant="heading" />;
}

Vision.render(<Overlay />, { target: "layer" });
```

### Interactive Page — `src/interactive.tsx` (optional)

A dedicated full-screen page for active participants and control workflows. All components are fully interactive here, just like the editor panel.

<Note>
  Interactive pages are not intended as high-scale public viewer pages. Do not
  use them as a replacement for a general web app serving thousands of
  concurrent stream viewers.
</Note>

```tsx theme={null}
import {
  Vision,
  CompactView,
  Text,
  Button,
  useExtensionStorage,
} from "@1upvision/sdk";

function Controls() {
  const [storage, setStorage] = useExtensionStorage();

  return (
    <CompactView title="My Extension">
      <Text content="Quick controls for your stream." variant="muted" />
      <Button
        label={storage.visible ? "Hide" : "Show"}
        variant={storage.visible ? "destructive" : "default"}
        onClick={() => setStorage({ ...storage, visible: !storage.visible })}
      />
    </CompactView>
  );
}

Vision.render(<Controls />, { target: "interactive" });
```

<Tip>
  Need a shareable participant link with custom query params? Use
  `useExtensionContext()` and start from `context.interactiveUrl`.
</Tip>

That's it. The editor configures, the interactive page gives quick actions, and the layer shows the result on stream — all synced in real-time.

<Note>
  Every entry point must call `Vision.render()` within 10 seconds of loading, or
  the extension will be terminated.
</Note>

***

## Build

```bash theme={null}
pnpm install
pnpm build
```

This compiles each entry point into `dist/admin.js`, `dist/layer.js`, etc.

<Info>
  React and `@1upvision/sdk` are provided by the Vision runtime — they're not
  bundled into your extension. Your output stays small.
</Info>

***

## Upload and Test

<Steps>
  <Step title="Create the extension">
    In Vision, go to **Extensions > My Extensions > Create Extension** and select **Vision SDK** as the type.
  </Step>

  <Step title="Create a version">
    Click **Create Version** and enter a version number (e.g., `1.0.0`).
  </Step>

  <Step title="Upload your build">
    Upload your `dist/` folder as a zip file.
  </Step>

  <Step title="Add to an overlay">
    Open an overlay in the editor, add a layer, and select your extension. Your settings panel should appear.
  </Step>
</Steps>

***

## Local Development

Use `vision dev` for the fastest workflow. It watches your project, rebuilds on change, and pushes everything (client bundles, server bundles, and schema) automatically:

```bash theme={null}
vision dev
```

Alternatively, use **Switch to Test** mode to load client bundles from a local URL:

```bash theme={null}
npx serve dist --ssl-cert cert.pem --ssl-key key.pem
```

Then set the test URL to `https://localhost:3000` in the extension settings. Changes to your build are picked up on reload.

### Testing Server Functions

During development, you can invoke server functions directly from the terminal:

```bash theme={null}
vision run query:getPlayers
vision run mutation:addPlayer '{"name": "Alice", "score": 100}'
```

***

## Agent Skill (Optional)

If you use coding agents, install the Vision Extensions skill so they have SDK-specific guidance:

```bash theme={null}
npx skills add 1upmanagement/vision-extensions
```

***

## Next Steps

<CardGroup cols={3}>
  <Card title="Server Functions" icon="server" href="/extensions-sdk/server-functions">
    Add a backend with database, auth, and external APIs
  </Card>

  <Card title="Components" icon="puzzle-piece" href="/extensions-sdk/components">
    All available UI components and how to use them
  </Card>

  <Card title="Hooks" icon="plug" href="/extensions-sdk/hooks">
    Storage, context, and real-time sync
  </Card>
</CardGroup>
