181 Commits

Author SHA1 Message Date
min
f46e6f0102 fix(studio): убрал 2 eslint-ошибки в main (showToast no-undef + text self-assign) — CI был красным для всех PR
Some checks failed
CI / Lint (pull_request) Failing after 28s
CI / Build (pull_request) Failing after 31s
CI / Secret scan (pull_request) Failing after 34s
CI / PR size check (pull_request) Failing after 32s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
2026-06-07 15:06:28 +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
c62073f7f8 chore: проверка CI с восстановленным runner (ubuntu-latest label)
Some checks failed
CI / Lint (pull_request) Failing after 37s
CI / Build (pull_request) Failing after 31s
CI / Secret scan (pull_request) Failing after 32s
CI / PR size check (pull_request) Failing after 36s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
2026-06-07 14:54:25 +03:00
min
661ff60bdf fix(studio): инвентарь — собранное идёт сначала в hotbar (виден), hotbar поднят над подсказкой
1) add() заполняет сначала hotbar, потом grid → собранные предметы сразу видны
   в постоянном хотбаре (раньше уходили в скрытую сетку — хотбар казался пустым).
2) Хотбар поднят bottom 14→64px, не перекрывает подсказку внизу экрана.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:51:27 +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
b1fbc3790e chore: re-trigger CI after runner restart
Some checks failed
CI / Lint (pull_request) Failing after 40s
CI / Build (pull_request) Failing after 29s
CI / Secret scan (pull_request) Failing after 36s
CI / PR size check (pull_request) Failing after 36s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
2026-06-07 14:43:27 +03:00
min
2645337bdd chore: e2e-тест workflow разработчиков после восстановления
Some checks failed
CI / Lint (pull_request) Failing after 3m7s
CI / Build (pull_request) Failing after 40s
CI / Secret scan (pull_request) Failing after 29s
CI / PR size check (pull_request) Failing after 39s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
2026-06-07 14:36:52 +03:00
min
48e2e83ef7 docs(studio): вики задача 40 — превью/скрин = кадр с облачками урона над зомби
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:22:11 +03:00
min
c20ac56895 docs(studio): вики задача 40 — обновлена под зомби-арену (бластер + autoMobFloaters + волны)
Карточка #64 «Зомби-арена — бластер и цифры урона» + статья переписана:
giveTool бластер, autoMobFloaters (авто-облачко над мобами), spawnNpc+follow
волны зомби, прицел в точку клика, ручной damageFloater (типы/стек/комикс).
Новые скрины scene/play (зомби-шутер).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:18:53 +03:00
min
931d53b4d9 fix(studio): бластер от 3-го лица стреляет в точку клика, а не в центр камеры
При свободном курсоре (нет pointer-lock, 3-е лицо) выстрел шёл из getForwardRay
(фокус камеры). Теперь onDown берёт координаты клика → setAimScreenPoint → луч
через точку клика; onMove обновляет _holdAim для авто-огня при удержании. При
pointer-lock (1-е лицо, курсор в центре) — прежнее поведение (центр).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:01:14 +03:00
min
e4fdd91b12 fix(studio): оружие попадает по NPC (pickable+npcId) → авто-floater урона работает
Меши NPC ставились isPickable=false → raycast бластера/меча проходил сквозь
них, урон и авто-floater не срабатывали. Теперь меши NPC pickable + npcId в
metadata; damageByMesh находит NPC по metadata (быстро) или по rootMesh.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:49:06 +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
c93070170b docs(studio): вики задача 40 — карточка #64 + статья «Тренировочный полигон (цифры урона)»
Карточка g5 #64 guide-floaters (openProjectId 2676) + статья: game.fx.
damageFloater, типы (damage/crit/heal/mana/miss), стек stackKey, comicStyle,
object pool. 2 скрина (scene/play) в public/wiki.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 11:08:28 +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
f8f0d976ef fix(studio): Ctrl+шорткаты не двигают камеру (Ctrl+D больше не уводит вправо)
onKeyDown клал любую клавишу в _codes (набор для WASD-движения камеры),
включая D при зажатом Ctrl → камера летела вправо при копировании. Теперь
клавиши с ctrl/meta в _codes не попадают.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:44:14 +03:00
min
6c0c3dc26e fix(studio): Ctrl+D дублирует объект РОВНО на месте оригинала (не смещает +1 по X)
duplicateSelected для model/userModel/primitive ставил копию на sel.x+1 →
визуальное смещение. Теперь копия появляется в той же точке (как Roblox Studio).
Block остаётся с поиском свободной клетки (воксель нельзя в занятую).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:38:34 +03:00
min
e477d652f6 fix(studio): mainMenu.show подхватывает opts.onPlay/onShow/onHide (порт)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:17:43 +03:00
min
ba90bf5c7d feat(studio): кит «Таблица лидеров» в Toolbox → Готовые механики
Новый кит (категория ui): определяет лидерборд (Очки primary + Время),
время идёт само, очки растут от broadcast('score'|'coins'). Сохраняется в БД.
Работает вместе со счётчиком монет/очков. Всего 47 китов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 10:11:18 +03:00
min
1c976ee870 docs(studio): вики задача 20 — скрины (scene/play), page заменён на текст
Скриншоты сцены (редактор) и геймплея (таблица лидеров) в public/wiki.
Страница достижений описана текстом (отдельного скрина пока нет).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 10:09:43 +03:00
min
7bb789f1af docs(studio): вики задача 20 — карточка #63 + статья «Сбор монет (лидерборды и достижения)»
Карточка g5 #63 guide-leaderstats (openProjectId 2616) + статья в docsLessons:
что получится, API leaderstats/achievements, 2 шага (таблица/достижения),
bindToStat, сохранение в БД. 3 скрина (scene/play/page) — донести вручную
(headless-студия не пускает после взлома, попрошу у пользователя).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 10:04:57 +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
c9498b086e fix(studio): SkyboxManager.hexToRgb поддерживает короткий хекс #fff (был NaN в облаках)
skybox.clouds.color='#fff' → substring(4,6)='' → parseInt NaN → addColorStop
'rgba(255,15,NaN,0.9)' падал при load → прерывал загрузку проекта. hexToRgb
теперь расширяет #fff→#ffffff и подстраховывает NaN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:49:01 +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
c4d184257b fix(studio): враг=NPC+урон, волна бьёт, удалённые скрипты не исполняются, ключ+дверь красивые, тени-acne
1) Враг с HP → R15-NPC (зомби-скин), преследует и бьёт игрока при касании.
2) Волна врагов: враги наносят урон при касании (onTick дистанция → damage).
3) Удалённые скрипты больше не исполняются: _cleanupOrphanScripts при удалении
   объекта (primitive/model/userModel) + перед enterPlayMode чистим скрипты-сироты.
4) Ключ и замок: ключ из примитивов (стержень+кольцо-torus+бородка), дверь
   как дверь-по-E (плавный поворот вокруг петли, только с ключом).
6) Тени-полосы: normalBias 0.005→0.02 (убирает acne-полосы от соседних объектов).

Машина (vehicle:car) — остаётся рантайм-спавном (особенность транспорта).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 20:12:50 +03:00
min
26e6306f6e fix(studio): дверь-код подсказка E только при открытой, NPC=R15-скин (анимация рук/ног), торговец видимый
1) Дверь по коду: подсказка «E закрыть» теперь только когда дверь открыта
   и игрок рядом (через onKey+onTick, без постоянного interact-промпта).
2) NPC-киты используют R15-скин 'skin_roblox-noob' → процедурная анимация
   бега/покоя с руками и ногами (R15Animator), вместо безжизненного покачивания.
3) Торговец-кит: невидимый триггер (insertGameplayKit теперь уважает
   prim.visible=false, раньше хардкод visible:true) + NPC-персонаж рядом —
   синий куб больше не виден.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:54:38 +03:00
min
9903719f9d fix(studio): дверь-код закрывается по E, NPC ходит с анимацией, торговец=NPC, тени короче
1) Дверь по коду: открытую можно закрыть по E (onInteract) → снова вводить код.
2) NPC: процедурная анимация ходьбы (покачивание по Y + наклон корпуса) для
   Kenney-моделей — раньше скользили без анимации.
3) Торговец переделан в NPC-персонажа (spawnNpc character-a) + невидимый
   триггер с диалогом по E (вместо примитивов).
4) Тени: убрана «полоса через всю карту» — autoCalcDepthBounds off,
   shadowMaxZ 90/60 (было 200/120), lambda 0.6, frustumEdgeFalloff 12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:47:27 +03:00
min
fe8b6b5b38 fix(studio): NPC-киты (robot→character-a), дверь по коду плавно распахивается
1) NPC-преследователь/торговец/волна: spawnNpc('robot') → 'character-a'
   (модели 'robot' не существует в ModelTypes → spawnNpc возвращал null → ошибка).
2) Дверь по коду: верный код → ПЛАВНОЕ открытие вокруг петли (как дверь по E),
   декор-панели вращаются вместе с полотном. Раньше полотно уезжало вниз,
   декор оставался.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:36:18 +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
018fce474b fix(studio): объекты больше не вываливаются из папки после Play/Stop (folderId в serialize)
Корень: serialize примитивов/моделей/userModel НЕ сохранял folderId. При
Play→Stop сцена восстанавливалась из снапшота без группировки → все части
кита (светофор/шипы/дверь) вываливались из папки в общие «Примитивы».
Добавлен folderId в serialize всех 3 менеджеров + восстановление в loadFromArray
(model/userModel явно, primitive через opts.folderId).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:00:36 +03:00
min
6ece149924 fix(studio): камера 3-го лица не цепляется за проходимые зоны (canCollide в metadata)
Зона опасности / триггеры (canCollide:false) ловились camera-clamp, и камера
прыгала к игроку внутри зоны. Причина: metadata примитива НЕ содержал
canCollide, а PlayerController._clampCameraToWorld проверяет md.canCollide.
Добавлен canCollide в metadata меша (+ синк при updateInstance).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:49:17 +03:00
min
2d669a3ff3 fix(studio): выделение папки раскрывает дерево + Delete удаляет всю папку с содержимым
1) При выделении папки (клик по сцене / вставка кита) дерево авто-раскрывается:
   workspace + цепочка родителей + scrollIntoView к строке папки. Раньше папка
   выделялась на сцене, но в свёрнутом дереве её не было видно.
2) Delete на выделенной папке (type='folder') → removeFolder(id, true) удаляет
   всю папку со ВСЕМ содержимым + _cleanupOrphanScripts чистит осиротевшие
   скрипты привязанные к удалённым объектам.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:36:55 +03:00
min
46414d874b fix(studio): кит спавнится на поверхности в фокусе + многочастный в папку + снятие выделения при Play
1) Предметы кита из тулбокса спавнятся на ТВЁРДОЙ поверхности под центром
   экрана (getPlacementPointAtCenter: raycast в пол/объект), а не под камерой.
2) Многочастный кит (дверь) теперь реально попадает в папку: insertGameplayKit
   ставил folderId, но дерево не пересобиралось (markDirty не трогает
   hierarchyDirtyRef) — добавлен hierarchyDirtyRef.current=true.
3) enterPlayMode снимает любое выделение редактора (объект/папка) + убирает
   пивот папки и gizmo — в Play больше нет подсветки выбранного.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:30:41 +03:00
min
bf93219266 fix(studio): клик по части папки выделяет всю папку + free-drag папки + удаление обновляет дерево + затухание длинной тени
1) Длинная тень-полоса: csm.frustumEdgeFalloff=8 — тень персонажа больше не
   тянется на весь пол.
2) Удаление примитива/модели/блока через ПКМ теперь обновляет дерево
   (markDirty + hierarchyDirtyRef) — раньше объект удалялся, но не пропадал.
3) Клик по СЦЕНЕ по объекту в папке → выделяется ВСЯ папка (selectByMesh
   проверяет folderId). Отдельную часть — через раскрытие папки в дереве.
4) Free-drag папки: зажал ЛКМ на группе и тянешь — двигается вся папка
   (moveFolderBy по дельте центра).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:19:02 +03:00
min
ed7310a532 feat(studio): +25 готовых механик из Вики (вся партия 3 — все остальные)
Добавлены все оставшиеся механики из TOOLBOX_KITS_FROM_WIKI.md:
Мир: зона опасности, шипы, светофор, грядка-урожай, падающие предметы.
Интерфейс: счётчик очков, HP-бар, дверь по коду (textbox), метка с именем,
  обратный отсчёт, 3D-стрелка-указатель.
Эффекты: костёр (particles fire), магнит монет.
NPC и бой (новая категория): преследователь, торговец (modal.dialog),
  мишень, враг с HP, волна врагов, диалог/кат-сцена, машина (vehicle:car).
Экономика (новая категория): магазин-кнопка, кликер, ключ+замок.

+2 категории китов (NPC и бой, Экономика). Всего ~37 китов.
Опущены «Главное меню» и «Экран загрузки» — требуют целой сцены, не «1 клик».
Все 45 скриптов прошли синтаксис-проверку, билд зелёный.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:55:32 +03:00
min
f270854795 feat(studio): +5 готовых механик (цветная плитка/лава/лифт/финиш/звук)
Партия 2 из TOOLBOX_KITS_FROM_WIKI.md:
- Цветная плитка — onTouch → смена цвета (self.setColor).
- Лава — onTouch/onUntouch → урон 15 HP/сек пока стоишь (player.damage).
- Лифт — onTick синусоида, ездит вверх-вниз 8 единиц.
- Финиш (победа) — onTouch → экран «ПОБЕДА!» + setInputBlocked.
- Звуковая плитка — onTouch → sound.play('coin') + подсветка.

game.self расширен: setColor(hex). Все 22 кита прошли синтаксис-проверку.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:31:49 +03:00
min
6938f83a3c fix(studio): декор двери поворачивается в ту же сторону (левосторонняя СК Babylon)
Ручка/филёнки уезжали на обратную сторону двери: формула поворота смещения
была правосторонняя, а Babylon mesh.rotation.y — левосторонняя. Единая rotY()
(wx=lx·c+lz·s, wz=-lx·s+lz·c) для полотна И декора → всё открывается синхронно
в одну сторону.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:23:35 +03:00
min
0e4fa89f40 fix(studio): декор двери (филёнки+ручка) вращается вместе с полотном
Декор-части находятся по имени (findOne), их локальное смещение от центра
полотна поворачивается вокруг той же петли в place() — теперь филёнки и ручка
открываются вместе с дверью, а не висят в проёме.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:20:15 +03:00
min
9a58c34303 feat(studio): красивая дверь (рамка+филёнки+ручка) + плавная анимация открытия
- Дверь теперь многочастная: полотно из тёмного дерева + 2 филёнки + золотая
  ручка + косяк-рамка (2 стойки + перемычка). Уходит в общую папку.
- Плавное открытие: постоянный onTick ведёт угол cur→target со скоростью
  ~0.5с на 90° (вместо мгновенного скачка). Поворот вокруг петли сохранён.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:16:46 +03:00
min
32cbb7bbe9 fix(studio): дверь поворачивается вокруг петли (как настоящая), а не отскакивает
Было: дверь сдвигалась вбок. Стало: вращение вокруг левой грани (петли) на
90°. Центр двери пересчитывается по дуге вокруг hinge (p0.z - halfW), плюс
self.rotate(angle) — дверь распахивается, как в реальности.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:51:36 +03:00
min
4906c82792 fix(studio): портал ищет второй портал по имени, дверь уезжает вбок
- Портал: вместо хардкода +8 по X — findOne('Портал B') в момент касания и
  телепорт к реальной позиции второго портала (его можно двигать куда угодно).
  findOne на старте давал null (sceneSnapshot через rAF) → искать в onTouch.
- Дверь по E: сдвиг вбок (+3 по X) вместо ухода вниз (выглядело как исчезновение).
  Текст подсказки «Открыть / закрыть».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:46:34 +03:00
min
cfc79f325f feat(studio): +5 готовых механик из Вики (батут/ускорение/портал/исчезающая платформа/дверь)
Партия 1 из TOOLBOX_KITS_FROM_WIKI.md:
- Батут (пружина) — onTouch → setVy(20) подброс вверх.
- Лента ускорения — onTouch → x2 скорости на 3с.
- Портал-телепорт — пара порталов, onTouch → teleport ко второму.
- Исчезающая платформа — onTouch → через 1с пропадает, через 3с возвращается.
- Дверь по кнопке E — onInteract → дверь уезжает вниз/возвращается.

game.self расширен: setVisible(vis) / setCollide(can) (нужны для исчезающей
платформы). Все скрипты прошли синтаксис-проверку (new Function).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 07:41:25 +03:00
min
6b857636c3 fix(studio): крестик закрытия Toolbox прижат к правому краю шапки
После переработки header убрал .headerInfo (flex:1), который раздвигал
заголовок и крестик → крестик прилип к названию. Добавил margin-left:auto
кнопке закрытия.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 07:28:32 +03:00
min
c7b5f3645d fix(studio): групповые манипуляции папки в реальном времени (не телепорт)
Дельта пивота применялась только в dragEnd → объекты телепортировались в
конце. Теперь _onFolderGizmoDrag применяет инкрементальную дельту на каждом
тике (setOnDrag) — движение/вращение/масштаб группы видно в процессе, как
у одиночных объектов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 02:53:35 +03:00
min
8b887e866a fix(studio): многочастные киты в папку + стартовая площадка задаёт спавн
- Кит из нескольких частей (сундук = тело+крышка) теперь кладётся в общую
  папку (folderManager.createFolder + assignToFolder), выделяется как группа.
  Раньше части лежали отдельно в корне.
- Кит «Стартовая площадка»: on-target скрипт телепортирует игрока НА площадку
  в начале игры (game.player.teleport через game.after 0.1с). Теперь игрок
  появляется на ней, а не в фолбэк-точке (0,0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 02:46:25 +03:00
min
4c8f8c99cb feat(studio): групповые манипуляции папки (выделение+move/rotate/scale всей группы)
Клик по папке в дереве → выделяется вся группа (подсветка всех объектов
внутри, рекурсивно по подпапкам) + групповой gizmo на пивоте в центре папки.
Манипуляторы двигают/вращают/масштабируют ВСЕ объекты папки сразу. Выбор
отдельной модели внутри — манипулирует только ей (как раньше).

- FolderManager: getFolderObjects (рекурсивный сбор + центр), moveFolderBy,
  scaleFolder (от центра, +размеры примитивов), rotateFolderY расширен на модели.
- SelectionManager.selectFolder → multi-подсветка + type:'folder' + пивот-gizmo.
- BabylonScene._attachFolderGizmo/_applyFolderGizmo: пивот-TransformNode,
  на dragEnd дельта (move/rotate/scale) применяется ко всей папке, пивот
  пересоздаётся в новом центре. Пивот убирается при смене выделения.
- Дерево: клик по строке папки = выделить группу; клик по шеврону = свернуть.

Многокомпонентные модели уже кладутся в авто-папку (ModelManager) — теперь
их можно двигать как единое целое.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 02:40:00 +03:00
min
7fc4ee94f6 fix(studio): удалённая точка спавна не появляется при Play + скрыта из дерева
Баг: после удаления точки спавна она всё равно появлялась при запуске.
Теперь _spawnEnabled синхронизируется в React (spawnEnabledUI) через
onSceneChange/load/setSpawn/deleteSpawn; пункт «Точка спавна» скрыт из дерева
когда удалён; player.start использует фолбэк (0,поверхность+2,0). Стартовая
площадка теперь срабатывает (игрок не телепортируется на старый спавн).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 02:33:15 +03:00
min
471af1cdeb fix(studio): сундук→счётчик монет через broadcast, удаление точки спавна + фолбэк 0,0
- Киты «Сундук» и «Счётчик монет» связаны через game.broadcast('coins',{add})
  + game.onMessage('coins') — раньше каждый кит в своём worker, счётчик не
  обновлялся (был globalThis, не работает между воркерами).
- Точку спавна теперь МОЖНО удалить: Delete (SelectionManager.deleteSelected
  обрабатывает type==='spawn' → scene.deleteSpawn) + ПКМ в дереве → контекст-
  меню «Навести камеру / Удалить точку спавна».
- Если точка спавна удалена (_spawnEnabled=false) — игрок появляется в
  (0, поверхность+2, 0). Постановка новой точки (setSpawnAtCamera) возвращает.
- spawnEnabled сериализуется в project_data.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 02:21:38 +03:00