docs: initial plan
This commit is contained in:
+194
@@ -0,0 +1,194 @@
|
|||||||
|
# Idle-XBOCT — план игры для Twitch-чата
|
||||||
|
|
||||||
|
Смесь Stream Avatars и idle-игр (Melvor Idle / Idle Iktah) с кооп-задачами.
|
||||||
|
Аватары зрителей живут на экране стрима; команды чата управляют ими.
|
||||||
|
|
||||||
|
**Ключевой принцип:** весь геймплей через команды чата — клиенты только отображают состояние.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Стек
|
||||||
|
|
||||||
|
| Слой | Выбор |
|
||||||
|
| -------- | ------------------------------------------------------------------------------------------- |
|
||||||
|
| Монорепа | pnpm workspaces + TypeScript strict |
|
||||||
|
| Клиенты | Svelte 5 + PixiJS 8 (8.x) + bitecs 0.4 |
|
||||||
|
| Сервер | Node.js, `node:http` + `ws` + `sirv` (без фреймворка), симуляция на bitecs |
|
||||||
|
| Twitch | `@twurple/easy-bot` (чтение команд + ответы в чат), `@twurple/eventsub-ws` (Channel Points) |
|
||||||
|
| БД | SQLite (`better-sqlite3`) через тонкий слой репозиториев |
|
||||||
|
|
||||||
|
Решения по ECS: **bitecs, новый API 0.4** (в 0.4 API переписан; старый доступен как `bitecs/legacy`).
|
||||||
|
Запасной вариант — koota (pmndrs), если новый API окажется слишком зубодробительным.
|
||||||
|
miniplex отклонён (объектный оверхед + не развивается с 2023).
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Twitch IRC ──> [сервер: очередь команд] ──> тик 1 Гц
|
||||||
|
│
|
||||||
|
SQLite <── persist WS-снапшот+дельты ──> overlay (OBS browser source)
|
||||||
|
└──> web-страница-мир
|
||||||
|
```
|
||||||
|
|
||||||
|
**Сервер полностью авторитарный.** Все зрители видят одно и то же; OBS произвольно
|
||||||
|
перезагружает browser source; сейвы в одном месте.
|
||||||
|
|
||||||
|
### Два слоя состояния
|
||||||
|
|
||||||
|
Не тащить всё в ECS:
|
||||||
|
|
||||||
|
- **Симуляционный слой (bitecs)** — то, что тикает и рендерится:
|
||||||
|
аватары (позиция, цель, прогресс действия), ноды ресурсов, костёр на сцене.
|
||||||
|
- **Мета-слой (plain TS records + SQLite)** — инвентарь, XP/скиллы, рецепты,
|
||||||
|
вклад в костёр, подарки. Живёт вне ECS, сохраняется напрямую.
|
||||||
|
|
||||||
|
## Синхронизация
|
||||||
|
|
||||||
|
- Подключение → полный снапшот; далее дельты раз в тик + события («+XP», «скрафчено», «вклад в костёр»)
|
||||||
|
- **Команды обрабатываются сразу при приходе**, не ждут тика → мгновенная реакция на `!рубить`
|
||||||
|
- **Движение — декларативные твины**: сервер один раз шлёт «идёт из A в B, скорость v»,
|
||||||
|
клиент анимирует сам. Позиции и прогресс-бары дорисовываются локально между тиками
|
||||||
|
- Тик фиксированный 1 сек (захочется отзывчивее — константа → 2–4 Гц)
|
||||||
|
- Симуляция от wall-clock таймстемпов: при старте сервера пропущенное время
|
||||||
|
догоняется ретроактивно (декей костра копился, пока стрим был оффлайн)
|
||||||
|
|
||||||
|
## Хостинг-ready (почти бесплатно сейчас)
|
||||||
|
|
||||||
|
Локально для себя, но с прицелом на будущий мультистримерный хостинг:
|
||||||
|
|
||||||
|
1. **`channelId` везде с первого дня**: колонки в таблицах БД, поле в командах и WS-сообщениях
|
||||||
|
2. **Интерфейс `TwitchSource`**: локально = свой bot-токен через twurple;
|
||||||
|
на хостинге замена на OAuth-flow без изменений в остальном коде
|
||||||
|
3. **Тонкий слой persist** над SQLite — заменим при необходимости
|
||||||
|
4. **Контент как данные** (JSON-in-TS в `shared`) — баланс правится без кода
|
||||||
|
|
||||||
|
Протокол — контракт: клиенты зависят только от него, язык сервера можно сменить позже.
|
||||||
|
|
||||||
|
## Структура репозитория
|
||||||
|
|
||||||
|
```txt
|
||||||
|
idle-xboct/
|
||||||
|
├─ packages/
|
||||||
|
│ ├─ shared/ # протокол WS, контент (предметы/скиллы/ноды/рецепты), XP-кривые.
|
||||||
|
│ │ # Чистые данные, без DOM/canvas зависимостей — импортируется и сервером
|
||||||
|
│ ├─ server/ # node:http + ws + twurple-bot + bitecs-sim + sqlite
|
||||||
|
│ │ └─ src/{twitch, sim, game, net, persist}
|
||||||
|
│ ├─ render/ # pixi-зависимый общий рендер (аватары, ноды, интерполяция)
|
||||||
|
│ ├─ overlay/ # Svelte 5 + Pixi 8 — компактный, прозрачный фон, для OBS
|
||||||
|
│ └─ web/ # Svelte 5 + Pixi 8 — страница-мир: большой канвас + панели
|
||||||
|
```
|
||||||
|
|
||||||
|
`web` = богатый спектатор, OAuth зрителям не нужен: read-only панели
|
||||||
|
(свой инвентарь по нику, дерево рецептов, лидерборды, прогресс костра).
|
||||||
|
Кликабельные действия — возможное будущее расширение с Twitch OAuth.
|
||||||
|
|
||||||
|
## Игровые механики MVP
|
||||||
|
|
||||||
|
Навыки: Рубка леса, Добыча руды, Кузнечное дело, Рыбалка, Кулинария.
|
||||||
|
XP-кривая Melvor-подобная, уровни открывают ноды/рецепты.
|
||||||
|
|
||||||
|
- Действие = 15–60 сек с видимым прогрессом (зритель должен увидеть аватар за работой)
|
||||||
|
- Ноды ресурсов: тиры деревьев/руды/рыбных мест, респавн
|
||||||
|
- Крафт: топоры/кирки тирами; предметы — стаки, строковые slug-id
|
||||||
|
- Инструменты можно менять и дарить (`!подарить @ник предмет`); подарки только
|
||||||
|
**перемещают** предметы — нельзя подарить то, чего у тебя нет
|
||||||
|
- Аватар продолжает текущее действие, пока не придёт другая команда (`!стоп` — остановиться)
|
||||||
|
- Онбординг — в самом виджете (HUD-подсказки), чат ботом не засоряем
|
||||||
|
- Команды: `!рубить`, `!копать`, `!ковать`, `!рыбачить`, `!готовить`, `!отдых`,
|
||||||
|
`!стоп`, `!подарить`, `!топ`; спотлайт — не команда, а Channel Point награда.
|
||||||
|
RU сейчас, EN-алиасы потом через конфиг
|
||||||
|
|
||||||
|
### Камера и «показать меня»
|
||||||
|
|
||||||
|
Оверлей показывает не весь мир, а окно-видеоискатель. Мир — горизонтальная полоса зон:
|
||||||
|
лес | рудник | река | костёр/кузница | кухня.
|
||||||
|
|
||||||
|
- **Автотур**: камера сама плавно переезжает между зонами с активностью,
|
||||||
|
стоянка ~30–60 сек на зону; без активности — медленный дрейф
|
||||||
|
- **Спотлайт через Channel Points**: стример создаёт кастомную награду «Показать меня»
|
||||||
|
в твитч-панели → зритель выкупает за свои очки канала (Twitch сам начисляет и списывает,
|
||||||
|
своя экономика не нужна) → сервер ловит redemption по EventSub → камера едет к аватару
|
||||||
|
на ~1 минуту → возврат в тур. Очередь спотлайтов; балансировка спроса — позже,
|
||||||
|
другими наградами за те же очки
|
||||||
|
- Камера стрима **авторитарна на сервере** — все клиенты стрима видят одно и то же;
|
||||||
|
веб-страница-мир получает свободную камеру + «следовать за мной»
|
||||||
|
|
||||||
|
### Кооп-костёр
|
||||||
|
|
||||||
|
- Общий пул прогресса + ledger персональных вкладов
|
||||||
|
- Декей съедает вклады → визуальный откат, если долго никто не работает
|
||||||
|
- Уровни костра 1–5
|
||||||
|
|
||||||
|
### Отдых (бафф за активность, не за силу)
|
||||||
|
|
||||||
|
- `!отдых` у костра тратит рыбу → **+20% добычи на 5 минут за 1 минуту отдыха**
|
||||||
|
- Стакается ограниченно; влияет почти незаметно — механика вовлечения, не прогресса
|
||||||
|
|
||||||
|
### Антиспам
|
||||||
|
|
||||||
|
Кулдаун на смену действия, троттлинг ответов бота (пишет только при значимых событиях).
|
||||||
|
|
||||||
|
## Милстоуны
|
||||||
|
|
||||||
|
- **M0 — каркас.** Монорепа, overlay+web скелеты, WS-эхо.
|
||||||
|
✅ аватар-заглушка виден в OBS
|
||||||
|
- **M1 — вертикальный срез.** `!рубить`/`!стоп`, спавн аватара (аватарка из тегов чата),
|
||||||
|
ходьба к дереву, брёвна + XP + уровень, автосейв, WS-снапшот+дельты,
|
||||||
|
камера-окно + простейший автотур.
|
||||||
|
✅ зритель пишет `!рубить` и видит себя рубящим в лесу
|
||||||
|
- **M2 — руда и кузница.** `!копать` + `!ковать` + тиры топоров/кирок.
|
||||||
|
✅ скрафтил железный топор → рубишь заметно быстрее
|
||||||
|
- **M3 — рыба и кухня.** `!рыбачить` + `!готовить` + `!отдых` у костра.
|
||||||
|
✅ рыба → жареная рыба → бафф +20%/5 мин
|
||||||
|
- **M4 — кооп-костёр.** Ledger вкладов, декей с откатом, уровни 1–5.
|
||||||
|
✅ растёт общими силами, без активности откатывается
|
||||||
|
- **M5 — экономика и полировка.** Спотлайт через Channel Points (EventSub, очередь),
|
||||||
|
`!подарить`, `!топ`, дашборд стримера (баланс-конфиги, сбросы).
|
||||||
|
✅ полная экономика + управление без правки кода
|
||||||
|
|
||||||
|
## Риски / известные ловушки
|
||||||
|
|
||||||
|
- **bitecs 0.4**: мало примеров под новый API — время на чтение исходников;
|
||||||
|
системы оборачиваем тонким интерфейсом для дешёвого fallback
|
||||||
|
- **OBS browser source кэширует**: dev через отдельный порт, версионирование протокола
|
||||||
|
в рукопожатии клиента/сервера
|
||||||
|
- **Аватарки Twitch CDN**: ленивая загрузка + фолбэк-спрайт
|
||||||
|
- **Rate limits чата**: бот отвечает дозированно
|
||||||
|
- **EventSub**: нужен Twitch-апп (client id/secret) у стримера; EventSub WebSocket
|
||||||
|
работает локально без публичного webhook-URL — ок для локального MVP
|
||||||
|
|
||||||
|
## Ассеты
|
||||||
|
|
||||||
|
Аватар зрителя = фото профиля Twitch в кольце; спрайтовые человечки — «тела» под ними
|
||||||
|
и фолбэк. Поэтому берём паки, где тело и голова разделены.
|
||||||
|
|
||||||
|
### Человечки + скины
|
||||||
|
|
||||||
|
- **LimeZu — Modern Interiors / Modern Exteriors** (itch.io, ~$10–15) — основной кандидат:
|
||||||
|
генератор персонажей с сотнями скинов/одежды, домики, мебель, здания уровня «ратуша»,
|
||||||
|
всё в одном стиле
|
||||||
|
- **Universal LPC Spritesheet Generator** (бесплатно, онлайн) — сборка спрайт-листов
|
||||||
|
с ходьбой/анимациями из тысяч деталей. Лицензия GPL/CC-BY-SA — проверить перед коммерциализацией
|
||||||
|
- **Kenney.nl** — CC0, человечки простые геометрические — для прототипа M0–M1
|
||||||
|
|
||||||
|
### Домики, костёр, ратуша
|
||||||
|
|
||||||
|
- **Sprout Lands** (Cup Nooble, itch.io) — милый фермерский стиль
|
||||||
|
- **Mystic Woods** (Game Endeavor, itch.io) — есть бесплатная lite-версия: домики, костёр, природа
|
||||||
|
- **OpenGameArt.org** — много RPG-паков зданий, лицензии смешанные — читать каждую
|
||||||
|
- **CraftPix freebies** — бесплатные наборы зданий/персонажей
|
||||||
|
|
||||||
|
### Правила выбора
|
||||||
|
|
||||||
|
1. Для стрим-игры (канал может быть монетизирован) — CC0 или платная лицензия;
|
||||||
|
CC-BY только с готовностью указать авторство (можно в дашборде)
|
||||||
|
2. Один стиль важнее качества каждого пака — брать линейку у одного автора
|
||||||
|
(LimeZu закрывает людей, дома, ратушу и предметы)
|
||||||
|
3. Прототип M0–M1 — на CC0/Kenney, красивые паки подключаем с M2+
|
||||||
|
|
||||||
|
## Идеи на потом
|
||||||
|
|
||||||
|
- FakeTwitchSource: генератор фейковых зрителей/команд для разработки без живого стрима
|
||||||
|
- Событие усталости: аватар временно перестаёт работать, зритель реагирует
|
||||||
|
- Совместная работа: несколько аватаров у одной ноды дают небольшой бонус (социальная связка)
|
||||||
|
- Рандомные события для удержания: золотая жила, дух леса и т.п.
|
||||||
Reference in New Issue
Block a user