SOTAESAN ATLAS

Markdown 원본 다운로드

iPhone 11 모바일 비교

확인된 결과

2026-10-02 USB로 연결한 실제 iPhone 11 Safari에서 Playwright MCP와 Web Inspector CDP bridge로 시험했다. 작은 공통 장면에서는 세 구현 모두 열렸고, 정지 상태 p95 프레임 간격은 PlayCanvas 52ms, Three.js BVH 65ms, Rapier 78ms였다. 이 조건에서 PlayCanvas의 프레임 간격이 더 짧았다. 모바일의 최종 엔진 선택을 확정하는 결과는 아니다.

이동 시험에서는 세 구현 모두 시험용 충돌 바닥 밖으로 나갔다. Three.js는 자동 낙하 복구가 작동했지만 PlayCanvas는 계속 떨어졌다. PlayCanvas 이동 수치는 정상 보행 비교에서 제외한다. Three.js의 이동 수치도 복구 횟수와 실제 경로가 달라 동등한 작업량의 비교로 사용하지 않는다.

큰 Sunnyvale 장면은 PlayCanvas에서 두 차례 준비 완료를 확인했다. Three.js BVH에서는 준비가 끝나지 않았다. 모바일에서 해결할 우선 과제는 대형 SOG 로딩 실패 처리와 바닥 밖 낙하 복구, 작은 화면의 조작 UI다.

시험 조건

항목 조건
기기 물리 iPhone 11, 기기 조회 iOS 27.0.1 / 24A446
브라우저 Safari / WebKit, UA의 Safari 버전 27.0.1
GPU Apple GPU, WebGL 2.0
화면 세로 375×616 CSS px, 기기 DPR 2
앱 렌더링 DPR 상한 1.5, drawing buffer 562×924
릴리스 local-4d5905679d2e-6df18be3ac38
공통 장면 Knock Hall, 900,000 Gaussian SOG, 수동 프록시 충돌 24삼각형
실행 한 Safari 시험 탭에서 BVH → Rapier → PlayCanvas 순서
반복 구현마다 정지 30초×3회, 이동 30초×3회
입력 canvas에 합성 DOM TouchEvent, 실제 손가락 입력 아님

Mac의 로컬 preview 서버를 iPhone IP 192.168.1.119만 허용하는 임시 relay로 전달했다. 6173은 5173, 6174는 5174로 연결했다. Chrome 확장이나 사용자 Chrome은 사용하지 않았다.

모든 측정에서 document.hidden=false였고 숨김 프레임과 visibility 변경은 없었다. 그러나 document.hasFocus()=false가 계속 보고됐다. 포커스가 확보된 시험이라고 표현하지 않는다. 원격 디버거가 연결된 상태이며, 온도·배터리 상태·실행 순서·캐시는 통제하지 않았다. OS 버전은 기기 조회를 사용했다. UA의 OS 18_7과 bridge가 제공하는 가상 Chromium/V8 식별자는 실제 OS나 렌더러 버전으로 사용하지 않는다.

정지 상태 측정

각 구현의 30초 구간 3개에서 수집한 requestAnimationFrame 간격을 합쳐 계산했다. 구간별 p95의 평균이나 중앙값이 아니다. p95가 작을수록 긴 프레임 지연이 짧다. 앱 준비 표시는 GPU 첫 표시 완료 시간과 다르다.

구현 프레임 수 평균 간격 ms p95 ms p99 ms 구간별 p95 ms
Three.js BVH 1,509 59.53 65 68 67 / 65 / 64
Three.js Rapier 1,540 58.39 78 81 58 / 81 / 61
PlayCanvas Ammo 2,242 40.09 52 55 54 / 49 / 49

Rapier의 두 번째 정지 구간은 다른 두 구간보다 느렸다. 순서 교대·온도 통제가 없는 세 반복으로 이 차이를 물리 엔진만의 영향이라고 단정할 수 없다.

정지 상태 처리 시간

각 구간의 walkingTimings.totalMs 증가분을 실제 측정 경과 초로 나눴다. 호출당 시간은 같은 증가분을 호출 수로 나눴다.

구현 계측 경과 ms / 실제 1초 호출당 평균 ms 포함 범위
Three.js BVH 52.14 3.10 앱 보행 step
Three.js Rapier 124.58 7.27 앱 보행 step 및 연결된 Rapier 처리
PlayCanvas Ammo 61.13 2.45 PlayCanvas rigidbody system step

이는 계측 함수 안에서 흐른 시간이며 프로세스 CPU 사용률·배터리 소모·물리 엔진만의 비용이 아니다. PlayCanvas는 전체 rigidbody system, Three.js는 앱 보행 step을 계측하므로 포함 범위가 다르다. Safari 시간 표본은 원본에서 1ms 단위로 나타나 작은 호출의 오차도 고려해야 한다.

이동 시험에서 발견한 문제

매번 시작점으로 복귀하고 1.5초 대기한 뒤, 전진·오른쪽·후진·왼쪽을 각 7.5초씩 입력했다. 동일한 입력 순서가 동일한 이동 경로를 보장하지 않는다. 이 장면의 프록시 바닥은 촬영 장면 전체를 덮지 않는다.

구현 원본 이동 p95 ms 관찰 성능 비교 판정
Three.js BVH 60 전체 시험 종료 시 자동 복구 누적 4회 경로·복구가 달라 동등 비교에 사용하지 않음
Three.js Rapier 62 전체 시험 종료 시 자동 복구 누적 15회 경로·복구가 달라 동등 비교에 사용하지 않음
PlayCanvas Ammo 43 각 30초 종료 발 높이 약 −1,075 / −1,024 / −1,007m 정상 이동 비교에서 제외

PlayCanvas는 후진 구간부터 바닥 밖으로 떨어졌고 마지막 구간까지 낙하했다. 카메라도 장면에서 멀어지므로 렌더링과 접촉 작업량이 줄어들 수 있다. 따라서 43ms를 PlayCanvas 정상 이동 성능으로 인용하면 안 된다. 시작점 버튼으로는 복귀했다. 이 측정 릴리스에는 수동 복귀만 있었고 자동 낙하 복구는 없었다. 이후 수정은 아래 기능 검증에 기록했다.

측정 구간에서 세 구현 모두 수집된 페이지 예외·unhandled rejection·WebGL context loss는 없었다. 이는 이동이 정상이라는 뜻이 아니다. 좌표를 확인해야 위의 실패를 찾을 수 있었다.

후속 이동 비교는 바닥 안의 짧은 왕복이나 고정 외벽 밀기로 제한하고, 접촉·좌표·복구 횟수를 검증한 뒤 수행한다. 자동 낙하 복구를 추가한 릴리스의 모바일 성능은 다시 측정해야 하며 기존 표본에 합치지 않는다.

큰 장면: Sunnyvale

3,999,361 Gaussian SOG, 충돌 메시 337,680삼각형 장면을 별도로 열었다. 아래 관찰은 캐시를 초기화한 cold/warm 로딩 비교가 아니다.

진단 로딩에만 probe=worker를 주입했다. 작은 장면 성능 측정에는 이를 사용하지 않았다. Spark worker의 실패가 로딩 대기를 끝내지 못하는 경로에 앱의 시간 제한과 새 페이지 재시도를 추가했다. 아래 기능 검증은 실패 대응을 확인한 것이며 iPhone 대형 장면의 디코딩 원인과 자산 처리 전략은 추가 조사가 필요하다. 메모리 부족을 확정 원인으로 기록하지 않는다.

수정 후 기능 검증

릴리스 local-4d5905679d2e-882e63d01db8에서 두 가지 실패 대응을 추가했다. 별도 headed Chromium과 Playwright MCP로 검증했으며 GPU는 Apple M4 Pro의 ANGLE Metal이었다. 데스크톱 기능 검증이며 iPhone 성능 재측정이 아니다.

Three.js 로딩 오류와 재시도

시간 제한은 대기를 끝내는 장치다. SDK 디코더를 고치거나 즉시 worker 작업을 취소하는 기능은 아니다. iPhone에서 Sunnyvale 로딩이 성공하는지는 아직 확인하지 않았다.

PlayCanvas 낙하 복구

이는 시험 장면 밖으로 떨어질 때의 안전장치다. 충돌 바닥의 빈 부분이나 계단을 보완하지 않으며, 시작점보다 10m 낮은 정상 지형에서도 복귀할 수 있다. PlayCanvas는 시작점으로, 기존 BVH·Rapier는 마지막 안전 위치로 복귀하므로 복구 경로를 동일하게 취급하지 않는다.

pnpm check에서 테스트 43개, 자산 검증, 타입 검사와 두 앱 빌드가 통과했다. 브라우저 기능 검증 근거: 원본 JSON, Three.js 시간 초과 화면, PlayCanvas 복구 후 이동 화면.

모바일 화면과 남은 확인

대형 장면의 후속 대조 시험에서는 Sunnyvale의 점 수를 유지하고 고차 SH만 제거한 버전이 47.320초에 준비됐다. 90만 점 축소본도 성공했다. 원본 호환성 문제는 아직 해결되지 않았으며, 위 원본 실패 기록을 대조군 성공으로 대체하지 않는다. 해독 대조 시험.

종료 스크린샷에서 데스크톱용 안내 패널이 세로 화면의 큰 부분을 덮는다. PlayCanvas 작은 장면 패널 높이는 약 441px로 616px 화면의 약 72%다. Three.js는 추가 컨트롤러 선택 때문에 더 길다. 안내 문구도 WASD 중심이다. 모바일에서는 도움말·진단을 접고 터치 조작 안내를 제공할 필요가 있다.

overlay 자체는 pointer-events:none이며 버튼·select만 입력을 받는다. 시험 터치 시작 좌표의 hit-test는 canvas였다. 따라서 패널이 시야를 덮는 문제와 터치 입력을 막는 문제를 혼동하지 않는다.

아직 확인하지 않은 항목:

재현과 근거

bridge는 임시 환경의 pymobiledevice3 11.20.2로 실행했다. 승인된 프로젝트 시험 탭만 대상으로 Runtime.evaluate와 Page.captureScreenshot을 사용했다. isolated world의 page.evaluate는 이 bridge에서 실패했다. 작은 장면을 열고 측정 함수 실행 후 진행 상태를 폴링하며, 탐색 전 원본을 저장한다. 입력 생성자는 실제 손가락을 대신하지 않는다. 시험 종료 후 자신이 만든 relay·bridge를 종료하고 임시 설치 환경·캐시와 보관 완료한 중복 출력 파일을 제거했다. 5173·5174 preview 서버는 유지했다.