commit ae2a7e1ce96035afab4686b123df4255d796beb8 Author: Ku6epXBOCTuK Date: Tue Aug 25 20:15:49 2026 +0500 docs: initial plan diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 0000000..d378c92 --- /dev/null +++ b/docs/PLAN.md @@ -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: генератор фейковых зрителей/команд для разработки без живого стрима +- Событие усталости: аватар временно перестаёт работать, зритель реагирует +- Совместная работа: несколько аватаров у одной ноды дают небольшой бонус (социальная связка) +- Рандомные события для удержания: золотая жила, дух леса и т.п.