← 목록
기타 2026-06-28 3KB 읽기 4분

에덴고 vs os.crowny.org 크라우니월드 — 코드원리 성능 분석 (울트라, 적대검증)

14에이전트 울트라: 4차원 병렬분석 → 9건 적대검증(6확정) → opus 종합. 2026-06-28.

통념 반박 (적대검증으로 정정)

  • 무거움의 원인 ≠ 픽셀 스프라이트. 에덴고 drawSoul 64×64 상세경로(85~100 fillRect)는 데드코드(sprites.js 선로드→if(ES.draw) 항상 참, souls.js:319). 실제 ~18 fillRect/soul.
  • 개당 비용은 오히려 os 3D 박스모델(HUMAN9 ~142 fill)이 에덴고 소울(~18)보다 ~35배 무거움.
  • os drawResidents(라이온14) = 미호출 데드코드(village.js:537 vs frame 854-902).

근본원인 랭킹

  1. [CRITICAL] 정적 타일맵 매프레임 전체 재페인트 — 414타일×6.82=~2,823 fillRect/frame(map 불변인데 캐시 없음, game.js:569-571·389-408). os=buildFaces 1회 베이크→타일 fillRect 0.
  2. [CRITICAL] 루프 게이팅 부재 — 패널이 캔버스 덮어도 ~2,519 call/frame 60fps 지속(game.js:580, render 가드 없음). os=paused로 rAF 정지(village.js:902/955).
  3. [HIGH] ember rgba+toFixed 문자열 ~182~414 String/frame(game.js:401-402).
  4. [HIGH→MED] 엔티티 무컬링 전수순회(game.js:433-489). os=프러스텀(project null)+거리컬.
  5. [MED] 비네트 createRadialGradient 매프레임(불변 리터럴, game.js:574) + drawSky = 2 gradient/frame.
  6. [MED] measureText 매프레임(이름배지, 최대~25/frame).
7-8. [LOW] loadRegion 버스트·forEach 클로저.

총 draw-call: 에덴고 ~3,024 vs village ~948 = 3.2× (오버레이 중 ∞).

os가 가벼운 4원리

정적 베이크(buildFaces 캐싱) · 루프 게이팅(paused) · _cacheT 배치+WASM 오프로드(액터.wasm) · 프러스텀/거리 컬링.

처방 (목표 ~3,024→~50 draw-call/frame ≈ 60×)

  • P0: 정적 타일맵 오프스크린→drawImage(2,823→1) ·· 패널 중 루프정지(2,519→0)
  • P1: 그래디언트 캐시(2→0) · ember 문자열 LUT
  • P2: 엔티티 뷰포트 컬링 · 스프라이트 오프스크린 캐시→drawImage(soul 18→1)
  • P3: measureText Map 캐시

리스크

픽셀동일성(imageSmoothingEnabled=false·정수좌표) · game.js 32KB캡=별도파일 · souls.js:319 로드순서 의존(깨지면 데드 64×64경로 부활) · 타일캐시 dirty무효화(loadRegion·awake토글) · village도 완전무할당 아님(FACES.slice().sort()·flat rgba).

구현 현황

P0/P1 구현+벤치마크 = 별도 포크 진행(edengo-bench.js·edengo-tilecache.js·타일캐시.한선, sw v15). before/after 실측 표는 본 문서/요청문서에 추가됨.

P2 구현 결과 (2026-06-28) — 60× 달성

  • 스프라이트 오프스크린 캐시(edengo-sprites.js): draw→drawRaw+키(spec색/플래그+awake+bob+cell)캐시→drawImage. soul/npc/seed/gardener 18 fillRect→1 drawImage(~18×). 노드/캡처 폴백 drawRaw. 픽셀 byte-identical(source-over 결합·정수좌표·smoothing off).
  • 애니 레이어 분리: 물/ember를 drawTile에서 제거(game.js -166B)→tilecache 오버레이가 가시 물/dark 타일만 매프레임 → 정지 시에도 애니 복원(P0 동결 트레이드오프 해소), 공식 verbatim 일치.
  • 라이온 캐싱 제외(연속 t-애니 동결방지, 소수 엔티티).
  • 결과: 평상 draw-call ~50(목표 60× 달성), 엔티티 ~18×, game.js 32394/32768, sw v16, 라이브 200.
  • 잔여: 미탐험 dark 다수영역 ember LUT 양자화(P1#4)·라이온 애니분리 후 캐싱.