# Формат пака (черновик v0)

Один объект `PACK` описывает весь оверлей. Он вшивается в страницу инлайн-скриптом
(не грузится через `fetch`) — так сцена работает с `file://` без локального сервера.

**Что во что попадает.** `pack.js` — исходник, с которым работает редактор.
В OBS он никогда не указывается: браузерный источник всегда получает `.html`.
Редактор по кнопке собирает **самодостаточный `.html` на каждую сцену**, куда
движок, стили, данные и фоновые картинки вшиты внутрь — рядом с ним не нужно
ни одного файла.

```
редактор  →  scene.html  →  OBS (Браузер → Локальный файл)
   ↑
 pack.js (исходник/резервная копия, в OBS не нужен)
```

```html
<script src="runtime/overlay.js"></script>
<script>OVERLAY.mount({ /* PACK */ });</script>
```

Четыре независимых слоя: **show** (что за шоу) · **theme** (как выглядит) ·
**layout** (где что лежит) · **scenes** (какие экраны есть).

---

## 1. meta

```js
meta: {
  name: 'Неоновый протокол',
  version: 1,              // версия формата, для миграций
  canvas: { w: 1920, h: 1080 },
  storageKey: 'neon-v1'    // ключ localStorage; общий для всех сцен пака
}
```

## 2. show — данные шоу

Единая модель, вынесенная из `SHOW` в паках A. Всё, что правится в эфире.

```js
show: {
  title: 'НЕОНОВЫЙ ПРОТОКОЛ',
  subtitle: '',
  season: 1, episode: 7,
  league: '9 СЕЗОН ИГР ПАНДХАММЕР',
  place: 'ЛЕНИНГРАД, 2078',
  date:  '17 СЕНТЯБРЯ 2078',
  tagline: 'Город помнит всё.',
  master: { name: 'ПАНДХАММЕР' },
  players: [
    { char: 'РЕЙВЕН', name: 'ALEX' },
    { char: 'ГЛИТЧ',  name: 'MIRA' }
  ],
  next:   'СЛЕДУЮЩИЙ ЗАПУСК · 24 СЕНТЯБРЯ, 21:00',
  thanks: 'СПАСИБО, ЧТО БЫЛИ С НАМИ'
}
```

Подстановки в текстах: `{title}`, `{ep}`, `{ep2}`, `{player1}`, `{char1}`, `{master}`, `{place}`…

## 3. theme — оформление

Только токены, никакой разметки. Новый стиль = новый объект `theme`, движок не трогаем.

```js
theme: {
  id: 'neon',
  tokens: {
    bg:'#020610', ink:'#e8f6ff', dim:'#7da3b8',
    accent:'#00e5ff', accent2:'#ff2a6d', accent3:'#b026ff',
    line:'rgba(0,229,255,.45)', plate:'rgba(4,10,20,.78)'
  },
  fonts: {
    display: "'Russo One', Impact, sans-serif",
    mono:    "'PT Mono', monospace",
    hand:    "'Marck Script', cursive"
  },
  frame: 'neon',            // neon | steel | wood | paper | none
  radius: 2,
  fx: {                      // слой помех ПОВЕРХ видео
    scanlines: 0.30, grain: 0.06, vignette: 0.55,
    dust: true, tracking: true, glitch: 'soft'   // off | soft | strong
  },
  backgrounds: {             // свои картинки; необязательны
    start:'assets/bg_start.jpg', game:'assets/bg_game.jpg',
    pause:'assets/bg_pause.jpg', end:'assets/bg_end.jpg'
  }
}
```

## 4. layout — раскладка окон

Главная таблица. Из неё строится **и DOM, и SVG-маска альфа-дырок, и таблица координат
в документации** — расхождение между ними становится невозможным (в нынешних паках
таблицы в README поддерживаются руками).

```js
layout: [
  { id:'cam1', kind:'cam',   label:'{char1}', x:24,   y:104, w:608, h:342 },
  { id:'cam2', kind:'cam',   label:'{char2}', x:656,  y:104, w:608, h:342 },
  { id:'gm',   kind:'cam',   label:'МАСТЕР',  x:1288, y:104, w:608, h:342 },
  { id:'chat', kind:'slot',  label:'чат',     x:1548, y:76,  w:348, h:485 },
  { id:'dice', kind:'slot',  label:'кубики',  x:1548, y:581, w:348, h:174 },
  { id:'vtt',  kind:'slot',  label:'карта',   x:24,   y:486, w:1150,h:575 }
]
```

### Типы окон

| `kind` | Поведение | Настройка в OBS |
|---|---|---|
| `cam` | прорезает дырку в оверлее | источник камеры **под** оверлеем |
| `slot` | полупрозрачная рамка, дырку не режет | браузерный источник (чат, кубики, карта) **поверх** оверлея |
| `panel` | декоративная панель без дырки | — |

Общие поля: `label` (подпись, поддерживает подстановки), `labelPos`, `hidden`, `z`.

`cam` — дырка с рамкой: сквозь неё виден источник под оверлеем.
`slot` — рамка поверх картинки, заливка полупрозрачная, фон сквозь неё просвечивает.
Разделение нужно, чтобы инструкция говорила, куда ставить источник в OBS:
камеры — под оверлей, виджеты — поверх.

> Тип `embed` (виджет по ссылке внутри iframe) отложен по решению пользователя —
> пока сцены добавляются браузерными источниками в OBS. Добавляется позже
> как надстройка, не меняя ядро.

## 5. scenes — экраны

```js
scenes: {
  intro: { type:'intro', animation:'glitch-boot', duration:4.9 },
  start: { type:'start', countdown:15*60, layout:[] },
  game:  { type:'game',  layout: layoutGame },
  pause: { type:'pause', layout:[ {id:'chat', kind:'slot', …} ] },
  end:   { type:'end',   credits:true },
  desk:  { type:'desk' },
  map:   { type:'map' }
}
```

Неролевые пресеты — те же `game` с другой раскладкой:
`solo` (одна камера + чат) · `talk` (болтовня) · `podcast` (двое).

## 6. Приоритет значений (при правке)

```
?e_<ключ>= в URL   →   localStorage[storageKey]   →   PACK.show / layout
```

Правка кликом пишет в `localStorage` и рассылает событие `storage` — остальные
открытые сцены обновляются вживую (механика взята из ORDO/SPO). Сцена ещё
сверяет хранилище сама: док OBS не всегда присылает событие.

Ключи, которые **не** являются текстами шоу:

| Ключ | Зачем |
|---|---|
| `win:<id>` | правка подписи, текста, улик |
| `scene:<id>.hidden.<окно>` | пульт прячет окно только на этой сцене |
| `__ov.mode` | `holes` · `chroma` · `artless` |
| `__ov.restart` | метка «таймеры сначала» |
| `__ov.intro` | метка «заставку снова» |
| `__ov.demo` | показать, где какие окна |

Пульт — страница `пульт.html` или тот же файл сцены с `?dock=1`.

## 7. Заставка и свой шрифт

Сцена `type: 'intro'` рисуется слоем `.ov-intro`, не окном. Ролик —
`animation` (`glitch-boot` · `typewriter` · `film-leader` · `neon-sign` ·
`slide-panels` · `tape-rewind`), длина — `duration` в секундах. Ноль или
«меньше движения» в системе сразу оставляют титр. Название, строка над ним
и подзаголовок берутся из `show.title` / `show.league` / `show.tagline`.
Клавиша `R` на этой сцене проигрывает ролик снова.

Свой шрифт — `theme.fonts.files.display` (или `mono` / `hand`):
`{ data: 'data:font/woff2;base64,…', format: 'woff2' }`. Движок собирает
`@font-face` и ставит его впереди стека. Выбор стека в редакторе файл снимает.

## 8. Открытые вопросы

* хранить ли позиции окон в процентах (для канвы не 1920×1080);
* хостинг конструктора (по умолчанию — диск / `file://`);
* тип окна `embed` — отложен.
