Utility and polishing + bag fixes

This commit is contained in:
Oleksandr Vlasiuk
2026-08-14 15:03:43 +03:00
parent 250f4a0d2c
commit 1f72420da0
45 changed files with 2542 additions and 1618 deletions
@@ -0,0 +1,93 @@
# Камера з конфігу платформи стала реальною (2026-08-14)
Слайдери `camera_position_p/_l` і `camera_rotation_p/_l` у Scene settings були
мертві: `CameraFollowC.init()` рахував позицію з константи `CAMERA_OFFSET` і
виводив кут одноразовим `lookAt()`, а конфіг не читав узагалі. Продюсер міг
крутити шість повзунків без жодного ефекту.
Вимога: повзунки прибирати не можна, вони мають працювати — і в експорті, і в
прев'ю платформи.
## Що з'ясувалось під час розбору
**Формат конфігу читається не так, як виглядає.** У `globalSettings.ts` кожна
вісь масивного параметра описана як `[min, max, default]`, тому
`camera_position_p` виглядав як три трійки координат. Насправді дефолт — це
третій елемент кожної трійки, а в рантаймі `Template.getCategory("global")`
віддає плаский `[x, y, z]`. Перевірено прогоном справжнього
`formConfigForPlayable(formConfigUI(...))` над нашим же `globalSettings`.
**Старі дефолти були з іншої моделі камери.** `[-2, 5, 42]` — це абсолютна
позиція камери зі статичного SDK-шаблону. У грі з follow-камерою абсолютна
позиція безглузда (її перезаписує кожен кадр), осмислений лише офсет відносно
гравця. Оскільки ці значення ніколи ні на що не впливали, від них нічого не
залежало — семантику переінтерпретовано на офсет.
**`Object3D.lookAt` і `Camera.lookAt` — різні.** Перша спроба вирахувати
еквівалентний кут дала `x=53.13, y=0, z=0` і виглядала правдоподібно, але
контрольна перевірка (зібрати кватерніон назад із цих кутів і зміряти
`forward · напрямок_на_ціль`) дала **−1.0** — камера дивилась рівно в
протилежний бік. Причина в самому three.js:
```js
if (this.isCamera || this.isLight) _m1.lookAt(_position, _target, this.up);
else _m1.lookAt(_target, _position, this.up);
```
Звичайний `Object3D` наводить на ціль свою вісь **+Z**, камера — **−Z**. Розрахунок
на `Object3D` замість `PerspectiveCamera` дає дзеркальний результат.
**Урок**: будь-який офлайн-розрахунок орієнтації перевіряти зворотним ходом
(відновити з чисел і зміряти скалярний добуток), а не приймати правдоподібні
числа на віру.
Справжній кут для офсету `(0, 8, -6)` — `x=-126.87, y=0, z=-180`. Еквівалентна,
але читабельніша форма `x=53.13, y=180, z=0` дає той самий кватерніон і той
самий up-вектор — саме її записано в дефолти. `y=180` тут не довільне: риг стоїть
позаду гравця на −Z і дивиться назад у +Z, а камера three.js за замовчуванням
дивиться в −Z.
Тип параметра — `int`, тож `53.13` округлено до `53`. Відхилення від старого
кадру — **0.13°**, візуально непомітно.
## Що змінено
- `globalSettings.ts` — тільки дефолти (id, назви, типи й діапазони не чіпані;
діапазони вже покривали нові значення). Портрет і ландшафт отримали однаковий
риг, бо гра й досі використовує один `CAMERA_OFFSET` для обох — тепер їх можна
розвести з платформи.
- `CameraFollowC` — новий `applyRigFromConfig()`: читає офсет і кут за поточною
орієнтацією, застосовує кут, лишається єдиним писарем `camera.rotation`.
`readVec3()` відсіює биті значення, і тоді кут виводиться старим способом
(`frameTargetAndStoreRotation()`) — зламаний конфіг деградує до «кадрує
гравця», а не до порожнього неба.
- `beforeResourcesLoadedCb` — `updateVariableConfig` тепер маршрутизує
`camera_position_*`/`camera_rotation_*` у `CameraFollowC`, FOV лишається за
`CameraC`. Роздільна власність — це і є захист від повторення бага з двома
писарями.
- `resizeCb` — на зміні орієнтації перечитує і FOV, і риг.
- `DebugConfigC` — повзунки кута/дистанції сідають із того самого конфігу
(`readCameraRigFromConfig()`), дубльована константа `DEFAULT_CAMERA_OFFSET`
прибрана. `setOffset()` і далі авто-кадрує й синхронізує `rotationDeg`.
- `TestSceneC.CAMERA_OFFSET` — лишився як фолбек, коментар оновлено.
## Перевірено
- `npx vite build` — 886 модулів, чисто.
- Прогін реального SDK-пайплайна: гра читає `camera_position_p = [0, 8, -6]`,
`camera_rotation_p = [53, 180, 0]`; відновлена з цих чисел камера дивиться на
гравця з похибкою 0.13°.
- `npx tsc --noEmit` у проєкті **не запускається** — `tsconfig.json` містить
`moduleResolution: node10`, яку TypeScript 7 видалив (TS5108). З обходом цієї
опції лишаються дві доіснуючі помилки, обидві не в зміненому коді:
deep-import `three/src/math/Color` у `ThreeC.ts` і застаріла декларація SDK для
`JoystickC.init({ color })`.
## Не перевірено
Візуально в браузері нічого не запускалось. Потрібен ручний прогін: старт у
портреті, поворот у ландшафт, правка повзунків на платформі наживо.
## Відкрите
Значення, збережені для вже наявних креативів на платформі, лишились у старій
(абсолютній) семантиці — їх треба одноразово перевиставити на офсет-значення.