# Andocs Prototypes — Live Reference
Fetch this URL to get the current prototype configuration.
## Schema Version

`prototype.json` supports **version 1** only.
```json
{
  "version": 1
}
```

## Markdown Syntax

Reference a prototype page with optional `title=` and `height=` parameters:

````markdown
```prototype path=my-app/pages/dashboard.html title="Dashboard" height=800

```
````

| Parameter | Description | Default |
|-----------|-------------|---------|
| `path=` | Repository-relative path to HTML file (required) | — |
| `title=` | Display title in toolbar. Falls back to `<title>` tag from HTML, then raw path | extracted from HTML |
| `height=` | Initial iframe height in pixels (200–800) | 600 |

**Title resolution chain:** `title=` from markdown → `<title>` tag extracted from HTML → raw file path.

## Navigation and static assets

Hosted project previews and CLI previews provide this API. Immutable public share
snapshots do not. Use `window.andocs.openPrototype('my-app/pages/dashboard.html')` with a repository-root
path. Andocs handles route parameters and repository context. Do not build
`/app/prototype` URLs inside prototype files.

HTML anchors work too: `<a href="./detail.html">Detail</a>` resolves from the current
prototype directory, and `<a href="/my-app/pages/dashboard.html">Dashboard</a>` resolves
from the repository root. HTML navigation preserves query strings and fragments.
External links keep normal browser behavior. Same-page fragments scroll within the iframe.

Relative static files work: `<img src="./logo.svg" alt="Logo">`,
`<link rel="stylesheet" href="./styles.css">`, and
`<script src="./helpers.js"></script>`. Supported images are GIF, JPEG, PNG, SVG,
and WebP. The hosted app syncs HTML and static files only under a
`prototype.json` directory marker. The CLI previews unmarked HTML but warns that
it will not sync to the hosted app. Files outside the repository and inside
`.git` or `node_modules` are rejected.

## CDN Libraries (auto-injected)

These libraries are automatically injected into every prototype iframe:
| Library | URL |
|---------|-----|
| Alpine.js | `https://cdn.jsdelivr.net/npm/alpinejs@3.14.9/dist/cdn.min.js` |
| Tailwind CSS v4 | `https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4` |
## Sandbox Restrictions

Prototype iframes run with `sandbox="allow-scripts allow-forms"`.
Prefer `type="button"` with a click handler. Forms work natively. Use `@submit.prevent` for form handlers because form submission never leaves the page.
**Allowed:**
- Inline and external JavaScript, including module scripts served by Andocs
- Alpine.js reactivity
- Tailwind CSS styling
- Native Web Components (Custom Elements, Shadow DOM)
- `postMessage` to parent (for height reporting)
- No access to parent cookies, localStorage, or DOM (`allow-same-origin` is NOT set)
- Module imports must use relative or absolute URLs; bare npm package imports require an import map or bundling
- Relative classic scripts, stylesheets, and images resolve from the prototype directory
- Forms save data through handlers; native form navigation is unavailable
- No popups or top-level navigation (self-navigation within the iframe remains possible)

## Persistent Prototype Data

Declare persistent data in the nearest `prototype.json` and use `window.andocsData` only when
the installed Andocs host supports it. Check the installed CLI help and the running preview before
using CLI data APIs. See the [prototype state guide](https://github.com/blogic-cz/blogic-marketplace/blob/2fa4c5c1abc7b9b776d28d7c2f3076862a3c5d9c/template-ts/skills/andocs/references/prototype-state.md)
for declarations, collections, CRUD, sync status, and migration rules.

`window.andocsState` is a deprecated API for data-backed prototypes. Use it only to inspect and
migrate state created by an existing prototype on a host that still provides it. Do not use it for
new prototypes. See the [legacy prototype state guide](https://github.com/blogic-cz/blogic-marketplace/blob/2fa4c5c1abc7b9b776d28d7c2f3076862a3c5d9c/template-ts/skills/andocs/references/prototype-state-legacy.md)
for its supported hosts and limits.

## Iframe Dimensions
| Property | Value |
|----------|-------|
| Min height | 200px |
| Max height | 800px |
| Default height | 600px |
Height auto-adjusts via `postMessage` from the iframe content.
Can be overridden per-block with `height=N` in the markdown syntax.

## Supported File Types
| File Type | Value | Description |
|-----------|-------|-------------|
| HTML page | `prototype-html` | Interactive HTML prototype page |
| Shared CSS | `prototype-css` | Shared styles (auto-discovered from nearest `prototype.json`) |
| Shared JS | `prototype-js` | Shared scripts (auto-discovered from nearest `prototype.json`) |
| Config | `prototype-config` | `prototype.json` marker file |
## Web Components

Prototypes support native Custom Elements with Shadow DOM — no build step required.
Define components in a plain `<script>` block or a local module script.

**Key patterns:**

- **Reactive rendering:** Use `static observedAttributes` + `attributeChangedCallback()` for attribute-driven re-renders
- **Encapsulation:** Use `this.attachShadow({ mode: "open" })` for style isolation
- **Named slots:** Use `<slot name="title">` for composable content projection
- **Smooth transitions:** Build DOM once in `connectedCallback()`, toggle CSS classes on state change (don't replace `innerHTML` — it kills CSS transitions)
- **Event listeners:** Attach to shadow root (`this.#shadow.addEventListener`), not child elements — child listeners are lost on `innerHTML` updates

## Critical Gotchas

1. **Use URL-based module imports** — bare npm package imports require an import map or bundling
2. **Declare ALL private class fields** — missing `#field;` declaration kills the ENTIRE script block, breaking all components
3. **Add `<title>` tag** — Andocs extracts it for toolbar display next to file path
4. **shared.js for shared code** — place a `shared.js` next to `prototype.json` to share Web Component definitions across pages (auto-injected as `<script data-andocs-shared-js>` in `<head>`)
5. **Escape `</script>` in template literals** — use `<\/script>` or `'</' + 'script>'`

## Design Tokens (CSS Custom Properties)

These CSS custom properties are injected into every prototype `:root`:
| Token | Value |
|-------|-------|
| `--accent` | `oklch(0.95 0.02 255)` |
| `--accent-foreground` | `oklch(0.48 0.2 255)` |
| `--background` | `oklch(0.99 0 0)` |
| `--border` | `oklch(0.9 0.01 250)` |
| `--card` | `oklch(0.99 0 0)` |
| `--card-foreground` | `oklch(0.15 0.03 250)` |
| `--chart-1` | `oklch(0.55 0.18 255)` |
| `--chart-2` | `oklch(0.5 0.16 255)` |
| `--chart-3` | `oklch(0.45 0.14 255)` |
| `--chart-4` | `oklch(0.4 0.12 255)` |
| `--chart-5` | `oklch(0.35 0.1 255)` |
| `--destructive` | `oklch(0.55 0.22 25)` |
| `--destructive-foreground` | `oklch(1 0 0)` |
| `--font-mono` | `"SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace` |
| `--font-sans` | `"Inter Variable", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif` |
| `--foreground` | `oklch(0.15 0.03 250)` |
| `--input` | `oklch(0.96 0.005 250)` |
| `--muted` | `oklch(0.96 0.005 250)` |
| `--muted-foreground` | `oklch(0.4 0.02 250)` |
| `--popover` | `oklch(0.99 0 0)` |
| `--popover-foreground` | `oklch(0.15 0.03 250)` |
| `--primary` | `oklch(0.48 0.2 255)` |
| `--primary-foreground` | `oklch(1 0 0)` |
| `--radius` | `0.5rem` |
| `--ring` | `oklch(0.48 0.2 255)` |
| `--secondary` | `oklch(0.97 0.01 250)` |
| `--secondary-foreground` | `oklch(0.2 0.03 250)` |
| `--shadow` | `0 2px 4px 0 rgb(0 0 0 / 0.08), 0 1px 2px -1px rgb(0 0 0 / 0.08)` |
| `--shadow-2xl` | `0 25px 50px -12px rgb(0 0 0 / 0.25)` |
| `--shadow-color` | `rgb(0 0 0)` |
| `--shadow-lg` | `0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)` |
| `--shadow-md` | `0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)` |
| `--shadow-offset-x` | `0px` |
| `--shadow-offset-y` | `2px` |
| `--shadow-opacity` | `0.1` |
| `--shadow-sm` | `0 1px 3px 0 rgb(0 0 0 / 0.08), 0 1px 2px -1px rgb(0 0 0 / 0.08)` |
| `--shadow-spread` | `0px` |
| `--shadow-xl` | `0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)` |
| `--shadow-xs` | `0 1px 2px 0 rgb(0 0 0 / 0.06)` |
| `--spacing` | `0.25rem` |
### Full generated CSS
```css
:root {
  --accent: oklch(0.95 0.02 255);
  --accent-foreground: oklch(0.48 0.2 255);
  --background: oklch(0.99 0 0);
  --border: oklch(0.9 0.01 250);
  --card: oklch(0.99 0 0);
  --card-foreground: oklch(0.15 0.03 250);
  --chart-1: oklch(0.55 0.18 255);
  --chart-2: oklch(0.5 0.16 255);
  --chart-3: oklch(0.45 0.14 255);
  --chart-4: oklch(0.4 0.12 255);
  --chart-5: oklch(0.35 0.1 255);
  --destructive: oklch(0.55 0.22 25);
  --destructive-foreground: oklch(1 0 0);
  --font-mono: "SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  --font-sans: "Inter Variable", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --foreground: oklch(0.15 0.03 250);
  --input: oklch(0.96 0.005 250);
  --muted: oklch(0.96 0.005 250);
  --muted-foreground: oklch(0.4 0.02 250);
  --popover: oklch(0.99 0 0);
  --popover-foreground: oklch(0.15 0.03 250);
  --primary: oklch(0.48 0.2 255);
  --primary-foreground: oklch(1 0 0);
  --radius: 0.5rem;
  --ring: oklch(0.48 0.2 255);
  --secondary: oklch(0.97 0.01 250);
  --secondary-foreground: oklch(0.2 0.03 250);
  --shadow: 0 2px 4px 0 rgb(0 0 0 / 0.08), 0 1px 2px -1px rgb(0 0 0 / 0.08);
  --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
  --shadow-color: rgb(0 0 0);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-offset-x: 0px;
  --shadow-offset-y: 2px;
  --shadow-opacity: 0.1;
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.08), 0 1px 2px -1px rgb(0 0 0 / 0.08);
  --shadow-spread: 0px;
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
  --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.06);
  --spacing: 0.25rem;
}
```

## shared.css Utility Classes
When a `shared.css` file exists next to `prototype.json`, it is auto-injected.
The recommended smart-default classes:
|-------|---------|
| `.prototype-shell` | Card container with border, radius, shadow |
| `.prototype-title` | 1.375rem/700 heading |
| `.prototype-subtitle` | 0.8125rem muted description |
| `.prototype-label` | Uppercase 0.75rem label |
| `.prototype-value` | 2.75rem/700 big number (tabular-nums) |
| `.prototype-btn` | Base button (combine with variant below) |
| `.prototype-btn-primary` | Primary-colored button |
| `.prototype-btn-secondary` | Secondary button with border |
| `.prototype-btn-ghost` | Transparent hover button |
| `.prototype-section` | Muted section with padding and border |
| `.prototype-divider` | 1px border-top separator |
| `.prototype-badge` | Pill-shaped accent chip |

## shared.js Shared Scripts
When a `shared.js` file exists next to `prototype.json`, it is auto-injected as a `<script data-andocs-shared-js>` block in `<head>` of every prototype page in that app root.
Use this to define shared Web Component classes (Custom Elements) once and reuse across multiple HTML pages.

**How it works:**
1. Place `shared.js` next to `prototype.json`
2. Define `customElements.define()` calls inside
3. All pages under that app root auto-receive the script
4. HTML pages use the components directly — no `<script src>` needed

**Example `shared.js`:**
```js
class StatusBadge extends HTMLElement {
  #shadow;
  static observedAttributes = ["status"];
  constructor() {
    super();
    this.#shadow = this.attachShadow({ mode: "open" });
  }
  connectedCallback() { this.#render(); }
  attributeChangedCallback() { this.#render(); }
  #render() { this.#shadow.innerHTML = `<span>${this.getAttribute("status")}</span>`; }
}
customElements.define("status-badge", StatusBadge);
```
