---
name: minigames-add
description: 신규 미니게임을 계약에 맞게 새로 제작해 카탈로그에 추가한다. 사용자가 "새 게임 추가", "미니게임 만들어줘", "게임 하나 새로 만들자", "새 미니게임 제작", "add a minigame", "create a new game", "build a new minigame"를 요청하면 리서치 참조 → templates/ 스캐폴드 → 구현 → 프로브 풀 게이트 통과 후에만 manifest에 등록한다.
---

# minigames-add — 신규 게임 제작·등록

> `docs/CONTRACT.md`(동결 계약)를 따르는 신규 게임을 `templates/` 스캐폴드에서 구현하고, `node probes/run-all.mjs` 풀 게이트를 통과한 경우에**만** `catalog/manifest.json` 에 등록한다. 계약 SSOT 는 `docs/CONTRACT.md`, 변환 레시피는 `docs/CONVERSION.md`.

## Triggers (트리거 문구)

- 한글: "새 게임 추가", "미니게임 만들어줘", "게임 하나 새로 만들자", "새 미니게임 제작", "게임 추가해줘"
- English: "add a minigame", "create a new game", "build a new minigame", "make a new game", "author a minigame"

## Purpose

리서치 근거로 시작해, 계약(계층 1 game.js / 계층 2 logic.js / strings.json / meta.json / style.css)을 만족하는 게임을 새로 만든다. **프로브 게이트가 그린일 때만 카탈로그에 편입** — 게이트 실패 게임은 등록하지 않는다(카탈로그는 검증된 게임의 SSOT).

## Use When

- 사용자가 카탈로그에 없는 새 게임을 만들고 싶어 할 때.
- `minigames-research` 리포트가 있고 그걸 실제 게임으로 구현할 때.
- **Use When NOT**: 기존 게임을 프로젝트에 넣는 거면 `minigames-embed`. 개념이 아직 흐리면 먼저 `minigames-research`.

## AskUserQuestion 사용 지점

- **게임 개념·메커닉을 확정할 때 질문한다.** 구현 전에 `AskUserQuestion` 으로:
  1. **어떤 게임/핵심 동사** — 무엇을 하는 게임인가? (리서치 리포트가 있으면 그 권고안을 후보로 제시.)
  2. **아키타입** — self-authored(자체 로직) · curated-library(사전 저작 풀) · expuzzles-backed(외부 로직 어댑트) 중 무엇인가? (리서치 권고를 첫 옵션으로.)
  3. **난이도 축(3티어)** — easy/medium/hard 를 가르는 파라미터는? (격자·개수·시간·제약 등. 인지·탐색 비용이 단조 증가하도록.)
- 각 질문은 Claude 추천안을 첫 옵션으로 표시(뒤에 "(추천)")해 사용자가 고르거나 비틀게 한다. 리서치 리포트로 이미 확정된 항목은 확인만 한다.

## Steps

1. **리서치 참조** — `research/` 에 관련 리포트가 있으면 읽는다. **없으면 `minigames-research` 를 선행 호출**해 근거를 먼저 만든다(개념·난이도 설계·계약 적합성).
2. **개념 확정** — 위 AskUserQuestion 으로 게임·아키타입·난이도 축을 정한다. 새 `<id>`(kebab-case 영문 소문자, 기존 24종·디렉터리명과 충돌 없음) 를 정한다.
3. **스캐폴드** — `templates/` 에서 `games/<id>/` 로 골격을 복사·치환한다:
   - `templates/game.js` → `games/<id>/game.js` (계층 1: `MiniGame.meta.id="<id>"`, `params.{easy,medium,hard}`, `create→{destroy}`).
   - `templates/logic.js` → `games/<id>/logic.js` (계층 2: `createPuzzle/applyMove/isSolved/selfTest`, 순수).
   - `templates/strings.json` → `games/<id>/strings.json` (`{ko,en}` — 한글 리터럴 전량 여기로).
   - `templates/meta.json` → `games/<id>/meta.json` (CONTRACT §8 스키마).
   - `templates/style.css` → `games/<id>/style.css` (`--mg-*` 변수만).
   - `templates/README.md` 는 복사하지 않는다(사용법 안내용).
4. **구현** — 플레이스홀더(`<id>` 등)·`TODO` 마커를 실제 로직으로 채운다. 반드시 지킬 인바리언트(CONTRACT §5 · CONVERSION §5):
   - 판 생성은 `ctx.rng` 만 소비(create 진입 시 `createPuzzle` 정확히 1회). 입력마다 rng draw 금지.
   - 시각 연출은 `Math.random` 만. `logic.js` 는 DOM/타이머/`Math.random` 금지(순수).
   - `game.params[difficulty]` 에 `createPuzzle` 이 쓰는 파라미터를 **전부** 담는다(엔진은 game.params 만 병합 — CONTRACT §12.3).
   - 한글 리터럴 0(전량 strings.json), 페이지 전역 id 금지(컨테이너 스코프), 하드코딩 색 금지(`--mg-*`).
   - `onResult` 정확히 1회(`{cleared, score, performanceRatio, elapsedMs, stats}`).
5. **프로브 작성** — `probes/<id>.probe.cjs` 를 기존 프로브(같은 아키타입) 구조로 작성한다. 결정론 diff-0 · rng 오염 가드 · 순수성 · 한글 잔존 · 단조성(solver/param-band) 검사.
6. **풀 게이트** — `node probes/run-all.mjs` 를 실행한다. **ALL GREEN 이 아니면 등록하지 않는다** — 실패 항목을 프로덕션 코드에서 고치고 재실행(테스트를 통과시키려 프로브를 무르게 고치지 않는다).
7. **manifest 등록(그린일 때만)** — 게이트 통과 후 `node scripts/build-catalog.mjs` 를 실행해 `games/<id>/meta.json` 이 `catalog/manifest.json` 에 집계되게 한다(스크립트가 검증·재생성). 실패하면 meta.json 스키마를 고친다.

## 산출물 경로 규약

- **`games/<new-id>/`** — game.js · logic.js · strings.json · style.css · meta.json (+ 데이터 파일 게임이면 puzzles.js/json). thumbnail.png 는 하네스 자동 캡처(직접 안 만듦).
- **`probes/<new-id>.probe.cjs`** — 게이트용 프로브.
- **`catalog/manifest.json`** — `build-catalog.mjs` 가 재생성(직접 편집 금지 — meta.json 이 소스).

## 실패 시 폴백

- **리서치 부재** → `minigames-research` 를 먼저 실행(1단계). 리서치 없이 바로 만들지 않는다.
- **프로브 게이트 레드** → 실패 원인(결정론 깨짐·rng 오염·순수성 위반·한글 잔존·단조성 밴드 미분리)을 프로덕션 코드에서 고치고 `run-all.mjs` 재실행. 3회 시도해도 같은 항목이 막히면 아키타입 선택이 잘못됐는지(예: 순수 분해 부적합) 재검토하고 CONTRACT §10 어댑터 폴백을 고려. **미등록 상태를 유지**한다 — 게이트 실패 게임은 카탈로그에 넣지 않는다.
- **build-catalog 검증 실패** → meta.json 의 필수 필드/enum(archetype·monotonicityProxy)을 CONTRACT §8 대로 교정. 스크립트는 실패 시 manifest 를 쓰지 않으므로(절반 상태 방지) 카탈로그는 안전.
- **id 충돌** → 다른 `<id>` 로 다시 시작(디렉터리명과 meta.id 는 일치해야 함).
