studio/ARCHITECTURE.md
МИН 31adbf151b Initial public release: Студия Рублокса v1.0
Open-source веб-студия для создания игр Рублокса, двойная лицензия
AGPL-3.0 + Коммерческая.

Главное:
- Vite 5 + React 18 + Babylon 7.54.3 + Monaco Editor + Colyseus 0.16
- Самодостаточный движок ~28к строк (66 файлов): BlockManager,
  TerrainVoxelBuilder, ModelManager, DecoManager, PlayerController,
  ScriptSandboxWorker, MultiplayerSync, 30+ GD-гейммодов
- Главный редактор KubikonEditor (~37к строк) + панели, ScriptEditor (Monaco)
- Витрина игр (KubikonFeed, KubikonStudio, KubikonDocs, KubikonLearn)
- Geometry Dash sub-app (GdMenu, GdShop, GdRules, GdCoverArt)
- 10 admin-preview каталогов для дизайнеров (скины, музыка, порталы и т.д.)
- Конфигурируемый бэкенд через VITE_API_BASE — работает со staging
  (dev-api.rublox.pro) без настройки
- Standalone-режим (VITE_STANDALONE=true) — открыть пустой редактор без бэка
- Полная документация (на русском): README, ARCHITECTURE, CONTRIBUTING,
  SECURITY, CHANGELOG
- ESLint + Prettier + EditorConfig
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Перед публикацией:
- Все импорты из minecraftia заменены на локальные
- Все хардкоды URL (minecraftia-school.ru) и внутренних IP убраны → env
- Admin-эндпоинты Kubikon3DService вырезаны (остаются в приватном репо)
- AdminKubikonModeration не публикуется (модерация — в team.rublox.pro)
- 93 МБ ассетов public/kubikon-assets вынесены в .gitignore
  (раздаются через release artifact)
2026-05-27 23:41:10 +03:00

9.7 KiB
Raw Permalink Blame History

Архитектура студии Рублокса

Как редактор превращает действия мыши в воксельный мир, GLB-модели, скрипты на JS — и сохраняет в JSON для запуска в плеере. Чтение ~10 минут.

Общий поток (открытие проекта)

URL = /edit/<gameId>
   │
   ▼
AuthProvider                читает JWT из localStorage
   │
   ▼
KubikonEditor.jsx (~3500 строк)   главный контейнер, useParams().id = projectId
   │
   ├── GET /api-storys/kubikon3d/projects/{id}    → project_data (JSON)
   │
   ▼
BabylonScene.create()       создание Babylon engine, scene, lights, skybox
   │
   ▼
GameRuntime.loadProject()   парсит project_data, спавнит:
   │                        - BlockManager.placeBlock() × N (воксели)
   │                        - ModelManager.spawnModel() × N (GLB Kenney)
   │                        - DecoManager.placeDeco() × N (трава, камни)
   │                        - PrimitiveManager.add() × N (box/sphere/cylinder)
   │                        - PlayerController.spawn() (камера-«редактор»)
   │
   ▼
ОСНОВНОЙ UI                 на сцене:
   │                        - TopRibbon (тулбар)
   │                        - HierarchyPanel (дерево объектов слева)
   │                        - InspectorPanel (свойства справа)
   │                        - TerrainPanel (кисти ландшафта)
   │                        - ScriptEditor (Monaco)
   │                        - ToolboxModal (выбор моделей)
   │                        - GuiOverlay/Hotbar (HUD режима игры)
   │
   ▼
ЦИКЛ РЕДАКТИРОВАНИЯ         юзер:
                            - кликает мышью → SelectionManager
                            - drag-and-drop → GizmoManager
                            - переключает кисти → TerrainManager
                            - пишет скрипт → ScriptEditor + Babylon-эмулятор
                            - жмёт «Сохранить» → POST /kubikon3d/projects/:id
                            - жмёт «Тест» → embedded preview-player

Главные модули редактора

editor/KubikonEditor.jsx (3452 строки)

Корневой компонент. Хранит ссылки на scene, engine, runtime, managers. Обрабатывает горячие клавиши, undo/redo через HistoryManager. Обвязывает все панели вокруг <canvas>.

editor/engine/ (66 файлов, ~28к строк)

Самодостаточный Babylon-движок. Точно такой же как в плеере, но с дополнительными редакторскими функциями:

Менеджер Файл Что делает
BabylonScene BabylonScene.js Wrapper над Engine+Scene, освещение
GameRuntime GameRuntime.js Оркестратор: loadProject/start/pause/dispose
PlayerController PlayerController.js R15-персонаж, камеры FPV/TPV, контролы
BlockManager BlockManager.js Воксельные блоки uint16-сетка
TerrainVoxelBuilder terrain/* Greedy meshing для чанков
ModelManager ModelManager.js Загрузка GLB через AssetContainer + кеш
DecoManager DecoManager.js ThinInstances для тысяч пропсов
PrimitiveManager PrimitiveManager.js Box/sphere/cylinder примитивы
SelectionManager SelectionManager.js Клик → выделение → highlight
GizmoManager GizmoManager.js Стрелки перемещения/вращения/масштаба
HistoryManager HistoryManager.js Undo/redo стек
ScriptSandbox scripts/ScriptSandbox.js Запуск user JS в Web Worker
MultiplayerSync multiplayer/MultiplayerSync.js Colyseus 0.16 клиент
Audio/Weapon/Zombie/Npc/Dynamics *Manager.js Игровые менеджеры

editor/engine/scripts/ScriptSandbox*.js

Безопасный JS-runtime для пользовательских скриптов. Запускается в Web Worker, без доступа к window/document/fetch. Через postMessage-мост даёт API:

game.onTick((dt) => { ... });
game.onKey('space', () => { player.jump(); });
scene.findOne('Cube1').rotateY(0.1);
ui.set({ score: 42 });

editor/engine/types/

TypeScript-определения для Monaco-автокомплита. Когда юзер пишет скрипт — IDE показывает все доступные методы.

UI-панели

+----------------------------------------------------------+
| TopRibbon: Файл | Правка | Тест | Опубликовать | Помощь  |
+--------+-----------------------------------+-------------+
| Hierar |                                   | Inspector   |
| chyPan |                                   | Panel       |
| el     |        <canvas WebGL>             | (свойства   |
|        |                                   |  выделен-   |
| Дерево |                                   |  ного)      |
| объек- |                                   |             |
| тов    |                                   |             |
|        |                                   |             |
|        +-----------------------------------+             |
|        | Hotbar / TerrainPanel (внизу)                   |
+--------+-------------------------------------------------+

Скриптовый редактор (Monaco)

editor/ScriptEditor.jsx запускает Monaco (~5МБ vendor chunk, lazy-loaded). Подгружает .d.ts из engine/types/ для автокомплита. При сохранении скрипт идёт в ScriptSandbox, который запускает Worker и шлёт результат обратно.

Поток данных при сохранении

Save кнопка → собрать снимок:
  - blocks[] (uint16 array → RLE-compress → base64)
  - models[] {id, type, x, y, z, rx, ry, rz}
  - primitives[] {id, type, color, size}
  - deco[] {type, instances[]}
  - script.code (текст из Monaco)
  - settings {sky, fog, multiplayer, isGd}
  - spawnPoint {x, y, z}
→ JSON.stringify
→ PUT /api-storys/kubikon3d/projects/<id> { project_data: "<json>" }

Чего НЕТ в студии

  • Само воспроизведение игры в проде — это Плеер (отдельный домен player.rublox.pro). В студии есть preview-player/ для теста «прямо здесь».
  • Лента / поиск опубликованных игр — на главном сайте rublox.pro/app.
  • Админка модерации — в team.rublox.pro/moderator/* (приватный фронт команды).

С чего начать новую фичу

Что хочешь добавить Начни здесь
Новый тип блока editor/engine/CONST/blockTypes.js
Новая декор-фабрика admin-preview/gd<тип>/ (фабрика) + регистрация в DecoManager
Новое API скриптов editor/engine/scripts/ScriptSandboxAPI.js + .d.ts в engine/types/
Новая GD-механика editor/engine/Gd<тип>.js + регистрация в GdGameModeRegistry.js
Новый UI-блок инспектора editor/InspectorPanel.jsx
Новая кисть ландшафта editor/TerrainPanel.jsx + TerrainManager.brush*

Производительность

Главные узкие места (что смотреть первым делом):

  1. game.ui.set() каждый кадр — React setState 60Hz убивает FPS. Дросселируй 250мс + diff.
  2. scene.findOne() на старте скрипта — sceneSnapshot приходит через rAF. Звать в onTick или setTimeout(0).
  3. blockMaterialDirtyMechanism=true в Babylon — НЕ включать (ломает рендер новых мешей).
  4. GLB через SceneLoader вместо AssetContainer — течёт материалами.
  5. Monaco-instance создаётся повторно при ремаунте — закешируй ссылку.
  6. Воксельный rebuild на каждый блок — батчить через requestIdleCallback.

Связь со студией / плеером / минкой

  • Бэкенд один на всехapi-storys микросервис (см. disaster-recovery/ в приватном репо мейнтейнера).
  • Авторизация общая — JWT с rublox.pro и player.rublox.pro работают здесь.
  • API-контракт описан в api/Kubikon3DService.js — все эндпоинты /kubikon3d/*.

Лицензионные заметки для контрибьюторов

Контрибьютя, ты соглашаешься лицензировать свои изменения под AGPL-3.0 И предоставляешь мейнтейнеру неисключительную безотзывную лицензию на сублицензирование (см. CLA.md). Это нужно чтобы проект мог продавать коммерческие лицензии корпорациям.