fix: deterministic physical item motion in 3D demo

Add physicalItemMotion as the single source of item pose, synchronize belt/item speed at 1 m/s, route items through chutes, keep C/D items settled inside roll-cages, render historical settled items, and use STL models with explicit fallbacks.
This commit is contained in:
root
2026-07-09 16:37:38 +02:00
parent 39dc11c773
commit 1528cfce10
24 changed files with 567 additions and 170 deletions

View File

@@ -0,0 +1,46 @@
# Iteration Visual QA Report
Date: 2026-07-09
Branch: `dan_branch`
Scope: one limited 3D demo improvement cycle for `https://arhipovdan.ru/`.
## Before / After Screenshots
Screenshots saved in `docs/visual_qa_screenshots/`:
- `before_initial_production.png` — production initial state before playback.
- `after_running_item_on_belt.png` — production after deploy, item moving on belt.
- `after_cv_overlay_no_overlap.png` — production after deploy, CV overlay visible without HUD overlap.
- `after_demo_complete_8_cases.png` — production after deploy, all 8 cases completed.
- `after_details_page.png` — `/details` production check.
## Top 3 Issues Fixed
1. Conveyor/item timing did not read as 1 m/s: movement phases were retimed to physical distances, and belt animation now runs only while the item is moving.
2. Items looked like route-colored cubes: STL/procedural item materials now use product-like surfaces with subtle route-colored outlines instead of category-color body fill.
3. CV overlay could overlap the top-right HUD: the measurement overlay now lives on the left side with bounded height.
## Verification
- `npm run build` — passed.
- `npm run test` — passed, 11 test files / 113 tests.
- `docker compose -p owl -f docker-compose.server.yml up -d --build` — passed, `owl-web-1` recreated and started.
- Playwright production QA — passed with `NO_CONSOLE_ERRORS`.
## Acceptance Checklist
- [x] No console errors.
- [x] Item does not fly.
- [x] Item does not fall through the belt.
- [x] STL/procedural items are visible and no longer read as route-colored cubes.
- [x] Belt and item movement are synchronized during movement phases.
- [x] HUD and CV overlay do not overlap.
- [x] Play starts the demo.
- [x] `/details` works.
- [x] Before/after screenshots exist.
## Notes
- No changes were made to `/details`, nginx, Dockerfile, classifier logic, or scenarios.
- No physics engine was added.
- No commit or push was made.

View File

@@ -0,0 +1,35 @@
# Physical Motion Fix Report
## Причины предыдущего хаоса
Ранее движение товара рассчитывалось независимо по осям с использованием интерполяции между хардкодными точками, что приводило к телепортации или "зависанию" объектов (в том числе над корзиной). Также отсутствовала система хранения объектов после завершения их этапа маршрутизации. Указанные в `ModelAssets` STL-модели загружались, но отображались некорректно. Из-за отсутствия независимой физической модели каждый фрейм пытался обновлять позиции локально.
## Решение
1. **Создана `physicalItemMotion.ts`** — единая физико-кинематическая модель `getPhysicalItemPose`. Она гарантирует детерминированное вычисление `[x,y,z]` и вращения на основе `elapsedMs`, отсчитанного от момента спавна товара, а также `CONVEYOR_SPEED_MPS` (1 м/с).
2. **Синхронизация ленты и товара**: Время и расстояние на ленте точно соответствуют $d = 1.0 \times t$. Движущаяся текстура ленты использует эту же скорость.
3. **Хранение (settled) элементов**: В `SorterDigitalTwinContinuous.tsx` теперь рендерятся все созданные (spawned) объекты за последние 20 циклов. Объекты попадают в корзину `C` или `D` по желобу (`chute`), меняя высоту, и остаются там (isSettled).
4. **STL модели**: Добавлен единый компонент `PhysicalPlaybackItem.tsx`, который грузит `STLGeometry` или использует `FallbackPrimitive` в случае их отсутствия, применяя при этом корректные материалы с реалистичным `roughness` и `metalness`.
## Подтверждение
- Скорость товара 1 м/с подтверждена тестами в `physicalItemMotion.test.ts`.
- Объекты остаются внутри cage благодаря смещению на базе `slotIndex`.
- Fallback применён только к отсутствующим или "heavy" STL. (Короб 300, 400, Тарелка, Бутылка, Цилиндр, ЛанчБокс — STL).
## Результаты QA и сборка
- `npm run build` — Успешно (0 ошибок).
- `npm run test` — Успешно (117 тестов пройдено).
- `docker-compose` — Контейнеры пересобраны и запущены.
- Production QA Script завершен с 0 ошибок консоли (`NO_CONSOLE_ERRORS`).
Скриншоты лежат в папке `docs/physical_motion_fix_screenshots/`:
- `stl_models_visible.png`
- `belt_sync_t0.png`
- `belt_sync_t1.png`
- `item_on_belt_no_flying.png`
- `route_to_c_chute.png`
- `item_settled_in_c_cage.png`
- `route_to_d_chute.png`
- `item_settled_in_d_cage.png`
- `no_overlay_overlap.png`
- `demo_complete_items_not_chaotic.png`
Ограничения: `slotIndex` использует простую матричную сетку 3xN, что при сильном переполнении корзины может вызвать небольшие наложения (clipping) STL-моделей друг на друга, но это визуально приемлемо и объекты остаются строго внутри корзины.

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB