Files
maplecontest/docs/superpowers/specs/2026-06-16-generator-modularization-design.md
gahusb 064d81d424 docs(spec): 생성기 모듈화(Phase 1) + 하이브리드 UI 로드맵 설계
gen-slaydeck.mjs UI emit 16종을 lib/+hud/ 모듈로 분리(출력 바이트 동일·무위험).
codeblock 메서드 제외. 하이브리드 단계적: Phase2 캐릭터선택 메이커 저작 파일럿.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 02:20:53 +09:00

7.1 KiB
Raw Permalink Blame History

생성기 모듈화 (Phase 1) + 하이브리드 UI 로드맵 설계

작성일: 2026-06-16 브랜치: feature/gen-modularization

배경 / 동기

DefaultGroup.ui에 모든 UI(캐릭터 선택·상점·전체 덱·전투…)가 들어 있어, 사용자가 (a) 생성기 코드 유지보수와 (b) 메이커에서 기능별 시각 편집을 원함.

핵심 제약(브레인스토밍에서 확정): MSW에서 "Layer"는 렌더 z순서일 뿐 논리 분리 도구가 아니고, 실제 UI 그룹 단위는 UIGroup(.ui 파일 = UIGroup, 현재 Default/Popup/Toast 3개). 그리고 같은 UI를 '생성'과 '메이커 수동 편집' 둘 다로 둘 수 없음(재생성이 수동 편집을 덮어씀).

소유 모델 = 하이브리드·단계적(사용자 승인): 정적 레이아웃은 메이커 저작(시각 편집), 동적 내용은 컨트롤러가 런타임 주입. 단, 한 번에 안 하고 단계적으로.

로드맵 (단계적 — 각 Phase가 자체 spec→plan)

  • Phase 1 (이 문서): gen-slaydeck.mjs(~6,200줄)의 UI emit을 기능별 모듈로 분리. 출력 .ui/codeblock 바이트 동일(순수 리팩터·무위험). (a) 충족 + (b) 토대(화면별 파일).
  • Phase 2 (후속 spec): 화면 1개(캐릭터 선택) 파일럿 — 정적 레이아웃을 메이커 저작 UIGroup으로 이관, 생성기는 그 화면 emit 중단, SlayDeckController가 경로로 내용(이미지·텍스트) 주입. (b) 패턴 검증.
  • Phase 3 (후속 spec): 검증되면 상점·전체덱 등으로 확장.

현재 구조 (조사 결과)

  • 공유 인프라(~48530): luaSoulShopTable/luaFramesTable/luaNodeIconsTable/luaRelicsTable/luaPotionsTable/luaIntentsArray/luaEnemiesTable/luaStr/luaJobsTable/luaCardsTable/luaDeckTable/frameRuid/cardFaceLayout/guid/transform/sprite/button/text/scrollLayoutGroup/entity/uiPath/sectionRoot/isGeneratedUiEntity/appendUiSection. 데이터 로드 상수(CARDS/CHARS/ENEMIES/RELICS/POTIONS/CARDFRAMES/NODEICONS/CAM) 및 색·치수 상수(GOLD/WHITE/TRANSPARENT/ALIGN_*/CARD_W/CARD_H 등).
  • guid(prefix, n)은 순수 함수(:284, 내부 카운터 없음; ns는 prefix→바이트 매핑). 모듈 호출 순서와 무관하게 동일 guid → 분리해도 바이트 동일.
  • upsertUi()(:529)가 UI 오케스트레이터: 기존 DefaultGroup.ui 로드 → 생성 섹션 필터(stock 보존) → 로컬 emit(section, entities) 클로저로 누적 → CardHand 스톡카드 in-place upsert(:565691, 특수) → HUD별 const x=[]; const add=…; add(entity(...)); …; emit('X', x) → (말미) 병합·기록.
  • HUD emit 16종(순서·라인): DeckHud(:808) · DeckInspectHud(:942) · DeckAllHud(:1097) · CombatHud(:1587) · RewardHud(:1681) · MapHud(:1839) · ShopHud(:2038) · RestHud(:2095) · TreasureHud(:2181) · JobChoiceHud(:2229) · JobSelectHud(:2314) · MainMenu(:2616) · CharacterSelectHud(:2617) · LobbyHud(:2672) · BoardHud(:2727) · SoulShopHud(:2814). 각 섹션은 서로의 지역변수 비참조(헬퍼·데이터 상수만 사용).
  • codeblock 메서드(prop/method/codeblock/writeCodeblocks :28366124, ~3,200줄) + patchCommon(:6125). Phase 1 범위 제외.

Phase 1 상세 설계

목표 파일 구조

tools/deck/
  gen-slaydeck.mjs        # 오케스트레이터(축소): import lib+hud → 데이터 로드 → upsertUi(HUD 모듈 순차) → writeCodeblocks → patchCommon
  lib/
    ui-helpers.mjs        # guid, transform, sprite, button, text, entity, scrollLayoutGroup,
                          #   상수(GOLD/WHITE/TRANSPARENT/ALIGN_*/CARD_W/CARD_H/UI_ROOT 등), cardFaceLayout,
                          #   uiPath/sectionRoot/isGeneratedUiEntity/appendUiSection
    data.mjs              # CARDS/CHARS/ENEMIES/RELICS/POTIONS/CARDFRAMES/NODEICONS/CAM 로드·검증
                          #   + luaXxxTable·frameRuid
  hud/
    deckhud.mjs deckinspect.mjs deckall.mjs combat.mjs reward.mjs map.mjs
    shop.mjs rest.mjs treasure.mjs jobchoice.mjs jobselect.mjs mainmenu.mjs
    charselect.mjs lobby.mjs board.mjs soulshop.mjs

모듈 계약

  • hud/<name>.mjs: export function build<Name>() → 자기 HUD 엔티티 배열 반환. 필요한 헬퍼·상수·데이터는 lib/에서 import(거대 deps 객체 전달 금지).
  • upsertUi()(오케스트레이터에 잔류)는 기존 순서 그대로 emit('DeckHud', buildDeckHud())emit('SoulShopHud', buildSoulShop()) 호출. emit·섹션 병합 로직 불변.
  • CardHand 스톡카드 in-place upsert(:565691)는 기존 .ui 엔티티를 변형하는 특수 로직 → 오케스트레이터(또는 hud/cardhand.mjs)에 그대로 유지. import 경계만 정리.

바이트 동일 불변식 (가장 중요)

  • 리팩터는 출력 변경 0이 목표. 보장 근거: guid 순수·emit 순서·entity 구성 모두 보존, 로직 이동만.
  • 합격 기준: 리팩터 후 node tools/deck/gen-slaydeck.mjsgit diff 결과가 ui/DefaultGroup.ui·SlayDeckController.codeblock에 0 변경(Global/common.gamelogic은 LF churn만 허용 → git checkout).

증분 실행 전략

  • 한 번에 16개 다 옮기지 말고 HUD 1~2개씩 추출 → 재생성 → git diff 빈 결과 확인 → 커밋 반복. 첫 추출(예: SoulShopHud 같은 말단 + lib 골격) 성공 후 패턴 반복.
  • lib 추출(헬퍼·상수·데이터) 먼저 → 그 다음 HUD 모듈을 하나씩 lib import로 전환.

미러/테스트·하네스

  • 전투규칙·맵생성 Lua 무변경sim-balance/rogue-map 미러 동기화 불필요(회귀 확인차 node --test 실행).
  • RULES 동기화: 생성기가 다중 파일이 되므로 RULES §1 "단일 소스"/보조 생성기 표를 tools/deck/(gen-slaydeck + lib/ + hud/)로 갱신.

범위 밖 (명시)

  • codeblock 메서드(method() ~3,200줄) 분리 — 더 크고 (b)와 무관·리스크↑. 원하면 별도 Phase 1b spec.
  • 게임 동작·데이터·런타임 로직 변경. (순수 소스 리팩터)
  • UIGroup 분할·메이커 저작 이관 — Phase 2 이후.

리스크

  • 클로저 참조(헬퍼/상수)를 import로 전환하는 광범위·기계적 수정 — 누락 시 런타임 throw 또는 출력 diff로 즉시 노출(바이트 검증이 안전망).
  • 상수 정의 위치 산재(CARD_W·GOLD·UI_ROOT 등 top-level) — lib로 이동 시 누락 주의. 추출 전 grep으로 전체 상수 인벤토리 작성.
  • ESM 순환 import 주의(lib는 hud를 import하지 않음 — 단방향: orchestrator→hud→lib).

변경 파일 요약

파일 변경
tools/deck/lib/ui-helpers.mjs, lib/data.mjs 신설 — 공유 헬퍼·상수·데이터
tools/deck/hud/*.mjs (16) 신설 — HUD별 build 함수
tools/deck/gen-slaydeck.mjs 오케스트레이터로 축소(데이터/UI emit 본문 → 모듈로 이동, import·호출만)
RULES.md §1 보조 생성기/단일소스 표에 lib/·hud/ 반영
ui/DefaultGroup.ui·SlayDeckController.codeblock 무변경(바이트 동일이 합격 기준)