44 Commits

Author SHA1 Message Date
min
66aac4826e debug: добавил лог lightingTimeUpdate для диагностики 2026-06-08 15:57:03 +03:00
min
52724ab9c8 fix(rbxl): invUI вместо inventory + Day/Night портирован + искры Sparkles
Что чинит:
1. _registerRbxlTool падал: использовал scene3d.inventory (InventoryManager,
   старый, без defineItem). Меняю на scene3d.invUI (новый InventoryUI с
   defineItem) — теперь hotbar реально заполняется.

2. Lighting.SetMinutesAfterMidnight теперь шлёт lightingTimeUpdate в
   GameRuntime → scene3d.setTimeOfDay(hour). Тротлинг 4 раза/сек.
   Roblox Day&Night скрипт теперь визуально меняет небо в нашем плеере!

3. Instance.new('Sparkles') шлёт particleCreated в GameRuntime.
   При эквипе Tool — _startRbxlToolParticles() запускает каждые 200мс
   burst у позиции игрока (имитация искр из руки).

4. Авто-эквип первого Tool через 100мс после регистрации — юзеру не
   нужно нажимать 1, инвентарь не очевиден.

5. stop() корректно гасит интервалы и сбрасывает state.

Эти 4 фикса должны дать Zapper-демке базовое визуальное поведение:
видный hotbar, искры из персонажа, плавная смена дня/ночи.
2026-06-08 14:08:09 +03:00
min
1080c18ae0 feat(rbxl): Tool/Backpack/Mouse flow — Шаг 1/3 (Zapper)
Цель: запустить Roblox Tools (Zapper и подобные оружия) в плеере.

Архитектура:
1. RobloxShim: localPlayer.Backpack, localPlayer:GetMouse(), allTools registry,
   equippedTool — внутренний учёт текущего Tool.
2. Instance.new('Tool') — теперь автоматически:
   - создаёт виртуальный Handle (Part) внутри
   - регистрирует Tool в allTools[]
   - шлёт 'toolRegistered' в GameRuntime
3. fireGlobalEvent обработка новых событий из плеера:
   - equipTool {index} → Tool.Equipped:Fire(playerMouse)
   - unequipTool → Tool.Unequipped:Fire()
   - toolActivated → Tool.Activated:Fire()
   - mouseButton1Down {hit} → mouse.Hit.Position + mouse.Button1Down:Fire()
   - keyDown {key} → mouse.KeyDown:Fire(key)
4. LuaSharedSandbox.addScript принимает toolName, в _startSingleScript
   подсовывает виртуальный Tool как script.Parent (через
   __rbxl_get_tool_by_name).
5. GameRuntime эвристика: скрипты с target=null и упоминанием
   script.Parent.Equipped/Activated → toolName='Tool', группируются
   в один Tool.
6. GameRuntime._registerRbxlTool: при получении toolRegistered кладёт
   item в InventoryUI.hotbar, слушает смену слота → equipTool.
7. Клики canvas → mouseButton1Down с raycast Hit.Position.

Следующие шаги:
- HUD: индикатор экипированного Tool в плеере (Шаг 2)
- Leaderboard UI из leaderstats IntValue (Шаг 3)
2026-06-08 13:57:37 +03:00
min
3271e53acf feat(rbxl): уважать enabled=false из Roblox-метадаты
Roblox-скрипты с Disabled=true (например 'Clean', 'Effects' в RayGun)
это шаблоны для клонирования через :Clone(), они никогда не должны
запускаться при старте — иначе while true do wait() end в них крашит
coroutine через WASM access out of bounds.

parseRobloxLuaMeta(code) парсит JSON-метадату из второй строки
packed-кода (формат '// {"roblox_class":..., "enabled":true}').
Скрипты с enabled=false идут в rbxlSkipped, не запускаются.
2026-06-08 13:43:09 +03:00
min
34062993ee feat(rbxl): импортированные скрипты снова включены — итеративная настройка 2026-06-08 13:35:14 +03:00
min
8febde9727 revert: импортированные .rbxl-скрипты выключены по умолчанию
Попытка выполнять Roblox-скрипты массово подвешивает страницу — даже
с object-stub Proxy и батчевым init. У типичной карты 500-2000 скриптов,
которые гоняют DataStore/Tools/RemoteFunction/PlayerGui — наш runtime
их не имеет и не должен иметь (это AGPL Roblox-клон, не эмулятор).

Импорт .rbxl теперь = ВИЗУАЛЬНЫЙ ПОРТЕР:
- геометрия, материалы, текстуры — да
- GUI (статические TextLabel/Button) — да
- физика, анимации игрока — да
- логика игры — пишется на нашем Lua (Этапы 1-7)

Юзер импортирует Roblox-карту → видит её точно → пишет свои скрипты
к примитивам, используя Vector3, Touched, Position-setters, Sound,
TweenService. Это работает идеально и без подвисаний.

Энтузиасты могут включить старое поведение через
window.__RBXL_RUN_IMPORTED = true перед Play.
2026-06-08 13:29:54 +03:00
min
5342c079d1 feat(lua): включил импортированные скрипты + защита от подвисания
1. TweenInfo.new(time, easing, direction, repeat, reverses, delay) —
   глобальный конструктор. Был причиной 'attempt to index nil (TweenInfo)'.
2. Расширенный Enum: InfoType, SortOrder, FillDirection, Font,
   TextXAlignment, ScaleType, PartType, SurfaceType, UserInputState
   и др. — типичные для Roblox-туториалов.
3. NumberSequence/ColorSequence/NumberRange/Rect — заглушки конструкторов.

4. _kickoff() теперь батчами по 20 скриптов через setTimeout(0).
   742 скрипта инициализируются за ~37 фреймов вместо одного
   синхронного блока, UI не подвисает.

5. Импортированные .rbxl-скрипты ВКЛЮЧЕНЫ по умолчанию
   (window.__RBXL_SKIP_IMPORTED=true чтобы выключить).
   Падения отдельных скриптов изолированы — tickScheduler ловит
   ошибки и удаляет битые coroutines, остальные продолжают работать.
2026-06-08 13:26:30 +03:00
min
c5b713fd1f feat(rbxl): импортированные скрипты выключены по умолчанию
Типичная .rbxl карта = 500-2000 Lua-скриптов. Многие используют
DataStoreService, Tools, PlayerGui, UserInputService, и т.п. фичи
которых у нас нет. Даже с object-stub Proxy сотни runtime-падений
после init подвешивают вкладку.

Решение: импорт сохраняет geometry+GUI+физику, скрипты пропускаются.
Юзер пишет свои Lua-скрипты к импортированным примитивам — они
используют наш Этап 1-7 API (Vector3, Touched, Position-setters,
Sound, TweenService) и работают идеально.

Включить старое поведение: window.__RBXL_RUN_IMPORTED = true в DevTools
перед Play.
2026-06-08 13:19:21 +03:00
min
2fa575ae4c refactor(rbxl-import): импортированные Lua-скрипты идут через LuaSharedSandbox
Раньше было два параллельных Lua-runtime:
- RobloxLuaSharedSandbox (Worker + wasmoon) для импортированных .rbxl;
- LuaSharedSandbox (main thread + wasmoon) для user-Lua.

Импортированные скрипты не получали фичи Этапов 4-6
(Position setters, GUI, Sound, TweenService) — их shim был в отдельном
Worker'е с более старым API.

Сейчас в GameRuntime.start():
1. Скрипты с маркером '// @roblox-lua' распаковываются
   через unpackRobloxLuaCode() и попадают в тот же luaUserBatch
   что и user-Lua;
2. Собыраются _rbxlImported=true для лога;
3. Числовой script.target (примитив id) уже совместим с
   LuaSharedSandbox.addScript → резолвится в script.Parent.

Удалены мёртвые файлы (общий размер ~2500 строк):
- RobloxLuaSharedSandbox.js + RobloxLuaSharedWorker.js
- RobloxLuaSandbox.js + RobloxLuaWorker.js (старая пара)
- roblox-shim.js + roblox-services.js + roblox-physics.js
- roblox-scheduler.js + roblox-tween.js
- из rbxl-lua-integration.js убрана функция startRobloxLuaShared()

Побочный эффект: импортированные Roblox-игры теперь автоматически
получают:
- живые part.Position/Size/Color setters;
- полный GUI (Frame/TextLabel/TextButton);
- TweenService:Create с реальной интерполяцией;
- Sound с процедурными звуками;
- Humanoid.Health/Died и прочие фичи Этапов 4-6.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 12:56:05 +03:00
min
936f93a42c fix(lua): part.Position теперь реально двигает куб
КОРНЕВАЯ ПРИЧИНА: BabylonScene.freezeStaticPrimitives() замораживает
world matrix anchored-примитивов при Play для оптимизации.
mesh.position.set(x,y,z) после этого не обновляет рендер.

Фикс в PrimitiveManager.updateInstance: если patch содержит position/
rotation/size — расфризить world matrix прежде чем менять transform.
2026-06-08 12:19:14 +03:00
min
55f4a3fc38 fix(lua): humanoid.Health=0 теперь реально убивает игрока через PlayerController.takeDamage 2026-06-08 11:38:03 +03:00
min
30d472bf43 feat(lua): дублировать Lua print() в DevTools Console для отладки 2026-06-08 11:35:11 +03:00
min
2b15ec821a feat(lua): Этап 3 — DataModel + Touched + Humanoid (main-thread wasmoon)
Главное достижение: KillBrick работает.
script.Parent.Touched:Connect(fn) фейерится когда игрок касается куба,
humanoid:TakeDamage(100) → playerSet команда → BabylonScene.player.hp=0
→ respawn + playerDied event.

Архитектурные изменения:
- LuaSharedSandbox v3: wasmoon в MAIN потоке вместо Worker'а.
  DevTools видит точные ошибки, breakpoints работают,
  console.log в RobloxShim виден сразу.
- LuaSharedWorker.js удалён (больше не нужен).
- RobloxShim добавляет полное DataModel дерево:
  game / Workspace / Players / LocalPlayer / Character /
  Humanoid / HumanoidRootPart / 15 services (RunService.Heartbeat,
  TweenService, HttpService, DataStoreService, etc).
- newPart создаёт RbxPart-обёртку вокруг каждого primitive в сцене,
  Touched/TouchEnded signals.

Wasmoon-quirk:
- TypeError: Cannot read properties of null (reading 'then') возникает
  когда JS-функция возвращает null в Lua-контекст. PromiseTypeExtension
  делает .then без guard. Везде заменили null → undefined (push'ится как nil).
- _rbxl_get_part_by_id возвращает undefined если не нашёл, FindFirstChild и
  прочие тоже undefined вместо null.

GameRuntime.js:
- _buildSceneSnapshot теперь даёт id (для partById), color, anchored,
  canCollide, opacity полей у primitives.
- partSet/sceneCreate user-Lua → handleLuaCommand (rbxl интеграция).
- playerSet handler: humanoid.Health=0 → respawn + hpChange event.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:32:31 +03:00
min
06df77cc97 feat(lua): этапы 1+2 — Lua-скрипты в Рублоксе
Этап 1 (UI):
- Скрипт имеет поле language: 'js' | 'lua' (дефолт 'js')
- Переключатель JS / Lua в шапке ScriptEditor (жёлтый / синий)
- При смене с пустого/template — подставляется шаблон нового языка
- При смене с реальным кодом — confirm
- Monaco автоматически переключает подсветку
- Badge JS/LUA в HierarchyPanel рядом с именем скрипта

Этап 2 (базовый runtime):
- LuaSharedSandbox — обёртка с API совместимым с ScriptSandbox
- LuaSharedWorker — Web Worker с одним wasmoon-VM на всю игру
- RobloxShim — Vector3/Color3/UDim2/Vector2/CFrame, Enum.*, print/warn,
  wait/task.*, RbxSignal, Instance.new (база), game.GetService (стабы),
  RunService.Heartbeat
- Scheduler для task.delay/defer через main loop tick
- GameRuntime разделяет скрипты: JS / Roblox-Lua (импорт) / user-Lua

На Этапе 3 — DataModel (game.Workspace + Instance.Parent + Touched).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 09:57:12 +03:00
min
2b98d8338b Merge remote-tracking branch 'origin/main' into feat/rbxl-import
All checks were successful
CI / Lint (pull_request) Successful in 1m8s
CI / Build (pull_request) Successful in 2m8s
CI / Secret scan (pull_request) Successful in 23s
CI / PR size check (pull_request) Successful in 7s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
# Conflicts:
#	src/editor/HierarchyPanel.jsx
2026-06-08 06:24:27 +03:00
min
9caea93d32 feat(rbxl-import): single-VM Lua runtime + GUI tree + Touched/click events
All checks were successful
CI / Lint (pull_request) Successful in 1m6s
CI / Build (pull_request) Successful in 1m58s
CI / Secret scan (pull_request) Successful in 23s
CI / PR size check (pull_request) Successful in 7s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
ITERATION 6 (single-VM rewrite):
  - RobloxLuaSharedWorker: один wasmoon-state на 742 скрипта (не 742 VM)
  - Pre-populated Workspace + Player.PlayerGui перед addScripts
  - На каждом Part — Touched/TouchEnded сигналы; на каждом TextButton —
    MouseButton1Click/Activated/MouseEnter/Leave; Humanoid с Died/Health
  - Двухфазный init: addScriptsBatch ВСЕ скрипты → kickoff() с PlayerAdded
  - wait()/task.wait/task.spawn/task.delay через scheduler+coroutines
  - guiClick от Rublox-GUI → fireEvent → инстанс.MouseButton1Click.Fire()
  - playerTouch → part.Touched.Fire(HumanoidRootPart) + humanoid.Touched

ITERATION 7 (nullStub compatibility):
  - debug.setmetatable(nil, ...) + debug.setmetatable(function() end, ...)
    с полным набором __index/__newindex/__call/__add/__sub/.../__len/__concat
  - Возврат undefined из FindFirstChild/WaitForChild (вместо JS proxy)
  - Lua-side __null_stub_singleton с Connect/connect/Wait/Fire (lowercase aliases)
  - __rbxl_lookup_part через __rbxl_parts_by_id table (не ipairs на JS array)
  - script.Parent гарантированно не nil (либо реальный Part либо null stub)
  - RbxSignal: Connect+connect, Wait+wait, Fire+fire, Disconnect+disconnect
  - SIGNAL_NAMES whitelist расширен: Tool (Selected/Equipped), Remote (OnInvoke),
    ChatMakeSystemMessage, etc.

Converter:
  - GUI: UDim2 dataclass правильно резолвится (scale*100 + offset/viewport*100)
  - размеры в процентах (как Rublox-GuiOverlay ожидает)
  - ScreenGui.Enabled → пропагируется в детей
  - Эвристика скрыть HD Admin/Chat/CommandBar/TeleportTo модалки
  - rbxasset:// rbxassetid:// фильтруются на пустой URL

Hierarchy:
  - scroll-to-selected раскрывает workspace+rootPrims+folders перед scroll
  - data-sel-id на всех ItemRow с rAF×2 timing

Известные ограничения:
  - Synapse X obfuscated скрипты часто всё равно падают (требуют конкретный Roblox-VM)
  - но debug.setmetatable перехват не даёт скриптам валиться на indexing/arithmetic
  - реальные пользовательские KillBrick (Touched) теперь работают
  - GUI кнопки → MouseButton1Click работают

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 06:18:55 +03:00
min
624bbc636b feat(rbxl-import): single-VM, Touched, scroll-to-selected, GUI
Some checks failed
CI / Lint (pull_request) Failing after 1m5s
CI / Build (pull_request) Failing after 49s
CI / Secret scan (pull_request) Successful in 25s
CI / PR size check (pull_request) Successful in 9s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Все 5 задач итерации:

1. Single-VM mode (RobloxLuaSharedWorker/Sandbox):
   - один Worker, одна wasmoon-VM на ВСЕ скрипты проекта
   - addScript() для каждого, общий tick/event broadcast
   - снимает WASM OOM (1 VM 16MB вместо 742 × 16MB)
   - убран per-script лимит 50, теперь все 742 загружаются

2. Touched events:
   - sendGlobalEvent в shared sandbox распознаёт playerTouch
     и пересылает в Worker как 'touched' с primId
   - Worker находит Part по __primId в workspace и Fire'ит
     его Touched сигнал — Lua-обработчики работают

3. Click в иерархии → scroll-to-selected:
   - useEffect в HierarchyPanel ловит изменение selection
     и scrollIntoView для нужного ItemRow
   - data-sel-id атрибут на primitive/model/block строках

4. GUI Roblox в конвертере:
   - ScreenGui/Frame/TextLabel/TextButton/ImageLabel/TextBox →
     scene.gui c полным набором свойств (UDim2→pixel, Color3→hex,
     BackgroundTransparency→bgOpacity, parentId)

5. Чистка:
   - удалены debug-console.warn из PlayerController._loadPlayerModel
     (убирает spam '[PlayerController.devlog]' в consoles)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 01:39:43 +03:00
min
412bb2fad9 feat(rbxl-import): студия исполняет импортированные Roblox-Lua скрипты
All checks were successful
CI / Lint (pull_request) Successful in 2m43s
CI / Build (pull_request) Successful in 1m57s
CI / Secret scan (pull_request) Successful in 1m21s
CI / PR size check (pull_request) Successful in 8s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Сегодня доведены до играбельного состояния:
- UI модалка импорта подключена в KubikonStudio (кнопка для МИНа в навигации)
- Converter: SCALE 0.35 (карта пропорциональна R15-персонажу),
  playerModelType='skin_bacon-hair', Lua упакован в поле code с маркером
  // @roblox-lua (storys API сохраняет только {id,code,target,name})
- vite.config: api+статика через rublox.pro/minecraftia-school.ru
- GameRuntime: распознаёт маркер, запускает через RobloxLuaSandbox
  + wasmoon Worker. Фильтрация: target!=null + lua<2500б +
  лимит 50 sandbox'ов (WASM OOM при >50 VM)
- roblox-shim: nullStub (Proxy с no-op методами) вместо null
  для FindFirstChild/WaitForChild — цепочки не падают
- require() заменён на nullStub
- RobloxLuaSandbox: совместимость с интерфейсом ScriptSandbox
  (sendGlobalEvent/SceneSnapshot/etc — no-op заглушки)
- RobloxLuaWorker: pcall обёртка над user-кодом
- remoteDevlog.js + /devlog endpoint: автосбор browser-логов
- PlayerController._loadSkinManifest: dev-fallback на studio.rublox.pro

Тест на Easy Obby:
- 8205 instances → 2245 primitives + 742 Lua-scripts
- 50/742 Lua-VM запущены (KillBrick handlers и т.п.),
  151 отфильтровано как admin/chat services, 541 пропущено по памяти
- Скин bacon-hair виден, FPS 20-25
- Сцена играется, можно ходить, прыгать

TODO (следующая итерация):
- Single-VM mode для wasmoon (один Lua-state на 742 скрипта,
  убрать WASM OOM)
- Реализовать select/focus в иерархии для импортированных карт
- Touched events от Babylon impostor → Lua-shim сигналы
- Поддержка GUI (ScreenGui/Frame/TextLabel) в конвертере

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 21:13:16 +03:00
min
c31b1ed3d6 feat(studio): задача 05 — экран загрузки (Ken Burns + название места)
LoadingScreenOverlay: Ken-Burns фон (CSS pan+zoom) + 4 стиля (ken-burns/static/
parallax/particles) + карточка-композиция (cover/название места/автор/verified-SVG).
Стартовый экран при входе в Play (showStartupLoadingScreen из enterPlayMode +
поля проекта loadingScreen.* + serialize/deserialize). API game.loading.
setBackground/isVisible/onHide + расширенный show. UI редактора: секция
«Стартовый экран входа (Ken Burns)». Вики g5 #62 + статья. Тест-игра 2713.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 20:01:00 +03:00
min
e15dc56de3 fix(studio): self.delete снимает interact-подсказку (E больше не висит на пустоте)
_applySelfDelete удалял меш, но запись в _interactables оставалась → промпт
«E Собрать» висел на месте собранного предмета. Теперь запись чистится по ref.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:59:25 +03:00
min
42f1334908 feat(studio): задача 44 — drag-drop инвентарь (сетка 8×5 + hotbar 9 + стаки + редкости)
InventoryUI.js: DOM-оверлей — окно инвентаря по I (сетка 8×5), постоянный
hotbar 9 (клавиши 1-9), drag-drop между слотами (HTML5), стаки с maxStack,
5 редкостей (цвет рамки), tooltip на hover, ПКМ-меню (использовать/разделить/
выбросить), сортировка по редкости. API: game.items.define([...]),
game.inventory.give/take/open/toggle/sort/setActiveHotbar. onUseEffect heal/speed.
Сериализация scene.inventory2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:45:24 +03:00
min
854074bfa2 feat(studio): авто-floater над мобами + урон NPC от оружия (задача 40 доп)
game.fx.autoMobFloaters(true) — включает облачка урона над NPC при любой потере
HP (NpcManager.damage). NpcManager.damageByMesh — оружие (бластер/меч) наносит
урон скриптовым NPC (weapons.setOnHit → npcManager.damageByMesh). Связка:
выстрел бластера → урон NPC → авто-floater «-N» над целью.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:41:41 +03:00
min
458b6c3b59 feat(studio): задача 40 — damage floaters (game.fx.damageFloater)
FloaterManager.js: object pool (30 billboard-планов с DynamicTexture), tween
подъём+fade+покачивание, crit pop-scale, цвета damage/crit/heal/mana/miss,
стек одинаковых по stackKey (×N), комикс-стиль (BAM!/KAPOW!/POW! на звезде).
API game.fx.damageFloater(position, value, opts) — position {x,y,z} или ref/
'player'. Интеграция: tick в render-loop, resetRuntime при stop. Тест-игра
«Тренировочный полигон» id=2676.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 11:05:25 +03:00
min
ce6e69a2e8 fix(studio): saveProgress/loadProgress с JWT-заголовком (был 401 при сохранении прогресса)
loadProgress/saveProgress (лидерстаты/достижения) слали fetch без Authorization
→ 401 UNAUTHORIZED. Используют _economyAuthHeaders() (JWT игрока из localStorage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 10:01:38 +03:00
min
33cd435d06 feat(studio): прогресс лидербордов и достижений сохраняется в БД (между сессиями)
GameRuntime.saveProgress/loadProgress — helper к storys savegame endpoint
(/kubikon3d/savegame/<pid>/<uid>/<ns>) для движковых менеджеров.

- Достижения: при unlock сохраняются в БД (namespace _achievements) + localStorage
  как быстрый кэш; loadFromDB при Play восстанавливает разблокированные.
- Лидерстаты: статы текущего игрока сохраняются в БД (namespace _leaderstats,
  дебаунс 1с при set); loadFromDB при Play восстанавливает значения.
- Загрузка из БД через 250мс после старта скриптов (даём define зарегистрировать).

Теперь прогресс игрока подгружается при каждой сессии с любого устройства.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:59:11 +03:00
min
5d49cd9eeb feat(studio): задача 20 — лидерборды (leaderstats) + достижения (achievements)
Leaderstats: HUD-таблица top-right (blur, сортировка по primary, топ-10,
подсветка me, flash-инкремент). API game.leaderstats.define/set/add/get/
onChange + me.* (format number/time/short). LeaderstatsManager.js.

Достижения: toast справа (4 редкости + звук + очередь, slide-in/out), кнопка-
кубок слева-снизу → страница grid (locked grayscale+замок, hidden=?, прогресс-
бар). API game.achievements.define/unlock/has/bindToStat/setButtonVisible/
openPage. bindToStat(id, stat, {gte/lte/eq}) — авто-unlock по лидерстату.
Сохранение unlocked в localStorage по проекту. AchievementsManager.js.

Интеграция: оба менеджера в BabylonScene (tick leaderstats в Play, resetRuntime
при stop, serialize/load в project_data scene.leaderstats/achievements). worker-
API + GameRuntime cmd-обработчики + мост leaderstats.onChange→worker (globalEvent
leaderstatsChange) для bindToStat. Плеер пока НЕ портирован (по плану).

Тест-игра «Сбор монет с достижениями» id=2616 (is_test): поляна + 30 монет +
3 стата + 5 достижений (3 через bindToStat).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:32:53 +03:00
min
cf34f9cdb6 fix(studio): враг бьёт с анимацией удара, ключ исчезает при подборе
1+2) Враг с HP / волна врагов: радиус удара 3.5 (NPC останавливался на
     followGap=2.5, урон-чек d<2.5 не срабатывал). Добавлена анимация атаки —
     R15Animator.attack (выпад рукой), npc.setAttacking, NpcManager.setAttacking.
3) Ключ исчезает при подборе: scene.setVisible теперь парсит ref ('primitive:N')
   — obj.visible=false слал {ref} без kind/id, поэтому ключ не пропадал.
4) Машина — остаётся рантайм vehicle:car (особенность транспорта).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 20:26:11 +03:00
min
3bf1e77230 fix(studio): self.setLabel, дверь по коду (красивая+радиус), счётчик механик, ссылка на скрипт в консоли
1) Дверь по коду: красивая составная дверь (полотно+рамка+кодовая панель),
   поле ввода появляется ТОЛЬКО когда игрок в радиусе 6м (onTick по дистанции).
2) game.self.setLabel/clearLabel добавлены (кит «Метка с именем» падал
   'setLabel is not a function').
3) Плитка «Готовые механики» в тулбоксе считает киты динамически
   (GAMEPLAY_KITS.length), а не хардкод «12».
4) Консоль: ошибки/логи скриптов привязаны к источнику — справа строки
   кликабельная ссылка «📄 имя скрипта», открывает скрипт в редакторе
   (_log прокидывает scriptId/scriptName).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:27:09 +03:00
min
045f892aaa fix(studio): светофор (obj.color по ref), грядка растёт+зреет (obj.scale), кит скрытия HP
1) scene.setColor теперь принимает {ref} (obj.color=hex), не только {id}.
   Светофор переключал цвета через obj.color, но ref игнорировался → не работал.
2) Грядка: добавлен obj.scale (scene.setScale → mesh.scaling). Урожай после
   сбора исчезает, растёт за 5с (scale 0→1) и зреет цветом красный→зелёный,
   при полном размере снова собирается.
3) Кит «HP-бар» теперь сам прячет стандартный HUD HP (setHpVisible false).
   Новый кит «Скрыть стандартный HUD HP» — отдельно прячет дефолтную полосу.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:13:02 +03:00
min
71536668f2 feat(studio): задача 16 — кастомное небо (SkyboxManager)
Процедурный gradient-skybox без внешних текстур: купол-сфера с ShaderMaterial
(градиент верх→горизонт→низ + солнечный диск + дымка), low-poly горы на
горизонте, billboard-облака с дрейфом, атмосферный туман, звёзды.

Пресеты: clear-summer-day / lowpoly-roblox / cloudy / sunset / starry-night /
space. Плавный fadeTo между пресетами (анимация цветов купола в tick).

game-API (студия): game.scene.setSkybox/setClouds/setFog,
game.scene.skybox.fadeTo/setSunDirection. Сериализация неба в project_data.
Тик облаков/перехода работает и в редакторе (превью).

Плеер пока НЕ портирован (по указанию — сначала проверка в студии).
Тест-игра «Небесная демка» id=2541 (dev-режим is_test=true, не в ленте).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:17:23 +03:00
min
2fda576e11 feat(14): Vehicle System V1+V2 — машины, на которых можно ездить
All checks were successful
CI / Lint (pull_request) Successful in 1m9s
CI / Build (pull_request) Successful in 2m2s
CI / Secret scan (pull_request) Successful in 2m36s
CI / PR size check (pull_request) Successful in 8s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Система транспорта для Рублокс-студии (задача 14 Недели 4):
- VehicleManager — аркадная физика (газ/руль/тормоз/реверс), коллизия
  через physics.moveAABB; GLB-кузов Kenney car-kit (колёса в модели).
- VehicleHud — графический спидометр-стрелка (SVG, 270° дуга) + передача D/R/N.
- Вход hold-F / выход E; камера follow/капот/кинематографичная (V циклит).
- game.scene.spawn(vehicle:car, opts) + onVehicleEnter/onVehicleExit.
- Звук мотора: низкочастотный рокот (бас-пила + шум + LFO-пульсация тактов),
  pitch/громкость ∝ скорости — не воющий тон.
- Авто оседает на землю при спавне (_settle + повторы при поздней готовности
  физики) — не висит/не тонет.
- Водитель скрывается за рулём; падение в бездну → выход + респавн.
- Производительность: addShadowCaster фильтрует мелкие/тонкие/огромный пол меши;
  InstancedMesh без receiveShadows (фикс тормозов 5→50 FPS).
- Вики: карточка #61 «Такси-симулятор» + статья + 2 скриншота.
- incrementPlay(id, userId) — передаём user_id для self/user-cooldown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-06-03 02:24:43 +03:00
min
f0e284878e feat(13): главное меню игры (game.mainMenu)
All checks were successful
CI / Lint (pull_request) Successful in 1m19s
CI / Build (pull_request) Successful in 2m6s
CI / Secret scan (pull_request) Successful in 2m36s
CI / PR size check (pull_request) Successful in 8s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Живое 3D-меню как в топ-играх Roblox: cinematic-камера облетает витрину,
патч-ноуты, логотип, кнопка ИГРАТЬ, музыка, блок управления.
- game.mainMenu.show/hide/setCamera/setPatchNotes/onShow/onPlay/onHide
- 4 режима камеры: cinematic(waypoints)/orbit/static/preset-cuts поверх camera.cutscene
- зацикливание облёта через onCutsceneDone (камера не вылетает за сцену)
- game.player.setInputBlocked экспортирован в worker + handler в runtime
- passthrough scene.mainMenu в toJSON/load
- вики g5 #60 guide-garage, тест-игра «Гараж Босса» id 2434 (GLB-машина Kenney)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:07:33 +03:00
min
34060c90c3 feat(12): внутриигровой Loading Screen (game.loading)
All checks were successful
CI / Lint (pull_request) Successful in 1m13s
CI / Build (pull_request) Successful in 2m3s
CI / Secret scan (pull_request) Successful in 2m35s
CI / PR size check (pull_request) Successful in 8s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Программный экран загрузки для перехода между мирами:
- game.loading.show(opts) → хэндл (setProgress/setText/setCover/close/onSkip/onComplete)
- game.loading.transition(opts) → Promise (фейковый прогресс за duration)
- cover sceneSnapshot, прогресс-бар+процент, спиннер, кнопка Пропустить, логотип
- blockInput + пауза симуляции, fadeIn/Out; tick независим от paused
- настройки проекта «Экран загрузки» (логотип/акцент/дефолты) + 3 сниппета
- LoadingScreenOverlay.js (новый DOM-оверлей), worker namespace loading,
  cmd loading.* + _ensureLoadingScreen, serialize/load конфига в scene
- вики g5 #59 guide-taxi (карточка + урок), тест-игра «Такси-босс» id 2427

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:00:26 +03:00
min
ee1b7352b7 feat(11): placement mode — расстановка предметов (tycoon)
Some checks failed
CI / Lint (pull_request) Successful in 1m15s
CI / Build (pull_request) Successful in 1m58s
CI / Secret scan (pull_request) Failing after 9s
CI / PR size check (pull_request) Successful in 6s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Движок: PlacementManager (тень-превью формой воксельной модели за курсором,
снап к сетке, стопка, проверка зоны и баланса, поворот R/колесо, ПКМ/Esc),
ShopInventoryUi (магазин-слоты, авто-серые при нехватке валюты); проводка
game.placement.* и game.inventoryUi.* в worker/GameRuntime/BabylonScene.

Попутные фиксы:
- TerrainManager: backFaceCulling=false — воксели не просвечивают (видна была
  задняя грань сквозь переднюю);
- KubikonEditor: guard от потери userModels/scripts при частичной загрузке
  (terrain догрузился, модели/скрипт нет → автосейв затирал) — критичный
  фикс защиты данных для ВСЕХ игр;
- Hotbar: пустой инвентарь не показывает панель (глобальное правило);
- MinimapOverlay: миникарта только по флагу игры (не авто на больших картах);
- cleanup usermodel-инстансов при Stop.

Вики: карточка #58 + статья-урок «Мой завод» (g5 Разбор готовых игр),
openProjectId=2345, скриншоты залиты на прод.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 19:06:03 +03:00
76b2afd312 feat(10): живые 3D-надписи (attachFace) + витрина-лутбокс + вики
Some checks failed
CI / Lint (pull_request) Failing after 5s
CI / PR size check (pull_request) Successful in 12s
CI / Secret scan (pull_request) Failing after 14m51s
CI / Build (pull_request) Failing after 14m52s
CI / Deploy to S1 + S2 (pull_request) Has been cancelled
Движок: LabelManager attachFace (текст плоско на грань примитива, FRONTSIDE
без зеркала), tilt, 5 пресетов, richText; GameRuntime scene.move/scene.rotate
для моделей и примитивов; ScriptSandboxWorker obj.move/obj.rotate в Instance-
proxy; InspectorPanel настройки label. Вики: карточка #57 guide-dynamic-label
(Часовая башня) + полная статья-урок с разбором attachFace/obj.move/format.money.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 21:15:54 +03:00
7c95072e4f merge main into feat/studs-material-09
All checks were successful
CI / Lint (pull_request) Successful in 1m6s
CI / Build (pull_request) Successful in 1m56s
CI / Secret scan (pull_request) Successful in 2m33s
CI / PR size check (pull_request) Successful in 7s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
2026-05-31 14:03:54 +03:00
7ab66fc4c5 feat(09): сочные круглые studs (v4) + color-пикер окрашиваемых блоков
- Текстура studs v4: круглые кружки с усиленным объёмом (normal strength 4.0,
  запечённый блик/тень) + контактная тень от каждого кружка. Фон 0.97 — цвет
  остаётся сочным. emissive 45% от цвета на примитивах (Roblox-look).
- Версионные имена файлов (studs_v4_*) — обход browser-кэша Babylon.
- Color-пикер блоков: в палитре при выборе окрашиваемого блока (studs-block)
  под категориями появляется ряд из 8 лего-цветов + input «свой цвет».
  BabylonScene.setActiveBlockColor → addBlock(...,color) при постановке.
- DEV-хук ?dev=<имя> (localhost): грузит /dev-<имя>.json в редактор для
  локального теста без БД (на проде неактивен).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 12:22:03 +03:00
65aa26996d feat(09): материал studs + окрашиваемый блок studs-block + лего-сет
Задача 09 «Studs материал» (лего-кружки):
- PrimitiveManager: material 'studs' — diffuse-текстура (серые кружки) × цвет
  меша + normal map (выпуклость). Тайлинг _studsTiling по размеру меша
  (STUD_UNIT=1, GRID=4), пересчёт в _recreateMesh при ресайзе. _studsDims на меше.
- InspectorPanel: «Studs» 5-й материал в палитре примитивов.
- BlockTypes: studs-block ('Окрашиваемые', colorable:true, normal, defaultColor).
- BlockManager: per-instance color через ThinInstance color buffer
  (thinInstanceSetBuffer('color'), useVertexColors) — тысячи блоков любых цветов
  один draw call. addBlock(x,y,z,type,color), _setBlockColorAt/setBlockColor,
  serialize/loadFromArray с color, batch flush.
- GameRuntime: scene.setColor для блока (ref 'block:x,y,z'), spawn block с color.
- ScriptSandboxWorker: spawn блока прокидывает color.
- ModelTypes: лего-сет 19 compound-моделей (кирпичи/плиты/скаты/дерево/куст/
  дом/машина/ступеньки/человечек) — все части material:'studs'.
- Вики: карточка g5 #56 «Лего-полигон» + урок guide-lego.

Текстуры: public/kubikon-assets/materials/studs_{diffuse,normal}.png (в .gitignore,
доставить на S2 build/ вручную). Проверено визуально: куб 6×6 кружков, 2×2 блока
разных цветов, лего-дом/дерево/машина.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 11:10:58 +03:00
7c928462fc fix(engine): findOne(x).onTouch работает + findOne на старте скрипта
All checks were successful
CI / Lint (pull_request) Successful in 1m8s
CI / Build (pull_request) Successful in 1m56s
CI / Secret scan (pull_request) Successful in 2m31s
CI / PR size check (pull_request) Successful in 6s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Баг: стрелка-указатель game.fx.pointer не переключалась на следующую цель —
при касании цель не менялась, стрелка не выключалась.

Первопричина (две движковые проблемы):
1. findOne(x).onTouch(...) не существовал: Instance-proxy не имел методов
   касания, движок ловил touch только объектов со скриптом-target/триггеров.
2. Race: скрипт исполняется синхронно в init, а sceneSnapshot приходил позже
   (rAF) → findOne() на старте = null → подписки onTouch молча не вешались.

Фикс:
- Instance-proxy: + onTouch/onUntouch/onClick → шлёт inst.watchTouch{ref}.
  Worker: _instTouchHandlers + маршрут instTouch/instUntouch/instClick по ref.
- GameRuntime: handler inst.watchTouch/watchClick → _watchedTouchRefs;
  routeInstEvent(ref,type); сброс в teardown.
- BabylonScene._detectTouchEvents: блок watched-объектов (AABB по ref, rising/
  falling edge → routeInstEvent), _refToTarget(ref)→{kind,id},
  _touchState.clear() в enterPlayMode.
- Первичный snapshot сцены передаётся прямо в init
  (ScriptSandbox.setInitialScene → worker заполняет _sceneIndex до userFn) →
  findOne работает в синхронном теле скрипта на старте.

Проверено: телепорт игрока по 3 целям игры 333 — стрелка переключается
red-cube→blue-sphere→gold-chest, на финале удаляется.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 08:28:02 +03:00
e3e5960241 feat: 3D-стрелка-указатель (game.fx.pointer) + is_test + Ctrl+V в редакторе + вики-карточка
All checks were successful
CI / Lint (pull_request) Successful in 2m10s
CI / Build (pull_request) Successful in 1m58s
CI / Secret scan (pull_request) Successful in 2m33s
CI / PR size check (pull_request) Successful in 10s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
- game.fx.pointer: лента бегущих шевронов + парящий quest-marker над целью
  (конус остриём вниз, свечение, bob+вращение, обводка); presets guide/quest/
  danger/gift/custom; расширенный game.fx.beam (8 текстур, curved, градиент).
- Примитив pointer в палитре (Геймплей) + инспектор + _activatePointers при Play.
- is_test: переключатель «Тестовая игра» в GameSettingsModal (не течёт в каталог).
- Ctrl+V в Monaco-редакторе скриптов (guard на .monaco-editor + activeElement).
- Вики: карточка g5 «Туториал — собери монетки» (Разбор готовых игр).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 21:45:57 +03:00
42be04def9 feat(week4): модальные сцены, кастомные скины игрока и вики-гайды по 4 играм
Some checks failed
CI / Lint (pull_request) Failing after 1m10s
CI / Build (pull_request) Successful in 2m2s
CI / Secret scan (pull_request) Successful in 2m36s
CI / PR size check (pull_request) Successful in 6s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Задача 04 — модальные сцены (затемнение + GUI/3D-анимация + блок ввода):
- engine/ModalManager.js (state-машина, fade, spotlight-проекция, HighlightLayer)
- editor/ModalOverlay.jsx (CSS-overlay + mask-image для spotlight)
- PlayerController.setInputBlocked/setCameraFrozen/captureCameraState/focusOnTarget
- game.modal.open/close/update/isOpen/onClose + пресеты bossIntro/lootbox/dialog/confirmation
- Фиксы ядра: клик GUI-кнопок (realId↔localId), modalOpened через globalEvent,
  guard от двойного срабатывания колбэков, кнопка ✓ на последней строке диалога

Задача 07 — кастомные скины игрока + магазин:
- non-humanoid скины (любая 3D-модель): загрузчик, процедурная анимация,
  настраиваемый AABB, центрирование через pivot-node
- PlayerController.reloadSkin (смена скина в Play)
- game.player.setSkin/unlockSkin/getAvailableSkins/onSkinChange/openSkinShop + локальная валюта
- editor/SkinShopOverlay.jsx (встроенный магазин, клавиша B) + SkinManagerModal.jsx (вкладка «Скины»)
- сериализация scene.skins, кнопка «Скины» в тулбаре

Вики — категория «Разбор готовых игр»:
- docsGames.js: группа g5 + 4 карточки (Двор/Витрина GUI/Сундук/Парк)
- docsLessons.jsx: 4 подробные статьи-урока для детей
- «Открыть мою копию» создаёт копию проекта (оригинал не трогается)

Адаптивная ширина кнопки billboard под длинный текст.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 00:50:56 +03:00
c32914c819 feat: интерактивные 3D-таблички (BillboardGui/SurfaceGui)
Some checks failed
CI / PR size check (pull_request) Successful in 22s
CI / Lint (pull_request) Failing after 2m17s
CI / Secret scan (pull_request) Successful in 3m21s
CI / Build (pull_request) Successful in 3m31s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Задача 01 из 1 - Неделя 4/ЗАДАЧИ РУБЛОКС. P0-приоритет: без таблиц
с кнопками невозможны симуляторы, тайкуны, фермы.

Новое:
- engine/BillboardUiManager.js — 4 пресета (shop-item, shop-purchase,
  banner, sign), 18 иконок, DynamicTexture-рендер, UV-hit-test
- PrimitiveTypes: новый тип 'billboard' в категории 'gameplay'
- PrimitiveManager: case billboard в _createMeshForType (Plane), init
  через applyToMesh, billboardOpts в updateInstance
- BabylonScene: PointerEventTypes-handler для кликов с _isPlaying-чеком
  и pointer-lock поддержкой
- GameRuntime: команды billboard.set/update/onClick, callback через
  sandbox.sendEvent('billboardClick')
- ScriptSandboxWorker: пространство game.billboard.{set,update,onClick}
- BillboardEditorModal.jsx — модалка с живым canvas-превью, 8 готовых
  градиентов + кастомные пикеры, дропдаун из 18 иконок
- InspectorPanel: кнопка 'Редактировать табличку…' для billboard-примитива
- KubikonEditor: проброс модалки через onEditBillboard prop
- Icon.jsx: SVG prim-billboard

Два режима ориентации: 'camera' (BillboardGui-аналог, всегда смотрит
на игрока) и 'fixed' (SurfaceGui-аналог, прикреплён к поверхности).

Клик-детекция через ray-pick → UV → пиксели текстуры → поиск кнопки
по AABB; работает с пиксельной точностью даже при повороте камеры.

Документация: RUBLOX_STUDIO_FUNCTIONS.md раздел 1.25.

Тестовая игра 'Магазин апгрейдов' (4 таблички + банер + HUD) — МИН
соберёт в студии drag-n-drop'ом.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 11:58:06 +03:00
61fba4e174 fix: починка билда + studio.rublox.pro инфра
Some checks failed
CI / Lint + Format (push) Failing after 32s
CI / Build (push) Failing after 37s
CI / Secret scan (push) Failing after 37s
CI / PR size check (push) Has been skipped
Большой консолидирующий коммит после поднятия studio.rublox.pro (28 мая 2026).
Содержит изменения которые делались в процессе подготовки прод-окружения:

Фиксы импортов после выноса из minecraftia:
- Массовая замена путей ../../components → ../components (40+ файлов в src/community/, src/admin-preview/)
- Замена ../KubikonEditor/ → ../editor/, ../KubikonStudio/ → ../community/, ../AdminPreview/ → ../admin-preview/
- API.js скопирован из минки целиком (было 8 экспортов, стало 312)
- Добавлены PLAYER_URL, MyButton_1, недостающие компоненты
- Заменены require() на статические ES-imports в BabylonScene, PrimitiveManager, GameRuntime (Vite не поддерживает CJS require)

Структура ассетов:
- public/kubikon-templates/ → public/assets/kubikon-templates/
- public/kubikon-learn/ → public/assets/kubikon-learn/
- (код искал в /assets/, файлы лежали без /assets/)

Навигация роутов внутри студии:
- /kubikon-studio/docs → /docs (90+ навигационных вызовов sed-replaced)
- /kubikon-editor/X → /edit/X, /kubikon/play/X → /play/X, /kubikon/gd/X → /gd/X

UI:
- Новый компонент StudioHeader (61px, как в минке) + копия favicon
- WithHeader wrapper в App.jsx для всех страниц кроме fullscreen-редактора/плеера
- SSO ticket-flow в AuthContext (auto-redeem #ticket= при загрузке)
- Тёмная тема карточек игр в ВИКИ (фон #1c2231 вместо #fff, картинка впритык)

Документация:
- docs/ONBOARDING.md — путь нового контрибьютора от нуля до PR
- docs/TUTORIAL_ADD_SCRIPT_API.md — как добавить game.* API
- API_USAGE.md — список эндпоинтов backend
- README в подпапках engine/, engine/terrain/, engine/voxel/, engine/robloxterrain/, engine/types/

.gitignore:
- public/wiki/ исключён (73МБ PNG, будут на CDN отдельной задачей)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 05:01:13 +03:00
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