threenebula23andCursor d1374d3d62
CI / tests (push) Failing after 12m25s
feat(v4): immersion UI, soundtrack, Windows export and itch screenshots.
Keep dist/exe/zip out of git so GitHub no longer rejects the 109 MB build.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 23:56:21 +03:00
2026-10-25 00:54:49 +03:00
2026-10-25 00:54:49 +03:00

PEAK HOUR 97

Час пик. Одна смена. Ни одного свободного места.

1997 год. Ночной диспетчер узла файлового обмена: принимайте пакеты, раскладывайте файлы-полимино по папкам, собирайте контейнеры запросов, проходите мини-игры и держите SLA. UI — «Kaleidos»: тёплая бумага, тонкие контуры и бирюзовый акцент.

Жанр: менеджмент / тайм-менеджмент, retro UI. Платформа: Godot 4.7.2 → Web (HTML5, без threads), RU-only. Окно: 1920×1080, логический viewport 1280×720, fractional scale. Забег: 9 игровых часов — 120 / 150 / 180 / 210 / 240 / 270 / 300 / 330 / 360 с (120 + 30×(h−1), всего 36 минут) + подготовка между часами.

Статус v3.0

Играбельный веб-прототип полного цикла: меню → подготовка → час → итоги часа → … → итоги забега. Актуальная спецификация — GDD v3.0, решения — DECISIONS (актуальны D45–D61, D01–D44 — история).

Реализовано:

  • 9 часов, длительность 120 → 360 с (+30 с за час), старт 50 $, SLA 60/60 (кап +40 за уровень lot_sla до 220), 1 слот (макс. 5), канал 10 (макс. 46), буфер 6 (макс. 12), таймер запроса 30 с (макс. 65), таймер пакета 20 с.
  • 4 типа файлов-полимино: текст 1, звук 2, фото 3, видео 4 клетки; поворот R/ПКМ во время drag; сетка папки 5×4 → 6×4 → 7×5 → 8×5 → 8×6 → 9×6 (до 54 клеток). Новая папка — 180 $, всего до 6.
  • Стол сортировки 4×6 в подготовке; файлы со стола нельзя прикрепить, на старте часа они автоматически возвращаются в папки (если места нет — час не начинается).
  • Запросы на 1–4 конкретных именованных файла: имена видны на карточке сеткой 2×2, прикрепление проверяется по точному file_id, потерянный файл помечается «ПОТЕРЯН», обязательные файлы жёстко зарезервированы. H1 стартует с seed-файла и сразу с запроса на него. Отдельного request_cap нет: одновременно живут не больше active_requests запросов, новые не появляются в последние 10 с часа; анти-голодание срабатывает только для первого запроса часа, дальше темп задаёт send_interval.
  • Файлы — каталог, а не расходник: успешная отправка только снимает привязку к запросу, файл остаётся в папке и может быть затребован снова. Приход задаётся только скоростью: окно спавна 75 % часа, интервал — spawn_window / hours[].files с джиттером ±20 %, без переноса и общего лимита файлов (carry = 0).
  • 9 лотов магазина; ровно 3 предложения, рероллы 40/80/120 (макс. 3 за подготовку), замок отдельного предложения. Магазин — с H2 и только в подготовке. Полное дерево — **8 825 ** (было 8 085 с 8 лотами), новый лот lot_udp — «UDP-повторитель».
  • 6 мини-игр отправки (dots, sound, text, video, photo, maze; 3 ступени) и 4 мини-игры атак (junk, ddos, phishing, ransomware; 4 ступени); без таймеров, с шапкой «название + цель», полосой прогресса и экраном результата: имя игры, q%, полоса качества, вердикт, детали и ПРОДОЛЖИТЬ/Esc.
  • TCP как отдельное соединение: до ПОДКЛЮЧИТЬСЯ файлы в запрос не прикрепляются. Успех (3 попадания) занимает out-слот, в слоте — имя клиента и случайный IP; мини-игра отправки сама не открывается. ОТПРАВИТЬ запускает её, только когда прикреплены все файлы. После успешной отправки запрос исчезает, файлы возвращаются в папку и остаются доступны новым запросам, выплата начисляется, но TCP-слот остаётся занятым (idle) до ручного ОТКЛЮЧИТЬ на слоте. TCP платит ×1.15.
  • UDP без соединения: время передачи ×0.8, выплата ×0.85, но успех — ролл в конце передачи: база 40 %, +10 % за уровень lot_udp, максимум 80 % (цены 60/120/210/350). Провал: −3 SLA, без выплаты и денежного штрафа, файлы не расходуются, запрос остаётся, повтор через 4 с, слот освобождается. Файлы не расходуются ни при успешной отправке, ни при отмене/таймауте/отключении.
  • Слоты общие для приёма и отправки: 1 + slot_level, максимум 5. TCP-соединение может занять единственный слот и заблокировать приём — это осознанное требование. Открепление файла — двойной клик по чипу.
  • Шрифты: тело — Kechusilka Regular (нормализован под Golos, fallback Golos Text), крупный текст — DisplayOTF, цифры/счётчики — Press Start 2P; шкала 11/13/17/26.
  • «ЖАРА»: в меню-баре вместо часов 03:42 — TemperatureGauge (216×18, колба, деления, °C); поверх игры — StressOverlay с heat-моделью и alpha-only шейдером без чтения экрана. Пульс SLA/CRIT, тряска панелей ≤2 px, «Снизить эффекты» (reduce_motion) отключает движение; в headless слой скрыт. Анимации карточек, слотов и drag — через UiMotion (Lane B).
  • 20 атак за забег (0,1,1,2,2,3,3,4,4), 4 вида, 4 ступени; атака — это мини-игра, которая ставит час на паузу. Щит «Заземление» гасит атаку автоматически (70 % награды, без штрафа).
  • Пошаговый туториал v3: 5 шагов (пакет → прикрепление → TCP-соединение → мини-игра → SLA/атаки), пульсирующие рамки у цели и кнопка «ДАЛЕЕ». Прохождение хранится в Game.stats["tutorial_done"]; кнопка «ОБУЧЕНИЕ» в главном меню запускает повтор.
  • Save VERSION 2: позиции только в folder.files/table, метаданные в files; v1-сейвы мигрируют без потери файлов и без уменьшения сеток; офферы/рероллы/замки, стол и tutorial_done сохраняются.
  • Мета-награды после 3/5/9 часов, маскот БАЙТ, UI v3 «Kaleidos», ambient машинного зала, VHS только в главном меню.

Ограничения:

  • Сохранение в Web идёт через IndexedDB (user://save.json); проверяйте продолжение после перезагрузки вкладки.
  • Средний расход магазина в симуляторе — 44,9 % дерева 8 825 $; итог 7 205 $ в полосе 6 982–8 500 $, поражений 0/240. H2, H4 и H5 идут близко к нижней границе −20 % (−16,4 %, −15,3 %, −15,1 %), поэтому дальше ужесточать темп нельзя. Подробности — tests/SIM_BALANCE_REPORT.md.
  • Remote push ещё не выполнен; сборка для itch.io готовится локально.

Управление

Действие Ввод
Выбор, меню, перетаскивание ЛКМ
Контекстное меню ПКМ
Поворот фигуры во время drag R или ПКМ
Пакет из «Приёма» → папка drag&drop
Файл из папки → карточка запроса drag&drop (TCP — только после ПОДКЛЮЧИТЬСЯ)
Файл ↔ стол сортировки drag&drop
TCP-соединение кнопка ПОДКЛЮЧИТЬСЯ справа снизу, 3 попадания в зелёную зону
Отправка запроса кнопка ОТПРАВИТЬ слева снизу
Отклонить запрос кнопка ОТКЛОНИТЬ слева снизу
Закрыть TCP-соединение ОТКЛЮЧИТЬ на слоте (мгновенно)
Открепить файл от запроса двойной клик по чипу
TCP/UDP переключатель на карточке запроса до соединения
Мини-игра: действие ЛКМ / Space / стрелки (по игре)
dots: линия нажать на «С» и вести курсор по клеткам
Пропустить мини-игру ПРОПУСТИТЬ/СДАТЬСЯ + второй клик
Результат мини-игры ПРОДОЛЖИТЬ или Esc
Магазин: закрыть ЗАКРЫТЬ или Esc
Пауза Esc

Запуск

Нужен Godot 4.7.2. Команды выполняются из корня репозитория; ниже GODOT — путь к бинарю Godot.

# один раз после клона: импорт шрифтов и темы
"$GODOT" --headless --path . --import

# игра
"$GODOT" --path .

# редактор
"$GODOT" -e --path .

В Windows удобно задать путь один раз:

$env:GODOT_BIN = "D:\Apps\godot\Godot_v4.7.2-stable_win64_console.exe"
& $env:GODOT_BIN --path .

Сборка Web

mkdir -p build/web
"$GODOT" --headless --path . \
  --export-release "Web" build/web/index.html

Результат: build/web/index.html, index.wasm, index.pck и служебные .js/.png. Пресет thread_support=false: COOP/COEP не нужны. Локальный просмотр — только по HTTP:

python -m http.server 8000 --directory build/web
# http://localhost:8000

Нужны export templates 4.7.2 (web_nothreads_release.zip). Каталог шаблонов должен называться 4.7.2.stable.

Тесты

Актуальный список — полный набор + parse-check в scripts/run_all_tests.sh / scripts/run_all_tests.ps1 (см. также tests/; число наборов и проверок может меняться между волнами, поэтому здесь не хардкодится). Core-наборы (test_hour, test_economy, test_save, test_slots, test_controller, test_integration, test_fuzz, test_full_playthrough, test_shop, test_shop_modal) обновлены и зелёные; UI-наборы (test_main_*, ui_smoke) прогоняются отдельно.

# Windows
powershell -ExecutionPolicy Bypass -File scripts/run_all_tests.ps1
# Linux / macOS
bash scripts/run_all_tests.sh

Windows-раннер сам ищет Godot (сначала GODOT_BIN, затем стандартный путь, затем godot4/godot из PATH); путь можно передать явно: -GodotBin <path>.

Точечно:

"$GODOT" --headless --path . --script tests/run_tests.gd
"$GODOT" --headless --path . --script tests/test_fuzz.gd
"$GODOT" --headless --path . --script tests/test_full_playthrough.gd
"$GODOT" --headless --path . --script scripts/ui/ui_smoke.gd

Баланс (240 сидов, отчёт tests/SIM_BALANCE_REPORT.md):

python tests/sim_balance.py

Отчёт tests/SIM_BALANCE_REPORT.md (240 сидов, 9 часов, q=0.85, TCP): средний итог 7 205 $ (payout 6 344 + recv_fee 177 + атаки 684) в полосе 6 982–8 500 $, расход магазина 3 964 $ (44,9 % дерева 8 825 $), 0 поражений из 240, SLA в конце H9 — 64,9, запросов выполнено — 62,0, вердикт PASS, exit code 0. H1 income_target — 100 $ (2-минутный час), H2, H4 и H5 близко к −20 %. Подробности — в AI_REPORT.

E2E-прогоны на реальной сцене Main и веб-смоук проводились в предыдущей волне; после изменений TCP/UDP-модели и UI их нужно перепроверить перед публикацией. Финальный счёт UI-наборов здесь не хардкодится.

Структура

Game-JAM/
├─ project.godot              # 1920×1080 / 1280×720, GL Compatibility
├─ export_presets.cfg         # Web (no threads)
├─ scenes/                    # Main + UI/мини-игры
├─ scripts/
│  ├─ main.gd                 # UI, ввод, модалки, drag&drop, туториал
│  ├─ game_controller.gd      # цикл menu → prep → hour → results
│  ├─ run_all_tests.ps1/.sh   # полный headless-прогон
│  ├─ autoload/               # Game, Data, Audio, Rng, Ambient
│  ├─ core/                   # HourDirector, FileRegistry, SlotManager, Economy
│  ├─ entities/               # файлы, папки, секции, пакеты, запросы, слоты
│  ├─ systems/                # Shop, AttackDirector, SaveManager
│  ├─ ui/                     # Theme90, FileGrid, SortingTable, ShopModal, VHS,
│  │                          # TemperatureGauge, StressOverlay, UiMotion
│  └─ minigames/              # MiniGame, factory, connection_game, send/, attack/
├─ data/                      # balance.json, strings_ru.json, names_ru.json
├─ art/fonts/                 # Kechusilka, DisplayOTF, Golos fallback, Press Start 2P
├─ art/icons/                 # пиксельные иконки + generate_icons.py
├─ audio/                     # sfx/, music/, amb/, generate_*py
├─ shaders/                   # vhs.gdshader (только главное меню)
├─ tests/                     # headless-наборы, sim_balance.py
├─ docs/                      # GDD, DECISIONS, UI_REFRESH, скриншоты
└─ build/                     # артефакты экспорта (gitignored)

Требования

  • Godot 4.7.2 (GL Compatibility).
  • Для Web: export templates 4.7.2, web_nothreads_release.zip.
  • Python 3 — для баланса и пересборки SFX/ambient.
  • Никаких секретов и внешних сервисов.

Документация

  • GDD — правила и числа v3.0.
  • DECISIONS — решения D01–D61 (актуальны D45–D61).
  • AI_REPORT — модели, приёмы и проверки.
  • ASSETS — шрифты, иконки, звук, лицензии и воспроизведение.
  • UI_REFRESH — UI v3 «Kaleidos».
  • IMPLEMENTATION и TEST_PLAN — исторические контракты v1 и матрица тестов (v3-дельты — в начале IMPLEMENTATION).
  • ITCH_PAGE — текст страницы itch.io.
  • screenshots — кадры меню, подготовки, часа и атак.

Лицензии

Код — MIT (LICENSE). Шрифты: Golos Text и Press Start 2P — SIL OFL 1.1, Kechusilka — лицензия подтверждена владельцем проекта, DisplayOTF — freeware/personal (Denis A Serikov). UI, пиксельные иконки (art/icons/) и иконка — MIT. SFX и hum.wav — MIT/CC0, сгенерированы audio/generate_sfx.py. Подробности и тексты лицензий — в ASSETS.md.

S
Description
No description provided
Readme MIT
60 MiB
0 Stars 1 Watchers 0 Forks
Languages
GDScript 90.4%
Python 7.7%
Shell 1.2%
PowerShell 0.4%
GDShader 0.3%