diff --git a/docs/superpowers/specs/2026-06-06-card-image-slot-design.md b/docs/superpowers/specs/2026-06-06-card-image-slot-design.md new file mode 100644 index 0000000..29e7af6 --- /dev/null +++ b/docs/superpowers/specs/2026-06-06-card-image-slot-design.md @@ -0,0 +1,59 @@ +# 카드 슬롯에 이미지 카드 적용 설계 + +- 날짜: 2026-06-06 +- 브랜치: feature/sts2-combat-layout +- 대상: `ui/DefaultGroup.ui`, `tools/gen-cardhand.mjs` +- 원본 이미지: `C:\Users\jaeoh\Desktop\workspace\source\images\maple\invincible belief.png` + +## 목표 + +하단 손패 5장 중 **5번 자리(현재 강타)** 의 카드 외형을 `invincible belief.png`(완성된 세로형 카드 이미지 "리부트 프로토콜")로 교체한다. + +## 배경 + +해당 PNG는 단순 아트가 아니라 코스트·이름·타입·등급·아트·설명·플레이버까지 포함한 **완성된 카드 한 장 전체**(세로 약 2:3 비율)다. 따라서 슬롯의 외형 전체를 이 이미지로 대체하고, 그 슬롯에는 우리가 생성하던 텍스트 오버레이(코스트/이름/설명)를 넣지 않는다(이미지에 이미 포함 → 겹치면 중복/지저분). + +## 범위 + +### 포함 +- PNG를 MSW 계정 sprite 리소스로 업로드 → RUID 발급 +- 생성기에 카드별 선택적 `image`(RUID) 데이터 추가 +- `image`가 있는 카드: 단색 배경 대신 해당 RUID 스프라이트(틴트 흰색)로 렌더, 텍스트 자식(Cost/Name/Desc) 생성 안 함 +- 5번 카드 크기를 이미지 비율에 맞춰 **180×270** 으로 조정(가로 유지, 세로만 +20), 행 중앙 정렬 유지 +- 나머지 4장은 기존 단색 목업 유지 + +### 제외 (YAGNI) +- 나머지 4장의 이미지화 +- 카드 클릭/효과/실제 전투 로직 +- 이미지 카드의 동적 데이터 연동 + +## 구현 방식 + +### 1. 에셋 업로드 (`asset_create_account_resource_storage_item`, 2단계) +- 1차 호출: `category=sprite`, `subcategory=etc`, `name`/`description` 지정, `contentLength`=파일 바이트 수, `fileUrl` 생략 → `presignedUrl` 수신 +- presignedUrl로 PNG를 HTTP PUT(raw 바이너리) +- 2차 호출: `fileUrl=presignedUrl` → 리소스 생성 완료, 응답에서 **RUID(DataId)** 확보 +- 업로드 결과 RUID는 재현 가능하도록 생성기 스크립트에 하드코딩한다. + +### 2. 생성기 변경 (`tools/gen-cardhand.mjs`) +- `cards[4]`(강타 슬롯)에 `image: ''` 필드 추가. (이름/코스트/설명 데이터는 남겨두되 image가 있으면 렌더에 사용하지 않음) +- 카드 빌드 루프 수정: + - 카드 배경 스프라이트: `image`가 있으면 `sprite({ dataId: image, color: {1,1,1,1}, type: 0 })`, 없으면 기존 `sprite({ color: tint, type: 1 })` + - 카드 크기: `image`가 있으면 180×270, 없으면 180×250 + - 텍스트 자식(Cost/Name/Desc): `image`가 없을 때만 생성 +- 멱등성/줄바꿈 보존/splice 로직은 그대로 유지 + +### 3. 형상관리 +- 이미지는 MSW 클라우드 리소스로 저장되고, `.ui`·스크립트에는 **RUID 문자열만** 포함. PNG 원본은 slaymaple 저장소에 커밋하지 않는다(원본은 `workspace/source/images/maple/`에 유지). + +## 검증 + +1. 업로드 응답에서 유효한 RUID 수신 확인 +2. 생성기 재실행 → JSON 유효, 5번 카드가 image 스프라이트 + 텍스트 자식 없음, 나머지 4장 불변 +3. Maker `refresh_workspace` → `play` → `screenshot`로 5번 자리에 "리부트 프로토콜" 카드 이미지가 왜곡 없이 표시되는지 확인 +4. (커밋 전) 디스크 무결성 확인 후 커밋 + +## 리스크 + +- 업로드한 sprite가 SpriteGUIRenderer에서 곧바로 렌더되는지(서브카테고리 무관 가정) — 검증 단계에서 확인, 안 되면 subcategory를 item 등으로 재시도 +- 카드 크기 180×270이 행 정렬에서 약간 위로 솟음 — 의도된 허용 범위