# AGENTS.md 이 저장소에서 작업하는 코딩 에이전트의 공통 지침이다. `CLAUDE.md`도 이 파일을 참조한다. 상세 문서는 아래 표에서 **현재 작업에 해당하는 것만** 읽는다. 규칙·수치를 바꾸면 근거 스펙도 함께 고친다. ## 프로젝트와 작업 흐름 - **Jelly Slice**: 모바일 우선 3D 젤리 절단 게임. TypeScript + Three.js(WebGL2) + 커스텀 GLSL + Vite. 모델·이미지는 절차 생성하고, 절단음은 승인된 WAV 샘플을 쓴다. - 같은 웹 코드를 Capacitor 8 앱으로 감싼다. 번들 ID `game.steadyloop.jelly`, `webDir: dist`, `server.url` 없음(오프라인 번들 사용). 폰은 세로 고정, 태블릿은 회전·크기 변경을 허용한다. - 배포는 Cloudflare **Workers 정적 에셋**이다(`wrangler.jsonc`, `jelly-cutting.steadyloop.dev`). **main 푸시는 운영 배포**를 일으킨다(`.github/workflows/deploy.yml`). - 작업 전 `PROGRESS.md`에서 현재 상태·알려진 문제·다음 할 일을 확인한다. 하위 프로젝트마다 스펙 → 계획 → 구현으로 진행하고, 하위 프로젝트를 머지할 때 `PROGRESS.md`를 갱신한다. - 규칙의 근거는 `docs/superpowers/specs/`, 구현 계획은 `docs/superpowers/plans/`다. 레벨 번호는 G 스펙의 재배치 이후 번호를 쓴다(옛 5~39 → 11~45). - 사용자 응답·코드 주석·커밋 메시지·문서는 한국어, 제품 UI 문구는 영어다. ## 주요 명령 Node.js 24를 권장한다(CI와 동일). 최초 준비는 `npm ci`와 `npx playwright install chromium webkit`이다. ```bash npm run dev # Vite 개발 서버 npm run build # tsc --noEmit + vite build → dist/ npm test # Vitest 전체 npx vitest run tests/CutResolver.test.ts npm run e2e:mobile # main 푸시 전 모바일 Chromium 기능 검사 npm run e2e # Playwright 전체, preview :4173 자동 기동 npx playwright test -g "pointercancel" --project=desktop-chromium npx playwright test --project=perf-desktop-chromium --no-deps npm run deploy # 빌드 + wrangler deploy, CI를 거치지 않는 운영 배포 npm run app:sync # 빌드 + Capacitor 동기화 npm run app:ios # 동기화 + iOS 실행 대상 선택 npm run app:android # 동기화 + 연결된 Android 실기기 실행 ``` - 별도 린터는 없다. `npm run build`의 strict TypeScript 검사를 사용한다. - CI는 단위 테스트·빌드·배포만 수행한다. 시각·입력 변경의 main 푸시 전 E2E 기준은 로컬 `npm run e2e:mobile`이다. 같은 커밋에서 이미 통과했다면 결과를 재사용한다. 전체 `npm run e2e`는 푸시마다 반복하지 않고 변경 범위나 명시적 요청에 따라 개발 중 별도로 실행한다. - Android 빌드는 JDK 21이 필요하다. Android Studio 내장 JBR 경로는 `/Applications/Android Studio.app/Contents/jbr/Contents/Home`이다. - iOS는 SPM이며 프로젝트는 `ios/App/App.xcodeproj`다. 앱 빌드·Jenkins·서명·업로드는 [테스트 상세](docs/agent-reference/testing.md)와 `docs/jenkins-pipeline.md`를 본다. ## 반드시 유지할 구조와 규칙 - 진입점은 `index.html` → `src/main.ts` → `Game.start()`다. `src/core/Game.ts`는 조립·상태 전이·프레임 루프를 맡는다. - 공통 서비스는 `GameClock`·`FeelService`·`PieceStore`·`ProgressService`다. 서비스는 레벨 모드를 모른다. - 모드 동작은 `src/core/modes/`의 `KnifeMode`·`StampMode`·`SlowMode`·`SwipeMode`에 둔다. 모드는 `Game`을 import하지 않고 `ModeHost`를 쓴다. `Game`에 모드별 분기를 추가하지 말고 `GameMode` 훅·`traits`로 연결한다. 기존 예외는 [아키텍처 상세](docs/agent-reference/architecture.md)에 있다. - UI는 모드가 제공한 표시 데이터(`HudView`·`ResultView`)를 그린다. 플랫폼 차이는 `src/platform/`의 `Platform` 어댑터에만 둔다. 저장은 `GameStore`를 통하며 `Game`에서 `localStorage`를 직접 쓰지 않는다. - `src/geometry/`·`src/stages/`와 절단·채점의 순수 로직은 three를 import하지 않는다. 렌더링 계층이 순수 로직의 결과를 소비한다. 정확한 경계는 [절단 상세](docs/agent-reference/cutting.md)에 있다. - 젤리 좌표 `Vec2{x,y}`는 월드 `(x,z)`다. 조각 폴리곤은 원본 젤리 좌표를 유지하고 분리는 `offset`, 출렁임·눌림은 시각 변형으로 표현한다. `PieceData.polygon`을 변형하지 않는다. - 절단과 채점은 독립이다. 가이드에 절단을 스냅하지 않는다. 휘둘러 베기도 실제 진입–이탈 직선을 쓰며 중심·각도를 보정하지 않는다. - 조각은 구멍 없는 단순 다각형(오목 허용)이다. 틀 찍기의 나머지 젤리는 `PieceData`로 만들지 않고 구멍 SDF로 표시한다. 메시·퍼즈 검사의 품질 임계값을 완화하지 않는다. - 새 조각 메시·SDF는 프레임을 나눠 준비한다. 휘둘러 베기 입력 처리에서 동기 메시를 만들지 않는다(`inputMeshBuilds`는 0). 준비 자원의 인계·취소·해제 책임을 유지한다. - 레벨 교체·숨김·컨텍스트 손실 시 장치 입력 취소가 모드 `exit`·`cancelInput`보다 먼저다. 모드는 장치를 중복 취소하지 않는다. 게임 시간은 `GameClock`, 숨김은 `Lifecycle`을 통한다. - `window.__jellyDebug`는 E2E·시각 검수의 공용 계약이다. 이름·시그니처를 바꾸면 관련 E2E와 `e2e/debug-api.spec.ts`도 갱신한다. - 절단음은 medium 3개·swipe 2개·long 1개다. 각각 이득 1, 마스터 0.55·리미터·Sound 토글·생명주기를 유지한다. long은 썰기 중 반복하며 별도 마무리 소리를 내지 않는다. 출처는 `src/audio/samples/SOURCES.md`다. ## 테스트에서 자주 걸리는 점 - Chromium E2E는 `playwright.config.ts`의 GPU·오디오 활성화 인자를 유지한다. `npm run e2e:mobile`은 모바일 기능 프로젝트만 실행한다. 전체 `npm run e2e`를 선택하면 기능 3프로젝트 뒤 성능 프로젝트를 데스크톱 → 모바일 순서로 단독 실행한다(설정의 dependencies). - :4173에 기존 preview가 있으면 옛 `dist/`로 테스트할 수 있다(`reuseExistingServer`). 결과가 변경을 반영하지 않으면 해당 서버를 확인한다. E2E 중에는 `dist/`를 덮는 빌드를 실행하지 않는다. 성능 A/B 중에는 `src`도 바꾸지 않는다. - E2E 진입은 `e2e/helpers.ts`의 `openLevel()`을 사용하고 `ready`·`canDraw()` 및 필요한 첫 프레임 상태를 기다린다. 모드별 도우미는 `e2e/helpers/{common,slow,swipe}.ts`에 있다. - 연출 중 최대·최소값은 `installSampler`/`sampled`로 기록한다. 결과 카드 위 HUD Home은 `pressHudHome`으로 누른다. 회전판 정답 절단은 `freezePlate`로 판을 세운다. - 부하 때문에 실패한 테스트는 해당 파일을 단독 재실행하고 최초 실패·재실행 결과를 함께 기록한다. `npx vitest list`는 퍼즈 파일에서 실패하므로 목록 비교 시 퍼즈 파일을 제외한다. - 셸 스크립트는 macOS bash 3.2 호환을 유지한다(연관 배열 없음). `gh` CLI 가용성 등 환경 상태는 필요할 때 확인한다. ## 기기 테스트 정책 - Android 에뮬레이터·AVD는 설치·생성·실행·테스트에 사용하지 않는다. ADB로 실제 기기 연결과 디버깅 승인을 확인한다. 없으면 실기기 연결·USB 디버깅 승인(무선은 페어링·연결)을 요청하고, 가능한 빌드·정적 분석·단위 테스트를 진행한다. 기기 검증은 미완료로 명시한다. - iOS 빌드·테스트 시작 시 기존 시뮬레이터와 테스트 복제본 목록을 기록한다. 종료 후 성공·실패·취소와 관계없이 이번 작업에서 생성한 복제본(XCTestDevices 포함)만 종료·삭제하고 잔여 여부를 확인한다. 다른 작업·기본 기기·런타임·실제 기기 데이터는 삭제하지 않는다. 보존 요청 또는 정리 실패는 대상과 사유를 보고한다. ## 시각 검수와 리뷰 - 시각 변경 전 화면·상태·해상도 범위와 반복 캡처·독립 리뷰에 따른 사용량 증가 가능성을 알리고, **기초 구현 + 사용자 시각 조정**과 **Superpowers 전체 시각 검수** 중 적합한 방식을 이유와 함께 추천하여 선택받는다. 이번 작업에서 이미 선택했다면 다시 묻지 않는다. 선택 없이 임의로 진행하지 않는다. - 기초 구현은 리소스·참조·동작 연결과 필수 컴파일·테스트·기능 검증까지 한다. 반복 화면 비교·취향에 따른 시각 수정은 하지 않는다. 조정 대상·방법을 인계하고 시각 검수는 사용자 담당/미완료로 명시한다. - 전체 검수는 계획한 화면·상태·해상도에 따라 캡처·비교·수정·재검토한다. 기본 해상도는 데스크톱 1280×800·모바일 390×844이며 리뷰 주체도 계획에 적는다. 범위가 크게 늘면 추가 실행 전에 알린다. 캡처 스크립트·결과는 `.playwright-mcp/`에 둔다(gitignore). - 어느 방식이든 Native/SDD 코드 리뷰·최종 독립 리뷰를 유지한다. 기초 구현의 사용자 담당 시각 검수를 완료로 판정하지 않는다. - Superpowers 최종 독립·전체 브랜치·새 컨텍스트 리뷰 기본값은 **`gpt-6.1-sol` / `medium`**이다. 도구에 두 값을 명시하며 사용자 지정값이 있으면 지정 항목을 우선한다. 지원하지 않으면 대체하지 말고 제한을 알린다. ## 작업별 상세 문서 아래 문서는 자동으로 모두 가져오지 않는다. 해당 영역을 수정·검증할 때 필요한 문서와 근거 스펙을 읽는다. 상세 API의 최종 기준은 코드다. | 작업 | 상세 문서 | 주요 진입점 | |---|---|---| | 프로젝트 배경·스펙 관계 | [프로젝트 배경](docs/agent-reference/project.md) | `PROGRESS.md`, `docs/superpowers/specs/` | | 네이티브 빌드·E2E 선택·성능 A/B·캡처 | [테스트 상세](docs/agent-reference/testing.md) | `playwright.config.ts`, `e2e/helpers.ts`, `docs/superpowers/refactor-baseline.md` | | 상태 조회·시간 제어·화면 좌표 | [디버그 API](docs/agent-reference/debug-api.md) | `src/core/JellyDebug.ts`, `src/core/GameDebug.ts` | | 서비스·모드 추가·프레임 훅·자원 인계 | [아키텍처 상세](docs/agent-reference/architecture.md) | `src/core/modes/GameMode.ts`, `src/core/Game.ts` | | 계층·좌표계·절단·채점 | [절단 상세](docs/agent-reference/cutting.md) | `src/cutting/CutResolver.ts`, `src/stages/StageSession.ts` | | 형상·셰이더·메시·식칼/메스 연출 | [렌더링 상세](docs/agent-reference/rendering.md) | `src/jelly/`, `src/core/knife/`, `tests/meshFuzz.ts` | | 틀 찍기40~45·천천히 썰기5~10·휘둘러 베기46~58 | [모드 상세](docs/agent-reference/modes.md) | `src/core/modes/`, `src/core/{slow,swipe}/` | | 앱 생명주기·저장·레벨 구성·이관 | [플랫폼·레벨 상세](docs/agent-reference/platform-levels.md) | `src/platform/`, `src/stages/LevelDefinitions.ts`, `src/stages/LevelMigration.ts` | ## 웹 기획서 스킬 - `/docs-site 반영할 내용`, `$docs-site 반영할 내용` 또는 `DocsSite` 기획서 생성·수정 요청은 `.agents/skills/docs-site/SKILL.md`를 읽고 따른다. 슬래시 메뉴 자동 등록과는 별개인 프로젝트 호출 규칙이다. - `DocsSite/`가 없으면 최초 생성하고, 있으면 기존 구조를 유지하며 수정한다. Windows와 macOS 공통 실행을 지원한다. - 이 작업에서는 브랜치·worktree를 만들거나 전환하지 않고 현재 브랜치를 유지한다. 기존 내용 삭제·의미 폐기·전체 교체는 구체적인 대상을 제시하고 사용자 확인 후 실행한다.