feat: initialize sunrise with 100-player shared rooms
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
# 관악산 Copernicus 지형 적용 계획
|
||||
|
||||
**Goal:** 공개 30m급 두 타일을 보존하고 관악산 주변 DSM을 기존 고정 시점 시뮬레이터에 적용한다.
|
||||
**Architecture:** Python 오프라인 전처리 → 정적 float32 높이 격자·메타데이터 → 기존 Three.js 장면의 지형 메시. 브라우저 GIS 의존성/백엔드는 추가하지 않는다.
|
||||
|
||||
## 범위와 결정
|
||||
- 원본 N37 E126/E127을 data/raw/copernicus에 보관하고 SHA256/출처를 기록한다.
|
||||
- 원본 WGS84 경위도와 EGM2008 높이를 확인한 후 관측점 중심 AEQD(m) 좌표로 변환한다.
|
||||
- 초기 영역은 동서·남북 24km, 30m 간격(801×801). 원본보다 정밀하다는 의미가 아니다.
|
||||
- +X 동, +Y 위, -Z 북. 구면 지구 곡률 하강을 근사 반영한다. 지상 대기굴절은 미반영.
|
||||
- 임시 수동 해발고도 629m 대신 해당 임시 좌표의 DSM 표면+눈높이에 카메라를 둔다. 계산에도 같은 DSM 고도를 사용하고 화면에 명시한다. DSM은 수목·구조물을 포함하므로 실측 관측점이 아니다.
|
||||
- 가상 0° 지평선의 불투명 하반구는 해발고도에 따른 단순 해수면 지평선으로 낮추고 선/방위 표시는 유지한다. 영역 밖 실제 능선은 미반영임을 명시한다. 태양 원반은 지형보다 멀리 배치해 깊이 버퍼로 가린다. 0° 아래 일괄 숨김은 지형 모드에서 제거한다.
|
||||
- 일출/일몰 숫자는 계속 천문 계산값이며 능선 위 첫 관측 시각을 새로 계산하지 않는다.
|
||||
- 지형 다운로드 실패 시 빈 성공 화면 대신 오류를 표시한다.
|
||||
|
||||
## 작업 및 검증
|
||||
- [x] 다운로드·메타데이터·결측값·관측점 표면고도 검사, 재현 가능한 전처리 스크립트 및 출처 파일.
|
||||
- [x] 격자 정합/방위/보간/곡률/실데이터 범위 검증 테스트 후 지형 생성.
|
||||
- [x] 기존 world/sun/horizon/main/UI에 지형 통합, 로딩/실패 처리와 출처 표시.
|
||||
- [x] 전체 테스트·빌드, 일출 전후/낮 브라우저 검증, 독립 코드 리뷰, 문서 갱신.
|
||||
|
||||
## 검증 기록
|
||||
- 원본 합계 79,266,369 bytes. 가공 높이 격자 2,566,404 bytes / 801² 표본 / 결측 0.
|
||||
- 관측점 표면 606.906372m, 격자 범위 1.314315~618.474609m. 실측 고도가 아니며 원본의 표면 높이를 그대로 사용.
|
||||
- 새 테스트 4개 포함 전체 22개. 실제 03-20 06:40/06:50 태양 중심의 차폐/통과를 확인.
|
||||
- 독립 리뷰: important issue 없음. 지형 로딩/렌더링 오류 없음. 내장 브라우저의 Pointer Lock 거부는 재현되었으며 오류 안내가 표시됨.
|
||||
- 일반 브라우저 Pointer Lock 수동 조작은 이전 단계 미검증 상태 유지(컨트롤 코드 변경 없음).
|
||||
|
||||
## 검토 초점
|
||||
북쪽 뒤집힘, 경도127° 타일 경계, DSM/수동 표고 불일치, 지형보다 가까운 태양, 0° 강제 차폐, 큰 정적 파일 배포 누락.
|
||||
@@ -0,0 +1,13 @@
|
||||
# 기사문 해변 추가
|
||||
|
||||
사용자 요청: 하조대 곶의 차폐를 피해 기사문 해변에서 일출을 관찰한다.
|
||||
|
||||
기존 해안 렌더러·전처리를 장소 매개변수로 확장하고 새 장소의 데이터만 추가한다. 관악산·하조대는 유지하며 세 장소 링크를 제공한다. 기본 URL은 기존 하조대를 유지하고 기사문은 `?site=gisamun`으로 접근한다.
|
||||
|
||||
- [x] 기사문 OSM 원본·출처 기록, 관측점 선정, 3×3km DSM 추출. 위도 38° 경계를 넘으므로 보유한 N37/N38 타일을 병합한다.
|
||||
- [x] 바다 로더와 장소 전환을 장소별 경로로 연결한다. 공통 렌더러를 복제하지 않는다.
|
||||
- [x] 육지 원점·바다 방향·일출 태양 차폐를 테스트하고 기존 테스트·빌드·브라우저 검증.
|
||||
|
||||
모래 영역은 OSM에 누락되어 공식 관광 안내의 해변 위치와 실제 해안선 구간을 기준으로 35m 폭의 시각적 근사를 사용한다. 측량값이나 실제 해변 경계로 표시하지 않는다. 방파제 높이·구조물·작은 섬 상세 형상은 원본 해상도의 한계다.
|
||||
|
||||
검증: 기사문 자동 테스트 2개 통과, 전체 36개 테스트와 빌드 통과. 브라우저 2026-10-29 06:55 태양 원반 확인, 기사문→하조대 전환 확인. 독립 읽기 전용 리뷰에서 중요한 문제 없음. 동시 진행 중인 관악산 구조물 변경은 유지했다.
|
||||
@@ -0,0 +1,22 @@
|
||||
# 하조대 해안 구현 계획
|
||||
|
||||
## 설계
|
||||
사용자가 요청한 하조대 지형 추출, 해안선과 바다 구현을 수행한다. 기존 Three.js/SunCalc와 지형 전처리 패턴을 재사용한다. 기본 장면은 하조대이며 관악산은 링크로 유지한다. 실측하지 않은 관측점은 임시값으로 표시한다.
|
||||
|
||||
선택: 관측점 중심 3×3km DSM을 추출하고 OSM 해안선으로 육지/바다를 구분한다. 단순 바다 평면만 겹치는 방법은 높이 0인 해변을 침수시키므로 제외한다. 해안 근접 형상을 위해 10m로 재표본화하되 원본 정확도는 30m급으로 명시한다. 해안 마스크는 2m 간격이며 원본 OSM 정확도를 높이는 것이 아니다. 해안에서 30m 이내 표면은 시각적으로 해수면에 접속하며 정밀 지반/수심 데이터로 취급하지 않는다.
|
||||
|
||||
바다는 지구 곡률을 반영한 메시와 절차적 물결/태양 반사를 사용한다. 바다 이동은 차단한다. 건물·등대 모델링, 실제 날씨/조석, 정밀 암반은 범위 밖이다. 날짜·시간·눈높이·기존 관악산 기능을 유지한다. 데이터와 렌더링 상수는 기능별 constants 파일에 둔다.
|
||||
|
||||
## 작업
|
||||
- [x] `scripts/prepare-hajodae.py`: 기존 rasterio/pyproj로 DSM, OSM 마스크/해안선 추출; public/terrain/hajodae/에 원본 URL·해시·보정 범위 포함.
|
||||
- [x] `src/constants/locations.ts`, `src/constants/coast.ts`, `src/scene/coast.ts`: 장소 설정, 경계 판정, 바다/해안 재질. 기존 terrain/world/main/UI에 최소 통합.
|
||||
- [x] 테스트: 해변 원점이 육지, 동쪽 바다/남쪽 곶 구분, 바다 차단, 지형과 해수면 곡률, 위치 전환 데이터 정합.
|
||||
- [x] 전체 기존 테스트 및 빌드, 브라우저에서 하조대 낮/일출·관악산 검증. 출처 페이지와 README 갱신.
|
||||
|
||||
## 판단 기록
|
||||
- Git 저장소가 없는 기존 작업 폴더에서 직접 진행하며 다른 변경을 되돌리지 않는다.
|
||||
- 사용자 요청과 앞선 대화로 구현 범위가 정해져 있으므로 추가 승인 없이 진행한다.
|
||||
- 리뷰: 해안에 인접한 바다 칸 -2m가 육지 삼각형을 수면 아래로 당기는 문제 확인. 숨겨진 바다 칸을 0m로 변경하고 (52,0) 지점과 전체 격자 비음수 검증을 추가했다.
|
||||
- 브라우저: 해안 조감, 해변 눈높이 낮/일출 전후 표시 확인. 조감의 원거리 물결 앨리어싱은 화면 미분값으로 주파수를 감쇠해 수정했다.
|
||||
- 최종 검증: `npm test` 33/33, `npm run build` 통과. 기존 500KB 번들 크기 경고는 남아 있다. 관악산 건물 조감 정상, 링크로 하조대 복귀 정상. 하조대 동쪽 전진 15초 후 52m에서 멈추며 추가 3초 입력에도 위치 유지. 내장 브라우저 Pointer Lock은 지원되지 않지만 기존 드래그/키보드 대체 조작으로 이동 검증했다.
|
||||
- 캡처: `data/references/hajodae/implemented-overview.png`. 배포용 데이터 총 402,503 bytes(설명 HTML 제외).
|
||||
@@ -0,0 +1,37 @@
|
||||
# 관악산 Semi-MVP 1단계 Implementation Plan
|
||||
|
||||
**Goal:** 고정 관측점의 실제 태양 위치를 KST 시간 제어와 FPS 시점으로 관찰한다.
|
||||
**Architecture:** 제공된 모듈 구조를 따르는 프레임워크 없는 Vite 앱. 천문 계산은 Three.js와 독립. 설정은 config/, 기능 상수는 constants/에 둔다.
|
||||
**Tech Stack:** TypeScript, Vite, Three.js Sky / PointerLockControls, SunCalc 2.x.
|
||||
**Spec:** 사용자가 제공한 Semi-MVP 1단계 작업지시서.
|
||||
|
||||
## 결정 및 범위
|
||||
- 빈 폴더에 로컬 실행 프로젝트를 만든다. Git 저장소가 없어 worktree/커밋은 생성하지 않는다.
|
||||
- 임시 관측점: 37.4450 N, 126.9640 E, 해발 629 m, 눈높이 1.7 m. 측량값이 아님을 화면과 코드에 명시.
|
||||
- 표준 가상 지평선은 고도각 0°. 일출/일몰은 해발+눈높이로 보정하며 표준 0m 결과도 함께 표시한다.
|
||||
- KST 날짜의 정오를 getTimes에 전달해 자정에 전날 solar day가 선택되지 않게 한다.
|
||||
- 태양 원반은 0.53°, 광학 halo는 별도 셰이더. Sky 내장 원반은 비활성화해 중복 원반을 방지한다.
|
||||
- DEM, 지형, 건물, 이동, 백엔드, 호스팅은 범위 밖.
|
||||
|
||||
## 구현 및 검증
|
||||
- [x] 천문/KST/방향 테스트를 먼저 작성하고 실패 확인. SunCalc 2.x 기반 계산 및 시간 모듈 구현.
|
||||
- [x] Sky, 원반/halo, 0° 지평선, 방위 표시, 고정 FPS 카메라 구성.
|
||||
- [x] 최소 한국어 UI와 실시간 1초 갱신, 날짜/슬라이더, 탭 복귀 재동기화 연결.
|
||||
- [x] NOAA 공개 수식의 독립 구현과 여러 계절/시각 대조. 허용 오차를 명시하고 결과 저장.
|
||||
- [x] TypeScript/production build, 18개 테스트, 브라우저 화면·시간 UI 검증. README에 실행법/제한 기록.
|
||||
- [ ] 일반 브라우저 Pointer Lock 회전 및 ESC 실제 확인: 내장 브라우저 거부, 일반 Chrome 자동화 URL 확인 실패로 미검증.
|
||||
|
||||
## 검토 및 실행 기록
|
||||
- 독립 리뷰의 2건(과거 서울 시차 불일치, LIVE 중 날짜 편집 덮어쓰기)을 재현 테스트로 확인 후 수정. 입력과 출력 모두 IANA Asia/Seoul 사용.
|
||||
- NOAA 전 구간 0.1° 테스트는 지평선 아래 5개 사례에서 실패. SunCalc 음수 고도 굴절 입력 clamp를 확인해 표시 구간 0.1° / 비표시 고도 0.5°로 구분. 원본 차이를 검증표에 보존.
|
||||
- Vite 단일 번들 500 kB 권고 경고는 Three.js 포함으로 발생. 범위에 불필요한 지연 로딩은 추가하지 않음.
|
||||
|
||||
## 검토 초점
|
||||
KST 자정, 방위각 래핑, 지평선 아래 원반 숨김, 고도 보정 일출과 0° 표시 구분, Pointer Lock 실패 안내.
|
||||
|
||||
## 추후 TODO (2026-10-30)
|
||||
- [ ] 서버 운영 단계에서 LIVE 모드를 서버 시간 기준으로 동기화한다. 현재는 구현을 보류한다.
|
||||
- 목적: 사용자 기기 시계의 오차 및 실행 중 시계 변경으로 인한 LIVE 시각 차이를 줄인다.
|
||||
- 접속 시 서버 시각을 받아 기준을 맞추고, 이후에는 `performance.now()`의 경과 시간을 더해 브라우저에서 매초 SunCalc를 계산한다. 서버에 매초 요청하지 않는다.
|
||||
- 탭 복귀 및 주기적 재동기화를 적용한다. 통신 지연 보정과 동기화 실패 시 처리 방식은 구현 시 결정한다.
|
||||
- CUSTOM 모드는 사용자가 선택한 날짜·시간을 유지하고, 입력·표시는 기존 `Asia/Seoul` 기준을 유지한다.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Summit structure assets implementation plan
|
||||
|
||||
> **For agentic workers:** Execute inline with superpowers:executing-plans. Asset authoring is verified by export/import checks and visual inspection.
|
||||
|
||||
**Goal:** Refine the eight existing summit structures in Blender and deliver editable Blender source, individual GLBs, and previews.
|
||||
|
||||
**Architecture:** Reuse `src/constants/structures.ts` as the dimension and placement source. Build locally centered, material-batched meshes in a separate Blender scene; preserve the user's original scene. Store geographic placement and terrain support anchors in the asset manifest. Preserve the current application until asset integration is explicitly requested.
|
||||
|
||||
**Tech Stack:** Existing Node/TypeScript, Blender 5.2 through MCP, Python bpy, glTF 2.0.
|
||||
|
||||
**Spec:** User-approved conversation: refine existing structures using the collected photos and extract `.blend` / `.glb` assets; proceed now.
|
||||
|
||||
## Constraints and decisions
|
||||
|
||||
- Existing IDs, estimated dimensions and source attribution remain authoritative.
|
||||
- No new dependencies. Photographs are modeling references, never distributed textures.
|
||||
- Details visible in references inform geometry; hidden details remain approximations.
|
||||
- Deck origin is the upper walking surface; tower/radar origin is the base. Metres; GLB Y-up.
|
||||
- Terrain-dependent footings/support lengths stay outside fixed geometry; export their anchors.
|
||||
- Ruling: direct artifact authoring, not a runtime feature; no new regression tests. Validate the actual GLBs with Three.js and Blender re-import, inspect previews, run the existing build.
|
||||
- This directory has no Git repository; no commits or worktree operations.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] Snapshot existing constants and author `scripts/build-summit-assets.py`: shared material-batched geometry, five towers, radar, two decks.
|
||||
- [x] Export `public/models/summit/*.glb`, a manifest, and `assets/summit/summit-structures.blend` with a presentation scene.
|
||||
- [x] Render overview and detailed previews; inspect and correct visual defects.
|
||||
- [x] Load exported GLBs with Three.js and Blender, verify dimensions, materials, IDs, finite geometry, and no external resources. Write a verification report and usage notes.
|
||||
|
||||
## Review focus
|
||||
|
||||
Check north-axis conversion, origins, detached stair rails, closed deck ends, whole-scene export accidents, material loss, measured-versus-estimated wording, and inclusion of private/reference images.
|
||||
|
||||
## Completion evidence
|
||||
|
||||
- Three.js GLTFLoader: 8/8 passed; 87,523 triangles, 44 material batches, approximately 4.13 MiB total GLB payload.
|
||||
- Blender re-import: 8/8 passed; bounding boxes match Three.js within 1 mm.
|
||||
- `npm run build`: passed; existing bundle-size warning remains.
|
||||
- Overview plus radar, deck and tower renders inspected. Corrected overview framing and studio ground extent.
|
||||
- Export limited to active scene and selected hierarchy; initial default cube leakage corrected before delivery.
|
||||
- Independent review found stale geometry/spec metadata on reruns. Existing meshes now retain generation specs and changed dimensions fail explicitly; regeneration requires a fresh Blender file. Hand edits remain preserved during re-export.
|
||||
- Automatic approval rejected a destructive rebuild verification attempt. Removed that path and completed with non-destructive re-export. Original Cube, Camera and Light remain in the original scene.
|
||||
- Editable source saved, all assets visible in the presentation scene; GLBs and manifest also packaged in `assets/summit/summit-glb-pack.zip`.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Building exterior lighting
|
||||
|
||||
User choice: replace night window patterns with lighting on facades and surrounding ground, not whole-building emission. Reuse the existing static light-spill texture and solar-altitude fade. Keep building footprints, heights, terrain, and sun/shadow behavior unchanged.
|
||||
|
||||
Implementation: remove the four-component buildingWindow attribute and random window shader. Retain one scalar facade height per vertex; use normals to reject horizontal surfaces and fade illumination above the existing 24m limit. Unlit building types receive a fully faded value. Reuse the same texture on terrain and facades. Remove constants used only by windows. No new dependencies.
|
||||
|
||||
Verification: update the existing night/dawn/day/reverse-time test to verify spill intensity and non-emitting materials, assert the old window buffer is absent and total geometry bytes are reduced. Run tests/build and inspect daytime and nighttime in browser, including shader errors. Record actual geometry memory before/after; do not claim measured FPS improvement without a benchmark.
|
||||
|
||||
Completed: 43 tests passed and production build passed (existing bundle-size warning). Independent static review found no actionable issues. Browser checks at midnight and noon rendered successfully with no console errors; night lighting remains subtle at city-overview distance. Actual geometry buffers: 21,382,272 → 16,036,704 bytes (25% reduction); lighting attribute: 7,127,424 → 1,781,856 bytes. Mesh and triangle counts are unchanged. No FPS improvement claim or indexing changes.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Gwacheon building data improvement
|
||||
|
||||
Goal: improve agreement with real building footprints and heights using the user-supplied AL_D010_41_20260719.zip, without invented density.
|
||||
|
||||
Scope agreed in chat: prioritize actual map agreement; compare official data with OSM, fill missing heights, and inspect DSM placement. The supplied archive continues that authorized work.
|
||||
|
||||
Design: retain existing OSM geometry and explicit heights, supplement confidently matched missing height/levels from VWorld, and add non-overlapping official polygons within the existing AOI. Preserve holes and multipart geometry (split into separately identified Polygon features). Record ambiguous overlaps instead of duplicating buildings. Official zero heights are missing values, not zero-height buildings. Keep source and date per feature. Do not flatten terrain or raise buildings to fabricate survey accuracy.
|
||||
|
||||
Execution: in the existing workspace (no Git repository); Python preprocessing only adds pyshp/shapely to the existing local GIS tools. Browser dependencies remain unchanged.
|
||||
|
||||
- [x] Extract all three EPSG:5186 shapefiles with a streaming regional filter; verify height/levels against the official column workbook.
|
||||
- [x] Add focused matching tests: same building, missing height, non-overlap, ambiguous overlap and multipart/holes; run red then green.
|
||||
- [x] Generate merged GeoJSON and a source/audit manifest, preserving the OSM regeneration path.
|
||||
- [x] Check burial against rendered DSM, choose only a defensible placement correction, and document residual uncertainty.
|
||||
- [x] Update source labels and disclosures; run Python tests, npm test and build; inspect daytime city in browser and validate footprint distribution/overlaps computationally.
|
||||
|
||||
Acceptance: unique source IDs, finite valid polygons, no newly introduced overlapping buildings, provenance for numeric heights, counts reproducible from the supplied ZIP. Visual improvement alone does not establish survey accuracy. Footprint acquisition dates and unresolved conflicts remain visible in the source report.
|
||||
|
||||
Results: 6,692 polygons (5,052 new); height 1,771 / levels 894 / fallback 4,027. Six Python tests and 43 app tests pass; build passes with the existing large-bundle warning. Independent review found competing official matches and the missing-height/existing-level case; both reproduced and fixed with tests. Conflicting field values are logged, not selected by ID. Existing floor counts remain unchanged when a missing numeric height is added.
|
||||
|
||||
Decision: no ground-placement modification. The source contains object height, not surveyed foundation elevation. Moving buildings upward or flattening DSM would trade the user's accuracy priority for an unverified visual fix. Burial remains a documented limitation. Browser daytime overview confirms increased density; no claim of field validation or universal map completeness.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Immersive UI Implementation Plan
|
||||
|
||||
> **For agentic workers:** Use superpowers:executing-plans for this approved UI change.
|
||||
|
||||
**Goal:** Show only scene/action buttons by default on mobile and desktop; open all information and controls in popups; rename visible prayer copy to 소원빌기.
|
||||
|
||||
**Architecture:** Preserve existing element IDs and controllers. One native modal dialog switches between existing feature sections, providing browser focus containment and inert background. The minimap retains its renderer inside a separately toggled wrapper.
|
||||
|
||||
**Tech Stack:** Existing TypeScript, HTML, CSS, Vite; no new runtime dependencies.
|
||||
|
||||
**Spec:** User-approved immersive mockup and follow-up naming correction in this chat.
|
||||
|
||||
## Constraints and review focus
|
||||
- Preserve shared/solo viewing, weather, time and character logic; keep internal `pray` protocol/animation identifiers.
|
||||
- Default minimap hidden; optional pin through 지도·시점.
|
||||
- Cover 320px mobile, desktop and short landscape; safe-area spacing, touch targets, modal scrolling.
|
||||
- Opening dialogs stops background movement via canvas blur; modal keyboard input cannot trigger emotes.
|
||||
- Closing via button, backdrop or Escape restores opener focus; nested sections return to menu.
|
||||
- No Git metadata exists in this folder; edit in place, no worktree or commit.
|
||||
|
||||
## Tasks
|
||||
- [x] Browser acceptance check: default panels hidden, modal navigation/focus, time changes, map pinning, equipment and shared viewing accessible.
|
||||
- [x] Replace index.html HUD structure and src/style.css layout; retain functional IDs.
|
||||
- [x] Add src/ui/dialogs.ts initialization and cleanup in main.ts; rename visible world.ts strings.
|
||||
- [x] Populate sources with existing provenance links and bundled license notices.
|
||||
- [x] Run browser checks, existing tests and production build; inspect mobile/desktop screenshots.
|
||||
|
||||
## Verification log
|
||||
- Baseline npm test: local server tests hit sandbox EACCES on loopback; rerun with network-capable execution for valid results.
|
||||
- Final npm test: 102 passed, 1 skipped, 0 failed (103 total).
|
||||
- Final npm run build: passed; existing large-chunk advisory remains.
|
||||
- Chrome browser acceptance: passed at 390×844, 320×568, 844×390 and 1440×900. Inspected mobile, desktop and popup screenshots. Mobile checks are browser emulation, not physical iOS/Android devices.
|
||||
- Verified native modal background isolation, Tab containment, Escape/backdrop/button closing, focus restore, KST edits, map toggle, existing menu controls, wish animation and license URL.
|
||||
- Independent read-only review: no actionable regression. Browser testing caught Tab navigation leaving the popup; explicit boundary wrap added and rechecked.
|
||||
- Concurrent lobby/entry changes were retained. Tests use the supported solo entry path; full live backend admission remains covered by existing server tests, not this UI browser check.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Mobile Rendering Implementation Plan
|
||||
|
||||
> Execute inline with superpowers:executing-plans; use measured evidence before enabling optimizations.
|
||||
|
||||
**Goal:** Improve mobile movement and rotation smoothness while preserving astronomy, movement, terrain and materials.
|
||||
**Architecture:** Add development-only profiling around the existing loop, then measure resolution and postprocessing separately. Keep production adaptive resolution independent of simulation updates.
|
||||
**Tech Stack:** Existing TypeScript, Three.js, Vite, Node tests. No new dependencies.
|
||||
**Spec:** User's 2026-10-30 mobile rendering work order and approved measurement-first approach in this chat.
|
||||
|
||||
## Constraints and review focus
|
||||
- Preserve solar calculations, movement speed, camera direction and spatial geometry.
|
||||
- No unmeasured LOD, mesh batching, texture compression or shadow system changes.
|
||||
- Distinguish rendered frames from idle animation callbacks; aggregate all composer passes.
|
||||
- Exclude hidden/loading/resize transitions from quality decisions without filtering ordinary slow frames.
|
||||
- Test hysteresis, idle gaps and resolution bounds; do not label desktop viewport tests as device validation.
|
||||
- No Git repository exists here: preserve original touched source in `.tmp/mobile-performance/`; no worktree or commit possible.
|
||||
|
||||
## Tasks
|
||||
- [ ] 1. Add development profiling and fixed-condition replay. Save baseline FPS/mean/p95/slow frames, whole-frame draw calls, triangles, textures, geometries, viewport, lights and passes. Scenarios: static, rotation, movement, dense view, 300-second endurance. Tests verify percentile aggregation.
|
||||
- [ ] 2. Measure DPR 2, 1.5, 1.25 and postprocessing separately with identical scene/time/weather/path. Retain only justified changes, preserving near PBR and silhouette. Save screenshots and raw JSON.
|
||||
- [ ] 3. Add adaptive resolution with 5-second slow windows, 20-second fast observation, 10-second settling and asymmetric thresholds. Default touch/mobile starting cap 1.5, desktop cap 2; actual frame evidence drives changes. Test thresholds, idle/hidden reset, and bounds.
|
||||
- [ ] 4. Run existing tests/build/solar checks and browser interactions; obtain independent code review. Record real device availability, five-minute results and unmet targets honestly.
|
||||
|
||||
## Ledger
|
||||
- Initial inspection: DPR 2; RenderPass + optional night bloom + OutputPass; no enabled shadows; building geometry already merged. Movement triggers solar/UI refresh and minimap redraw. These are candidates, not proven bottlenecks.
|
||||
- Real Android device discovery failed because ADB daemon could not start; device availability not confirmed. Safari not available through current browser inventory.
|
||||
- Task 1: development instrumentation complete; four provisional raw runs saved. Concurrent terrain edits invalidate cross-run source equivalence; these are observations, not a final baseline.
|
||||
- Ruling: user requested stopping the five-minute workload while other work runs. Stop all continuous render benchmarking; no passed endurance result or screenshot comparison is claimed.
|
||||
- Ruling: because matched resolution experiments cannot yet be completed and shared scene sources are changing, keep automatic resolution DEV-only behind `?profile&quality=adaptive`. Production defaults stay unchanged. Task 2 and production activation in Task 3 are deferred pending matched evidence, not marked complete.
|
||||
- Task 3 prototype: statistics and adaptive controller tests pass. Slow/healthy hysteresis, idle and visibility/texture/resize resets are wired only through developer diagnostics.
|
||||
- Validation: full suite 68 pass, production build passes (size warning), solar numerical comparison passes. Initial localhost test EACCES resolved by rerunning with local networking permitted.
|
||||
- Final review fixes: reset adaptive quality at benchmark start, collect inventory before samples, abort external resize. Restart regression test failed before implementation and passes afterward. Final suite 69/69; build passes. No additional GPU workload; browser viewport override reset.
|
||||
@@ -0,0 +1,54 @@
|
||||
# 관악산 공동 방 구현 계획
|
||||
|
||||
> 실행: 현재 세션에서 구현하고 서버 작업은 독립 파일 범위로 병렬 진행한다. 사용자 요청에 따라 추가 승인 없이 구현한다.
|
||||
|
||||
**Goal:** 관악산 100명 방, 기존 양 캐릭터·장비 상태 공유, 서버 시각·날씨, MongoDB 접속 기록.
|
||||
**Architecture:** 단일 Node/Socket.IO 인스턴스가 `gwanaksan-001`을 관리한다. 장소와 방 ID를 분리하고 MongoDB에는 방문 세션만 저장한다.
|
||||
**Tech Stack:** 기존 TypeScript/Three.js + socket.io/socket.io-client + mongodb 공식 드라이버.
|
||||
**Spec:** `docs/superpowers/specs/2026-10-30-multiplayer-design.md`와 후속 사용자 합의. 현재 양 캐릭터/3인칭/우천 장비를 유지한다. DB는 `172.16.0.7:27017`, 인증은 환경변수로 설정한다.
|
||||
|
||||
## 제약 및 검토 항목
|
||||
|
||||
- 작업 폴더는 Git 저장소가 아니므로 worktree/commit 작업은 생략한다.
|
||||
- 장비는 메모리에만 저장하고 새 세션에서는 해제한다. 서버 기록에는 장비·이동을 저장하지 않는다.
|
||||
- DB 저장 대기 중 정원 예약, 중복 입장, 연결 종료 후 늦은 응답, DB 실패 시 정원 반환을 검증한다.
|
||||
- 재접속/혼자 보기 전환 시 이전 소켓 상태를 제거하고 장비·시각을 초기화한다.
|
||||
- 공통 형식은 `src/multiplayer/protocol.ts`, 상수는 `src/constants/multiplayer.ts`를 기준으로 한다.
|
||||
- 실제 호스팅 배포 및 1만 명 확장은 범위 밖이다.
|
||||
|
||||
## Task 1: 서버와 기록
|
||||
|
||||
- [x] `server/room.ts`, `server/app.ts`, `server/visits.ts`, `server/index.ts` 및 서버 테스트를 추가한다.
|
||||
- [x] 100명 정원/101번째 거절/동시 예약/비활성 장소/입력 검증 테스트를 먼저 실행해 실패 확인 후 구현한다.
|
||||
- [x] Node HTTP 정적 파일 제공, health, Socket.IO 및 DB 연결 종료를 구현한다.
|
||||
- [x] `join`, `player:update`, `player:reset`, `clock:sync` 요청과 `room:state`, `player:correction`, `weather:state` 응답을 공통 타입으로 연결한다.
|
||||
- [x] 기존 보행 검증과 날씨 조회를 재사용하고 DB 기록은 입장/마지막 확인/퇴장만 수행한다.
|
||||
|
||||
## Task 2: 클라이언트와 화면
|
||||
|
||||
- [x] `src/multiplayer/client.ts`, `remotePlayers.ts`, 시간 동기화를 추가한다.
|
||||
- [x] 서버 시각 고정과 원격 캐릭터 자원 공유·해제 테스트를 먼저 작성한다.
|
||||
- [x] `world.ts`에 로컬 상태 읽기/보정과 원격 표시를 추가하고 기존 캐릭터 모델을 복제한다.
|
||||
- [x] `main.ts`, `timeController.ts`, `index.html`에 공동/혼자 보기 전환과 연결/정원 상태를 표시한다.
|
||||
- [x] 공동 모드 날짜 조작 차단, 원본 지형/프로파일은 혼자 보기로 제한한다.
|
||||
|
||||
## Task 3: 통합과 실행
|
||||
|
||||
- [x] package scripts, Vite 프록시, 환경설정 예시, README 운영 명령을 추가한다.
|
||||
- [x] 실제 Socket.IO 100명/101번째 거절/퇴장/재입장/장비 스냅샷/시각을 검증한다.
|
||||
- [x] MongoDB는 테스트 전용 DB로 기록 확인하고 실제 서비스 데이터와 분리한다.
|
||||
- [x] 기존 테스트와 빌드, 5분 부하, 가능하면 브라우저 두 화면과 99 캐릭터 렌더링을 확인한다.
|
||||
- [x] 별도 코드 리뷰 후 중요한 문제를 수정하고 검증 한계를 보고한다.
|
||||
|
||||
## 진행 기록
|
||||
|
||||
- 계획 작성. 기존 타입과 공유 함수 재사용을 우선한다.
|
||||
- 서버/클라이언트 구현 완료. 기본 캐릭터 신규 제작 대신 기존 양 모델·장비를 재사용하고 GPU geometry/material을 공유한다.
|
||||
- 서버 테스트와 프런트 상태/시간/자원 테스트 RED→GREEN 확인. 전체 103개 중 102 통과, 기존 1개 skip.
|
||||
- MongoDB 임시 DB에서 입장/heartbeat/종료 기록 검증 통과. 시작 시 기존 기록 일괄 복구는 자동 승인 검토 거절로 제거했고, 임시 DB에서 기존 열린 기록 보존 RED→GREEN 확인.
|
||||
- 별도 리뷰의 DB 실패 응답 지연 문제 수정: 정리 작업을 기다리기 전에 오류 응답, 재현 테스트 RED→GREEN.
|
||||
- 100개 클라이언트 5분 10Hz 부하, 101번째 거절/자리 재사용 통과. 결과 artifacts/multiplayer/load-report.json.
|
||||
- 두 실제 브라우저 상호 표시/이동, 공동 시각 잠금, 혼자 보기/재입장 확인. 별도 시작 화면/HUD 변경이 반영된 최신 UI에서 서버/채널 선택 후 입장도 확인.
|
||||
- 99명 가상 참여자+실제 브라우저 1개로 100/100명 표시와 양·우산·비옷 렌더링 확인. 정량 GPU 프레임/모바일 성능은 미측정.
|
||||
- 최종 npm test: 102 pass, 1 skip, 0 fail. npm run build: 프런트/서버 타입 검사 및 운영 빌드 통과. 기존 대형 JS 청크 경고 유지.
|
||||
- 기존 미종료 기록의 자동 갱신을 제거한 결정: 강제 종료 시 leftAt은 미확정으로 남고 lastSeenAt으로 마지막 확인 시각만 알 수 있다. 장비 영구 저장/다중 인스턴스/외부 배포는 요청 범위 밖이다.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Prebuilt buildings implementation plan
|
||||
|
||||
**Goal:** Load precomputed building geometry and illumination without changing appearance.
|
||||
**Architecture:** Keep the existing generator for offline preparation and experiments. Share material/shader/update logic with a small binary loader. Store exact typed arrays, indices, light pixels, bounds, counts and target; reject stale artifacts at build time using source hashes. No new dependencies or geometry compression.
|
||||
|
||||
- [x] Add equivalence and loader tests, confirm failure before implementation.
|
||||
- [x] Extract shared scene and light-texture restoration; add binary loading and offline generation.
|
||||
- [x] Switch main/world to baked assets; preserve experiment generator API.
|
||||
- [x] Generate assets, check exact equivalence and stale-file rejection, run tests/build and preview.
|
||||
- [x] Document regeneration and measured sizes, review resource handling.
|
||||
|
||||
Verification: original and restored position/normal/light-height/index arrays, bounding volumes, counts, target, material colors, spill pixels/bounds and night/dawn/day intensity match exactly. Browser midnight/noon views render with no console errors. 44 tests pass; production build passes with the existing bundle-size warning. Independent review found source hash sensitivity to checkout line endings; normalized CRLF to LF for text inputs and verified both remain fresh while changed content is rejected.
|
||||
|
||||
Output: 10,028,176-byte binary (8,979,600 geometry + 1,048,576 light pixels) plus JSON metadata. Local Node assembly-only timings across 3 runs: generation 571.72–786.20ms, restoration 0.14–0.40ms; excludes download, parsing, GPU upload, other scene work. No total-load-time or FPS claim.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Rain and snow
|
||||
|
||||
User requested actual falling rain and snow with intensity driven by the selected time's weather. Extend the existing weather controller and Three.js world without dependencies. Use rain plus showers in forecast/history and rain in reanalysis; snowfall remains cm. Accumulations represent the preceding hour, unlike interpolated cloud/visibility. Missing amounts stay unknown and produce no particles.
|
||||
|
||||
Implementation: bounded camera-local rain line segments and soft snow points; animate only active precipitation, scale density and rain streak strength with amount, preserve scene depth, clip at the sampled terrain/sea surface. Reuse weather transitions and render invalidation. No accumulation, surface wetness, measured wind, or roof collisions.
|
||||
|
||||
- [x] Extend weather request/parser/sampling and focused tests.
|
||||
- [x] Add precipitation constants and renderer, connect active camera/update/disposal.
|
||||
- [x] Show hourly rain/snow amounts, update documentation.
|
||||
- [x] Run focused/full tests, build, and browser rain/snow/mixed/dry checks.
|
||||
|
||||
No Git metadata exists in this workspace. Work in place, preserving unrelated edits.
|
||||
|
||||
Verification: all 79 tests pass, including the localhost HTTP test when run with network access. Production build passes with the existing chunk-size warning. Actual forecast, historical forecast and reanalysis requests returned HTTP 200 with rain in mm and snow in cm. Review identified transient false mixed precipitation when switching types; absent types now stop immediately while positive intensities ease in.
|
||||
|
||||
Browser verification with controlled API responses: heavy rain (15 mm/h, 3,535 streaks), light rain (0.2 mm/h, 408 streaks), snow (2 cm/h, 1,555 flakes), mixed rain/snow, dry, and unavailable precipitation all passed without page or WebGL console errors. The rain-to-snow assertion reproduced the review finding before the fix and passed afterward. Screenshots and the reusable local QA runner are in `.tmp/`. UI dates were frozen at noon KST; API fixtures are test data, not actual weather claims.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Red sheep implementation plan
|
||||
|
||||
Goal: implement the approved four-color sheep using Blender MCP, with a rear third-person camera, waving, and sunrise prayer.
|
||||
|
||||
Architecture: keep the existing observer camera as the walking/astronomy anchor; render through a separate following camera. Export a hierarchical GLB from a dedicated Blender scene. Animate named limb pivots in Three.js without adding dependencies.
|
||||
|
||||
Design: approved concept in the conversation. Three-head proportions, vermilion wool, cream face, dark horns/outline and gold sunrise emblem. Existing terrain and walking constraints remain authoritative. Prayer window is an implementation default: inclusive five minutes before/after computed sunrise, based on the selected simulation time. Movement cancels emotes. Prayer faces the sun; wave lasts three seconds.
|
||||
|
||||
- [x] Create reproducible Blender model script, inspect front/back, save .blend and export GLB.
|
||||
- [x] Add focused tests for prayer timing, animation reset and following-camera behavior.
|
||||
- [x] Implement constants, character loader/poses and following camera; integrate world lifecycle and controls.
|
||||
- [x] Add accessible buttons and keyboard shortcuts (1 wave, 2 prayer), including disabled-state explanation.
|
||||
- [ ] Run targeted tests, full tests, build, and visual checks. Record limitations.
|
||||
|
||||
Review focus: movement cancels poses; time changes end unavailable prayer; overview does not move player; camera clears terrain; asset failures are visible; disposal releases resources.
|
||||
|
||||
Verification: build and four feature tests pass. Full suite 74/75, pre-existing summit walking boundary assertion fails. Blender views inspected; in-game browser verification blocked by Windows browser URL detection. See docs/red-sheep.md. Independent review found stale overview buttons and walking-to-idle render invalidation; both corrected.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Summit performance optimization
|
||||
1. Measure the current summit overlay construction and profile continuous rendering at the same camera.
|
||||
2. Extract pure geometry generation into an offline builder. Bake indexed geometry and material distances into a compressed binary asset, with source-hash freshness checks.
|
||||
3. Load the asset alongside existing assets; runtime creates typed-array views, without recursive geometry generation or distance queries.
|
||||
4. Reuse identical vertices without changing triangles. Evaluate single-surface regions without sampling unused material textures, keeping boundary blends unchanged.
|
||||
5. Verify attribute equivalence, decoded binary validity, stale checks, walking tests, production build, and before/after browser rendering. Report measured construction timings separately from full startup or GPU FPS.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Panorama-based summit terrain implementation
|
||||
|
||||
Goal: implement the user's authorized estimated panorama start and local 100–200m terrain correction. This is a visual reconstruction, not surveyed terrain.
|
||||
|
||||
Design: retain the original terrain origin, binaries and building assets. Estimate a camera on the summit-side rocks northeast of the radar at 37.44472, 126.96422. Photos show a saddle between observer and elevated radar rock, with the eastern valley to the left when looking south; the supplied contour screenshot only constrains broad ridge/valley layout. It does not provide control elevations. All local target elevations are artistic estimates, including the 620m observer ground. The blog coordinate is not used as a measured camera position.
|
||||
|
||||
Approaches: replacing the DSM needs unavailable high-resolution data; raising the entire area loses the saddle. Selected: sparse estimated elevation controls, smooth residual interpolation, full influence through 100m and zero at 200m. Keep a same-start original-terrain comparison. No new dependencies.
|
||||
|
||||
## Tasks
|
||||
- [x] Add failing behavioral tests: unchanged vertices outside 200m, radar visible above eye level across the saddle, walking ray matches corrected geometry, original data unchanged. Smooth boundary uses smoothstep falloff; not separately measured by a test.
|
||||
- [x] Add feature constants and a local geometry correction. Reuse coordinate conversion and triangle height sampling.
|
||||
- [x] Integrate estimated start/reset and initial southward view, corrected contours and structure foundations, original comparison and explicit labels/source notes.
|
||||
- [x] Inspect both modes, reset, first drag and contour zoom in browser. Original at same camera coordinate: 604.1m, reconstructed: 620.0m. Screenshot saved in data/backups/summit-terrain-20261030/corrected-preview.jpg.
|
||||
|
||||
Review: independent reviewer found first south-facing drag reinterpreted XYZ Euler angles as YXZ. Added failing real-handler test; changed rotation.order assignment to rotation.reorder, test passed. Native pointer lock unavailable in embedded browser; drag fallback checked. Initial heading adjusted from173° to185° to keep radar clear of the right information panel.
|
||||
|
||||
Verification: full suite 47/47 before camera fix, followed by targeted camera test RED→GREEN. Final full suite48/48, building asset check, TypeScript and Vite build passed. Existing Vite >500kB bundle warning remains.
|
||||
|
||||
Review focus: original assets preserved; raw mode at same start; only Gwanaksan patched; startup/reset/eye height use same surface; estimated data never presented as measured. No Git repository is present, so worktree/commits are unavailable. Existing files are backed up before editing.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Open-Meteo weather integration
|
||||
|
||||
Goal: Synchronize cloud cover and visibility to the selected instant, and smoothly attenuate sunlight in cloudy or hazy conditions.
|
||||
|
||||
Design: Extend the existing TypeScript/Three.js app without dependencies or a backend. Fetch two UTC days of hourly data and interpolate by Unix timestamp (the UI remains in Asia/Seoul). Use forecasts near today, historical forecasts from 2022, and cloud-only reanalysis from 1940. Display missing data explicitly; do not substitute today's weather for another date. Cache requests, bound memory, ignore obsolete responses, and clean up requests on disposal. Weather remains representative of the site's fixed coordinates, not every walking step.
|
||||
|
||||
Rendering: Reuse Sky cloud uniforms, terrain fog and the separate sun shader. Apply an explicitly approximate cloud/haze transmission to disc, halo and directional light. Smooth transitions over frames without changing solar geometry. This is weather-conditioned visualization, not directional cloud reconstruction.
|
||||
|
||||
## Tasks
|
||||
- [x] Add tests for date routing, UTC/KST selection, interpolation/missing data, cache/races, and attenuation.
|
||||
- [x] Add feature constants and a small weather data/controller module.
|
||||
- [x] Connect weather to the sky/sun/fog and add status/attribution in the location panel (avoids overlap with the bottom controls).
|
||||
- [x] Run focused tests, all tests, build, and browser checks where available. Document API/network limitations.
|
||||
|
||||
No Git metadata is present in this workspace; implementation remains in the current directory. The user's follow-up authorizes the Open-Meteo approach described in the preceding investigation.
|
||||
|
||||
Verification: seven focused weather tests and all 57 current tests pass; production build passes with the existing bundle-size warning. The localhost HTTP test needed network permission. Live requests to all three API endpoints returned HTTP 200 with CORS `*`. Browser verified live values, October 29 hourly scrubbing (100% cloud), 2000 reanalysis with missing visibility, and 2099 unavailable fallback. A review found missing CUSTOM-mode retries; reproduced with a failing test and fixed with a disposable expiry timer. Browser QA found native fetch receiver binding; reproduced, fixed and tested. Concurrent workspace changes to walking/vegetation were preserved.
|
||||
@@ -0,0 +1,80 @@
|
||||
# 관악산 100명 공동 해돋이 설계
|
||||
|
||||
상태: 초기 설계 기록. 후속 합의에 따라 Node.js/Socket.IO, 기존 양 캐릭터 및 우천 장비 공유, MongoDB 접속 기록으로 구현했다. 최신 동작과 검증 결과는 `docs/multiplayer-server.md`를 참고한다. 서버 시작 시 기존 기록 일괄 갱신은 수행하지 않는다.
|
||||
|
||||
## 목적과 합의
|
||||
|
||||
관악산 한 공간에서 최대 100명이 각자 이동하며 다른 참여자의 캐릭터를 본다. Socket.IO를 사용한다. 공동 모드는 서버 기준 실제 현재 시각으로 고정하고, 날짜·시간 변경은 혼자 보기에서만 제공한다. 하조대·기사문은 비활성 상태를 유지하되 장소 추가에 공통 통신 로직을 재사용한다.
|
||||
|
||||
초기 게스트 접속과 메모리 관리를 제안한 대화에 이어 작성한 설계다. 아래 구체적 기본값은 구현자 제안이며 사용자가 각각 선택한 사항은 아니다.
|
||||
|
||||
## Approaches
|
||||
|
||||
- 선택한 통신: Node.js 단일 프로세스 + Socket.IO. room과 연결 수명 관리 기능을 활용한다.
|
||||
- 대안: 직접 WebSocket 사용. 전송 계층은 단순하지만 입퇴장·재연결 프로토콜을 더 직접 구현해야 하므로 선택하지 않았다.
|
||||
- 저장 제안: 참여자 Map과 장소별 상태를 서버 메모리에 유지한다. 영구 프로필이 없는 초기 범위에는 PostgreSQL을 도입하지 않는다. Redis와 다중 서버는 확장 요구가 생길 때 검토한다.
|
||||
|
||||
## 현재 코드와 재사용
|
||||
|
||||
- `src/constants/locations.ts`: 세 장소 정의와 관악산만 활성인 설정이 이미 있다. 장소 ID와 활성 상태는 서버와 클라이언트의 단일 출처로 유지한다.
|
||||
- `src/ui/timeController.ts`: LIVE가 로컬 Date를 읽는다. 시각 공급 함수와 공동 모드 잠금을 추가해 재사용한다.
|
||||
- `src/scene/world.ts`: 카메라 이동, 지면 높이 보정, 렌더 무효화, 조감 카메라, 시작점 복귀를 관리한다. 네트워크에는 관측용 조감 카메라가 아닌 실제 보행자 상태만 노출한다.
|
||||
- `src/controls/summitWalking.ts`: 기존 보행 가능 영역 검증을 재사용한다. 순수 계산에 필요한 의존성만 최소한으로 분리하고 서버에서 렌더러를 로드하지 않는다.
|
||||
- 속도는 `src/constants/movement.ts`의 기존 4m/s, 빠른 이동 20m/s를 기준으로 한다.
|
||||
|
||||
## 구성과 저장 경계
|
||||
|
||||
`server/`에 서버 시작과 입퇴장·상태 처리를 둔다. `src/multiplayer/`에 연결과 원격 캐릭터 처리를 둔다. 공유 이벤트 타입은 브라우저 전용 의존성이 없는 모듈에 둔다. 통신 주기·정원·보간 등 기능 상수는 `constants/`에 둔다. 세부 파일 분할은 구현자가 기존 패턴에 맞춰 결정한다.
|
||||
|
||||
서버는 플레이어 ID, 닉네임, 기본 외형 색상, 장소 ID, x/z 위치, 방향, 마지막 갱신 시각을 메모리에 저장한다. ID와 색상은 서버가 발급하며 클라이언트가 다른 사람의 ID를 지정할 수 없다. 좌표는 기존 장면의 미터 좌표계를 사용한다. 지면 y는 각 브라우저가 같은 지형에서 계산한다.
|
||||
|
||||
닉네임은 기본 자동 이름을 제공하고 입장 전 짧은 일반 텍스트 입력을 허용한다. 길이와 자료형을 검증하며 HTML로 렌더링하지 않는다. 로그인, 계정, 영구 외형 저장, 방문 기록, 채팅·음성, 결제는 범위 밖이다.
|
||||
|
||||
## 입장과 연결 수명
|
||||
|
||||
기본은 공동 보기이며 명시적 혼자 보기 전환을 제공한다. 장면 로딩이 끝난 후 입장을 요청한다. 관악산 room의 정원은 참여자 100명이며 자기 자신을 포함한다. 초기에는 연결 한 개를 참여자 한 명으로 취급하므로 여러 탭은 각각 정원을 사용한다.
|
||||
|
||||
서버는 장소 활성 상태와 정원을 확인하고 같은 동기 처리 구간에서 자리를 배정한다. 중복 입장은 멱등적으로 처리한다. 정원 초과나 비활성 장소 요청은 명확한 오류 코드로 거절한다. 101번째 참여자는 자동으로 다른 방에 배정하지 않으며 혼자 보기를 선택할 수 있다.
|
||||
|
||||
입장 응답에는 자신의 상태, 현재 참여자 전체 목록, 서버 시각을 포함한다. 서버가 Socket.IO 연결 종료를 감지하면 참여자를 제거하고 다른 사람들에게 퇴장을 전달한다. heartbeat 감지 전까지는 정원을 유지할 수 있다. 복구 시 이전 연결을 그대로 복원하려 하지 않고 새 입장과 전체 상태를 받는다. 중복 캐릭터와 이전 연결의 늦은 이벤트는 세션 경계에서 정리한다.
|
||||
|
||||
서버 재시작이나 재입장 시 기본 시작 위치로 돌아간다. 서버 장애 중에는 연결 끊김을 표시하고 원격 캐릭터를 정리한다. 공동 연결을 성공한 것으로 표시하지 않는다. 혼자 보기 전환 시 소켓을 끊고 정원을 반환한다.
|
||||
|
||||
## 이동 및 표시
|
||||
|
||||
로컬 보행은 기존 즉각 반응을 유지한다. 이동 상태는 최대 초당 10회 전송하고 서버는 검증된 변경분을 초당 10회 모아서 같은 장소에 방송한다. 정지 시 불필요한 상태 전송을 줄인다. 초기 전체 상태 및 주기적 전체 동기화로 상태를 수렴시킨다. 서버 시퀀스 번호로 오래된 업데이트를 무시한다.
|
||||
|
||||
서버는 유한한 수, 좌표 범위, 이동 속도와 경과 시간, 보행 가능 경로, 전송 빈도와 패킷 크기를 검증한다. 긴 비활성 기간이 순간 이동 허용으로 이어지지 않도록 이동 허용 시간은 제한한다. 거절 시 승인된 위치로 보정한다. 시작점 복귀는 별도 서버 명령으로 처리한다. 완전한 서버 물리 시뮬레이션이나 경쟁 게임 수준의 부정행위 방지는 범위 밖이다.
|
||||
|
||||
기본 캐릭터는 외부 모델 없이 가벼운 머리·몸통 형태와 색상으로 구분한다. 1인칭 자신의 몸은 표시하지 않는다. 다른 캐릭터는 약 100~200ms 보간 지연으로 표시한다. 원격 이동 및 보간 중에는 기존 렌더 무효화 흐름을 갱신한다. 공유 geometry/material을 사용하며 종료 시 자원을 해제한다. 캐릭터끼리 충돌하지 않고 시작 위치 겹침을 허용한다.
|
||||
|
||||
## 시간·장면·날씨
|
||||
|
||||
서버의 UTC epoch 시각을 요청/응답으로 받고 왕복 시간의 절반을 추정해 기준을 보정한다. 수신 후에는 monotonic 경과 시간으로 진행하고 주기적으로 재동기화한다. 네트워크 지연 때문에 완전한 프레임 일치는 보장하지 않는다. 표시 시간대는 기존 Asia/Seoul을 유지한다.
|
||||
|
||||
공동 모드에서는 날짜·시간 입력과 CUSTOM 전환을 UI 및 제어 로직에서 잠근다. 혼자 보기에서는 기존 LIVE/CUSTOM 동작을 보존한다. 공동 보기 복귀 시 현재 서버 시각과 새 입장 상태를 적용한다.
|
||||
|
||||
공동 모드는 기존 사진 기반 보정 지형 하나로 고정한다. 원본 지형 비교와 개발 프로파일 모드는 혼자 보기로 한정해 서로 다른 지면과 시간이 같은 room에 섞이지 않도록 한다. 기존 조감 기능은 유지하되 보행자 위치를 바꾸지 않는다.
|
||||
|
||||
공동 날씨는 서버가 관악산의 기존 기상 조회·캐시 로직을 재사용해 같은 자료와 상태를 배포한다. 브라우저 UI 제어와 순수 조회/보간 로직만 필요한 만큼 분리한다. 실패 시 모두 같은 기본 하늘 상태와 안내를 받는다. 혼자 보기의 과거 날짜 기상 조회는 기존 동작을 유지한다.
|
||||
|
||||
## 장소 확장
|
||||
|
||||
room 이름은 장소 ID로 정한다. 추가 장소에는 활성화 여부, 좌표 원점, 시작점, 보행 검증 정책을 연결한다. 장소별 분기는 입장/이동 이벤트 전체를 복제하지 않고 장소 설정과 지형별 정책에 한정한다. 하조대·기사문 활성화 및 실제 멀티플레이 검증은 후속 작업이다.
|
||||
|
||||
## 실행과 배포 범위
|
||||
|
||||
개발에서는 Vite가 `/socket.io`를 Node 서버로 프록시한다. 운영 실행에서는 Node 서버가 빌드된 정적 파일과 Socket.IO를 함께 제공하는 단일 인스턴스 구성을 기본으로 한다. 정적 파일 경로는 배포 루트 안으로 제한하고 출처와 입력 제한을 적용한다. 인터넷 서비스에서는 TLS 지원 프록시 뒤에서 실행할 수 있게 환경변수로 포트와 허용 출처를 설정한다.
|
||||
|
||||
이번 범위는 실행 가능한 서버 코드, 운영 빌드 실행 명령과 설명, 로컬 검증이다. 호스팅 계정·도메인·서버 사양을 정하거나 외부에 실제 배포하는 것은 포함하지 않는다. Git 저장소가 아닌 현재 작업 폴더에서는 설계 파일만 저장하고 커밋하지 않는다.
|
||||
|
||||
## 성공 기준과 검증
|
||||
|
||||
1. 100개 Socket.IO 클라이언트를 관악산에 동시에 입장시키고 101번째 거절, 한 명 퇴장 후 새 입장을 검증한다. 중복 입장과 비활성 장소 요청도 확인한다.
|
||||
2. 100명이 10Hz 이동하는 5분 로컬 부하 시나리오에서 참여자 상태 일관성, 프로세스 안정성, 이벤트 지연, CPU·메모리 추이를 기록한다. 지연 p95 200ms 이하를 초기 로컬 목표로 삼되 결과와 하드웨어를 함께 보고하고 운영 성능 보장으로 표현하지 않는다.
|
||||
3. 잘못된 좌표·과도한 속도·빈도, 시작점 복귀, 연결 종료/재접속, 정원 해제를 집중 검사한다.
|
||||
4. 실제 브라우저 두 개에서 상호 입퇴장과 이동을 보고, 공동 시간 잠금·서버 시각 동기화 및 혼자 보기 복귀를 확인한다.
|
||||
5. 99개 원격 캐릭터를 표시하는 브라우저 시나리오에서 프레임 시간과 자원 사용을 측정한다. 서버 부하 테스트와 렌더링 검증을 구분해 보고한다.
|
||||
6. 기존 테스트와 TypeScript/운영 빌드를 수행한다. 기존 지형·천문 계산 동작은 유지한다.
|
||||
|
||||
세부 UI 배치, 색상 팔레트, 검증 허용 오차와 보간 조정은 구현자가 결정하고 측정으로 보완한다. 검증하지 못한 운영환경·모바일 성능은 명시한다.
|
||||
Reference in New Issue
Block a user