After backend CORS rollout users had stale CORS-failure cached for
Mixamo GLB. Adding a query suffix forces browsers to re-fetch the URL
instead of replaying the cached failure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Этап 1 плана анимаций (ANIMATIONS_PLAN.md):
CROUCH (Ctrl):
- При зажатии Ctrl персонаж приседает, AABB → 0.45
- Скорость в crouch = 0.45×walk, crouch имеет приоритет над sprint
- Анимации: crouch_enter (one-shot) → crouch_idle / crouch_walk
- При вставании: crouch_to_stand (one-shot, если не движется)
- Y-drop для разных Mixamo-клипов (crouch_idle: -0.45, walk: -0.25)
- Anti-flicker debounce 120ms в MixamoAnimator
FULLSCREEN + СТАРТ-ЭКРАН:
- При запуске игры показывается оверлей "Нажми чтобы играть"
- Клик → requestFullscreen() → Chrome блокирует Ctrl+W/D/T/R/S и др.
- В fullscreen Esc отдаётся браузеру (выход), меню открывается на Tab
- Без fullscreen — Esc открывает меню как обычно
- BottomBar динамически показывает Esc/Tab в зависимости от режима
СКИН ЮЗЕРА:
- Приоритет: URL #skin=<id> → БД (rublox_equipped_skin) → localStorage → skin_y-bot
- В Esc-меню "Участники" Mixamo-скины грузят PNG с /character-assets/skins/
MIXAMO ANIMATOR:
- Полный класс с lazy-loading 35 состояний
- AnimationGroup loop=true через onAnimationGroupEnd safety-net
- crossFadeFrom для плавных переходов
- Жёсткий stop всех не-current групп → нет фантомных анимаций
LOCAL DEV: при запуске на localhost плеер берёт скин из:
1) hash-параметра #skin=<id> (сайт 3000 передаёт его при play-ticket
через buildPlayerUrl(gameId, ticket, selectedSkin))
2) localStorage самого плеера (rublox_selected_skin)
3) дефолт skin_y-bot
Это нужно потому что:
- localStorage на :5173 (плеер) и :3000 (сайт) — РАЗНЫЕ хранилища
- В прод-БД пока legacy-скины (skin_sigma-labubu и др.), пока feature-flag
RUBLOX_NEW_SKINS_AVAILABLE=false плеер не должен в неё лезть локально
PROD: только БД (rublox_equipped_skin) — поведение не меняется.
Также убран beforeunload-prompt: системное окно браузера невозможно
стилизовать (Chrome игнорирует кастомный текст с 2017), а уродливое
окно мешало. Случайное закрытие вкладки теперь без подтверждения.
Что:
- _resolveModelSource:
* Mixamo (skin_y-bot/x-bot/eve/...) → /character-assets/skins/<id>.glb
(с rublox-site, non-humanoid-rigged kind)
* Legacy R15 (skin_bacon-hair, skin_sigma-labubu и др.) — сохранена
старая ветка через manifest + /kubikon-assets/. Это нужно пока
бэк storys работает в legacy-режиме (RUBLOX_NEW_SKINS_AVAILABLE != true).
- skinFolderRef.current default: skin_bacon-hair → skin_y-bot
- BabylonScene._playerModelType default + миграция character-* → skin_y-bot
- PlayerController._modelTypeId default → skin_y-bot
- MultiplayerSync: все дефолты → skin_y-bot
LOCAL DEV:
- На localhost плеер сначала пробует localStorage('rublox_selected_skin')
(тот же ключ что в rublox-site), потом БД. Это позволяет тестить выбор
скина в сайте без записи в прод-БД.
Зависит от:
- PR storys (новый бэк-резолв + feature-flag)
- PR user (endpoint /<id>/gender)
- Заливки 80 GLB на rublox.pro/character-assets/skins/ (отдельная инфра-задача)
Из merge остались два блока объявлений задачи 20 → 'Identifier _lsMirror already declared' в Web Worker → ВСЕ игры запускались без скриптов. Убрал переобъявление во втором блоке.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GraphicsManager (постобработка/материалы/API game.graphics) — паритет со студией,
применяется при загрузке игры если автор настроил. Новые материалы chrome/water/
iridescent. Realtime-эндпоинт переведён на game.rublox.pro (S1 NPM прямо, без
hop через S2 — чинит разрывы WebSocket). MultiplayerSync улучшен.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Главное по задаче 05: переделан React loading-оверлей в KubikonPlayer (тот,
что игрок видит после клика «Играть» пока грузится игра). Новый компонент
GameLoadingScreen: Ken Burns фон + карточка-витрина + название места + автор
+ verified-галочка + прогресс-бар (реальный 0→100%) + спиннер. Данные:
project_data.scene.loadingScreen (настройки автора из студии) → мета игры
(title/thumbnail/автор) → дефолт. 0 ошибок, проверено headless.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Порт LoadingScreenOverlay (Ken-Burns/4 стиля/карточка/verified) + старт-экран
при входе в Play + API game.loading.setBackground/isVisible/onHide. Идентично
студии. worker SOURCE синтаксис проверен. Проверено headless в плеере (0 ошибок).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Корень инцидента 2026-06-07: .env.production был в .gitignore → CI-сборка
без VITE_API_BASE → API base падал на window.location.origin (rublox.pro)
вместо minecraftia-school.ru. redeem-ticket уходил на rublox.pro/api-user
(нет такого) → плеер не получал JWT → выбивал на /app через секунду.
Файл содержит только публичные URL, секретов нет.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
show() игнорировал колбэки из опций — onPlay из mainMenu.show({onPlay}) не
регистрировался, кнопка ИГРАТЬ ничего не делала. Теперь опции-колбэки пушатся
в _onPlay/_onShow/_onHide.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ReferenceError: require is not defined при game.self.setLabel/scene.setLabel
в плеере. Заменён require('./LabelManager') на статический import (как в студии).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LeaderstatsManager + AchievementsManager скопированы в плеер, интегрированы
в BabylonScene/worker/GameRuntime (те же точки, что в студии): HUD-таблица,
toast, кубок+страница, bindToStat, сохранение прогресса в БД (savegame, JWT),
мост onChange→worker. Прогон 2616 в плеере: таблица в DOM, 0 ошибок. Полная
фича-парность задачи 20.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>