# 시대별 충돌 교체 검증

2026-10-02. 릴리스 `local-4d5905679d2e-de5de5063e49`의 로컬 프로덕션 빌드에서 Playwright MCP의 별도 브라우저로 확인했다. 일반 성능 순위를 매기는 시험은 아니다.

## 시험 장면

장면 선택에서 **시대별 벽 · 전환 시험**을 선택한다.

- Three.js BVH: `http://127.0.0.1:5173/?scene=era&controller=bvh`
- Three.js Rapier: `http://127.0.0.1:5173/?scene=era&controller=rapier`
- PlayCanvas Ammo: `http://127.0.0.1:5174/?scene=era`

같은 바닥 위에서 현재의 황색 벽은 z=-7 m, 과거의 벽은 z=-10 m에 놓인다. W로 현재 벽까지 이동하고 과거로 바꾸면 앞의 벽이 사라져 더 이동할 수 있다. 과거 상태에서 현재 벽이 생길 자리에 서서 현재로 바꾸면 시작점으로 안전 이동한다. 이 장면은 충돌 교체를 확인하는 합성 시험이며 역사적 복원이 아니다.

## 결과

| 확인 항목 | BVH | Rapier | Ammo |
| --- | --- | --- | --- |
| 현재 벽에서 정지 | 통과 | 통과 | 통과 |
| 과거 전환 후 사라진 벽 통과, 새 벽에서 정지 | 통과 | 통과 | 통과 |
| 겹침 없는 전환의 위치·시선 유지 | 통과 | 통과 | 통과 |
| 새 벽과 겹치면 시작점 이동·안내 | 통과 | 통과 | 통과 |
| 대상 요청을 1.8초 지연해도 전환 중 W 이동 차단 | 통과 | 통과 | 통과 |
| 패널 닫기, 중복 전환 차단, 시대별 핫스팟 교체 | 통과 | 통과 | 통과 |
| 대상 요청 실패 시 이전 화면·충돌 복구, 입력 복구·재시도 | 통과 | 통과 | 통과 |
| 전환 후 충돌 면 표시와 촬영 화면 복귀 | 통과 | 통과 | 통과 |

현재/과거 벽 앞의 발 z 좌표는 BVH -6.600/-9.600 m, Rapier -6.590/-9.590 m, Ammo -6.600/-9.600 m였다. 캡슐 반경과 컨트롤러 여유 거리 때문에 벽 중심까지 이동하지 않는 것이 정상이다.

[측정 JSON](measurements/2026-10-02/era-collision-switch.json), [이동 재현 스크립트](measurements/2026-10-02/era-switch-driver.js), [지연·실패 재현 스크립트](measurements/2026-10-02/era-switch-failure-driver.js), [PlayCanvas 과거 화면](measurements/2026-10-02/era-playcanvas-historical.png).

`pnpm check`의 자산 검증, 단위 테스트, 타입 검사, 두 앱의 빌드·릴리스 산출물 검사를 통과했다.

## 구현 중 발견한 문제

PlayCanvas에서 화면용 GLB와 충돌용 GLB에 별도 Asset을 만들었지만 URL이 같으면 내부 ContainerResource가 공유됐다. 화면 교체 때 Asset을 해제하자 충돌에 사용하는 render 자산까지 파괴되어 Ammo가 오류를 냈다. 종류·URL별로 소유자를 하나로 합치고 충돌·공통 화면 자산을 고정 보유하도록 수정한 뒤 위 시험을 다시 통과했다. 공간 분할에서도 공유 자산의 수명을 명시적으로 관리해야 한다.

## 검증 범위와 남은 제한

- 시대별 충돌 GLB는 시작 시 모두 읽는다. 공간별 다운로드·해제는 다음 시험에서 확인한다.
- 겹침 판단은 작성자가 지정한 세계 좌표 `transitionBounds`와 캡슐의 외접 상자를 사용한다. 보수적인 안전 정책이며 실제 메시의 정밀 겹침 판정은 아니다.
- 공통 바닥을 유지했다. 시대에 따라 바닥이 사라지는 경우와 안전 위치까지의 경로 탐색은 확인하지 않았다.
- 자동 시험의 시선은 초기 각도였다. 비영점 시선·모바일에서의 전환은 추가 확인이 필요하다.
- 전환 요청 실패를 의도적으로 발생시킨 오류 로그는 정상적인 실패 시험의 근거다.
