Files
basket_utils/농구 전술보드 웹앱 MVP 작업지시서.md

976 lines
16 KiB
Markdown

# 농구 전술보드 웹앱 MVP 작업지시서
## 코드 작업 담당 모델
실제 코드 구현·수정·리팩터링·테스트 코드 작성은 **GPT-5.6 Luna (`gpt-5.6-luna`)**에게 지시한다. 주 에이전트는 조사·설계·작업 지시·검토·검증을 담당하며, 문서는 직접 수정할 수 있다. 구체적인 작업 규칙은 [AGENTS.md](./AGENTS.md)를 따른다.
## 1. 프로젝트 목표
Three.js 기반의 웹 농구 전술보드 MVP를 구현한다.
편집 화면은 전체 코트를 보기 편한 **쿼터뷰 2.5D 스타일**로 제공하되, 내부 월드 좌표는 실제 3D 좌표계를 사용한다.
사용자가 선수별 이동 경로와 시선을 간단하게 지정하면 이를 Sequence 단위로 저장하고, 재생 시 전체 전술 또는 특정 선수의 POV(Player View)로 확인할 수 있어야 한다.
핵심 방향은 다음과 같다.
- 사용자가 입력해야 하는 정보는 최소화
- 선수 이동 위치만 지정해도 기본 전술 재생 가능
- Facing, LookAt, Duration 등은 가능한 한 자동 계산
- 동일한 전술 데이터를 쿼터뷰와 선수 POV에서 함께 사용
- 추후 패스, 스크린, Read/Decision 등으로 확장 가능한 구조
---
# 2. 기술 스택
기본 기술 스택은 다음을 사용한다.
- Vanilla JavaScript
- Three.js
- HTML
- CSS
- Vite
- ES Module
초기 MVP에서는 별도의 React/Vue 등의 프레임워크를 사용하지 않는다.
Three.js의 Scene/Object3D 구조와 앱 상태 관리를 명확하게 분리한다.
---
# 3. 핵심 데이터 모델
전체 구조는 다음 개념으로 구성한다.
```text
Play
├─ Players
├─ DefenseType
└─ Sequences[]
└─ PlayerTracks
└─ Actions[]
```
## Play
하나의 완성된 전술.
예시:
```js
{
id: "play-001",
name: "Horns Entry",
defenseType: "man-to-man",
sequences: []
}
```
---
## Sequence
Sequence는 하나의 프레임이 아니다.
**여러 선수가 동시에 행동하는 하나의 전술 구간**으로 정의한다.
예:
```text
Sequence 1
1번
- 4번에게 접근
- 우측 엘보 방향으로 이동
4번
- 볼 캐치
- 핸드오프 준비
2번
- 코너 유지
5번
- 엘보 유지
```
각 Sequence의 모든 선수 행동이 종료되면 다음 Sequence로 넘어간다.
---
## PlayerTrack
하나의 Sequence 내부에서 특정 선수가 수행하는 행동 묶음.
```js
{
playerId: "offense-1",
actions: []
}
```
---
## Action
기존의 move보다 포괄적인 단위로 사용한다.
기본 구조는 다음과 같이 설계한다.
```js
{
id: "action-001",
location: {
x: 0,
z: 0
},
facing: null,
lookAt: null,
type: "move",
targetPlayerId: null
}
```
초기 MVP에서는 다음 필드 위주로 구현한다.
- location
- facing
- lookAt
- type
향후 다음 Action Type을 확장할 수 있도록 설계한다.
```text
move
pass
screen
dribble
shoot
hold
```
---
# 4. 코트 좌표계
화면 pixel 좌표를 데이터에 직접 저장하지 않는다.
실제 농구 코트 기준 좌표계를 사용한다.
예:
```text
X축 = 코트 좌우
Z축 = 코트 길이 방향
Y축 = 높이
```
Three.js에서는:
```js
player.position.set(x, y, z);
```
형태로 그대로 사용할 수 있도록 한다.
MVP에서는 하프코트를 우선 구현해도 된다.
코트 위치를 선택할 때 내부적으로 Grid Snap을 적용할 수 있도록 한다.
Grid는 화면에 항상 표시할 필요는 없다.
---
# 5. Three.js Scene
Scene은 하나만 사용한다.
```text
Three.js Scene
├─ Tactical Camera
└─ Player POV Camera
```
## Tactical Camera
전술 편집 및 전체 플레이 재생용 카메라.
쿼터뷰 형태로 제공한다.
카메라는 고정된 각도를 기본으로 한다.
예:
```text
높은 위치
+
골대 방향을 내려다보는 Perspective View
```
MVP에서는 자유로운 3D 카메라 회전 기능은 필요하지 않다.
---
## Player POV Camera
특정 선수의 시점에서 전술을 재생하기 위한 카메라.
선택한 선수 위치를 기준으로 한다.
개념:
```js
camera.position =
player.position + eyeHeight
```
시선은 해당 Action의 lookAt 데이터를 기준으로 계산한다.
---
# 6. 선수 표현
초기 MVP에서 현실적인 3D 인간 모델은 사용하지 않는다.
다음과 같이 단순화한다.
```text
Court
→ 3D Plane
Players
→ Billboard Sprite 또는 단순 Capsule/Cylinder
Ball
→ Sphere
Basket
→ 간단한 Low-poly Object
Move Path
→ Three.js Line
LookAt
→ Arrow 또는 Cone
```
공격과 수비는 명확하게 구분될 수 있어야 한다.
선수에는 번호를 표시한다.
예:
```text
O1
O2
O3
O4
O5
D1
D2
D3
D4
D5
```
---
# 7. 전술 생성 UX
새 전술을 생성할 때 다음 정보를 받는다.
```text
전술 이름
수비 형태
- Man to Man
- 2-3 Zone
- 3-2 Zone
```
전술 생성 시 자동으로:
```text
Sequence 1
```
을 생성한다.
공격 5명과 수비 5명도 기본 배치한다.
수비 전술 선택에 따라 초기 수비 위치를 자동 배치한다.
---
# 8. 기본 LookAt 자동 설정
사용자가 모든 Action마다 시선을 직접 입력하지 않도록 한다.
기본 규칙을 구현한다.
## 공격
볼 핸들러:
```text
lookAt → Rim
```
오프볼 공격자:
```text
lookAt → Ball
```
## 수비
Man to Man:
```text
기본적으로 매치업 상대 또는 Ball 방향
```
Zone Defense:
```text
Ball / 자신의 담당 Zone 방향
```
MVP에서는 수비 LookAt 로직을 단순화해도 된다.
사용자가 LookAt을 직접 설정한 경우 자동값보다 사용자 설정값이 우선한다.
---
# 9. Facing 자동 계산
사용자가 Facing을 직접 입력하지 않아도 되도록 한다.
Action N에서 Action N+1로 이동하는 경우:
```text
현재 위치
다음 위치
```
벡터를 계산해서 기본 Facing을 자동 지정한다.
예:
```js
direction = nextPosition - currentPosition
rotationY = atan2(...)
```
이동하지 않는 선수의 기본 Facing은 LookAt 방향을 사용할 수 있다.
사용자 override 기능은 추후 쉽게 추가 가능하도록 데이터 구조만 준비한다.
---
# 10. Action 입력 UX
사용자가 선수 하나를 선택한다.
이후 코트 위치를 계속 클릭하면 해당 선수의 Action이 연속 생성된다.
예:
```text
1번 선택
코트 클릭
→ Action 1
코트 클릭
→ Action 2
코트 클릭
→ Action 3
```
즉 사용자가 별도의:
```text
Action 추가
Move 추가
Duration 입력
```
같은 작업을 반복할 필요가 없어야 한다.
가능한 한:
```text
선수 선택
→ 위치 클릭
→ 위치 클릭
→ 위치 클릭
```
만으로 경로를 만든다.
---
# 11. LookAt 입력 UX
LookAt은 기본 자동값을 사용한다.
사용자가 특정 Action의 LookAt을 수정하고 싶은 경우에만 설정한다.
예:
```text
선수 선택
→ 특정 Action 선택
→ LookAt 모드
→ 다른 선수 또는 코트 위치 클릭
```
LookAt target은 다음을 지원할 수 있도록 설계한다.
```text
rim
ball
player
location
```
예:
```js
lookAt: {
type: "player",
targetId: "offense-4"
}
```
또는:
```js
lookAt: {
type: "location",
x: 4.2,
z: 6.1
}
```
---
# 12. Sequence 편집
화면 하단 또는 측면에 Sequence UI를 둔다.
예:
```text
[Sequence 1] [Sequence 2] [Sequence 3] [+]
```
현재 Sequence를 선택하면 해당 Sequence의 선수 위치와 Action 경로를 편집한다.
새 Sequence 생성 시:
**직전 Sequence의 마지막 위치를 새로운 Sequence의 시작 위치로 자동 상속한다.**
즉 사용자가 선수 위치를 다시 배치할 필요가 없어야 한다.
---
# 13. Sequence Duration 자동 계산
사용자가 Duration을 직접 입력하지 않게 한다.
각 PlayerTrack의 예상 수행시간을 자동 계산한다.
기본적으로:
```text
이동거리 / 기본 선수 이동속도
```
를 기반으로 한다.
예:
```text
Player 1 = 2.8초
Player 2 = 0.9초
Player 3 = 0초
Player 4 = 1.4초
Player 5 = 0초
```
Sequence Duration은:
```text
max(PlayerTrack duration)
```
으로 자동 결정한다.
위 예에서는:
```text
Sequence Duration = 2.8초
```
이다.
Player 2는 0.9초에 Action이 끝난 후:
```text
0.9초 ~ 2.8초
마지막 위치 유지
```
한다.
모든 선수는 동시에 다음 Sequence로 넘어간다.
---
# 14. Action Playback
Action 사이의 위치는 부드럽게 보간한다.
Three.js의 Vector3.lerp 또는 유사 interpolation을 사용한다.
예:
```text
Action 1
interpolation
Action 2
```
Facing 역시 갑자기 회전하지 않고 자연스럽게 보간한다.
LookAt 역시 Action 사이에서 가능한 경우 자연스럽게 변화시킨다.
---
# 15. 전체 전술 재생
Play 버튼을 누르면:
```text
Sequence 1
Sequence 2
Sequence 3
...
```
순서대로 자동 재생한다.
UI:
```text
▶ Play
⏸ Pause
⏹ Reset
```
정도만 우선 구현한다.
Playback은 기본 Tactical Camera에서 실행한다.
---
# 16. Player POV 재생
공격 선수를 선택한 후:
```text
Player View
```
버튼을 누르면 해당 선수 POV로 전환한다.
예:
```text
[ Tactical View ]
[ Player 1 POV ]
[ Player 2 POV ]
...
```
Player POV 재생 중 카메라는 선수 이동을 따라간다.
Camera Position:
```text
player location
+
eye height
```
Camera Direction:
```text
lookAt
```
을 기준으로 한다.
lookAt이 없는 경우:
```text
facing
```
을 사용한다.
---
# 17. 시야 시각화
편집 화면에서 선택된 선수의 시야를 시각적으로 표현한다.
예:
```text
╱────────
/
Player ───────→ LookAt
\
╲────────
```
구현 방식은:
- Arrow
- Line
- Sector
- Cone
중 간단한 방식으로 먼저 구현한다.
MVP에서는 LookAt 방향 Arrow만 구현하고, 이후 Vision Cone으로 확장해도 된다.
---
# 18. 상태 관리
Three.js Object 자체를 전술 데이터의 Source of Truth로 사용하지 않는다.
반드시:
```text
Application State
Three.js Renderer
```
형태로 분리한다.
즉:
```js
play.sequences[0].playerTracks...
```
가 실제 데이터이고,
Three.js Scene은 이를 렌더링하는 역할만 한다.
사용자가 선수를 이동하면:
```text
UI Interaction
→ State 변경
→ Scene 업데이트
```
순서를 따른다.
이 구조는 추후:
- 저장
- 불러오기
- Undo/Redo
- 서버 연동
- 공유
- Replay
구현을 쉽게 하기 위함이다.
---
# 19. 파일 구조
과도하게 복잡하게 만들지 말고 기능 기준으로 분리한다.
예:
```text
src/
├─ main.js
├─ three/
│ ├─ scene.js
│ ├─ court.js
│ ├─ player.js
│ ├─ cameras.js
│ └─ renderer.js
├─ domain/
│ ├─ play.js
│ ├─ sequence.js
│ ├─ action.js
│ └─ player.js
├─ playback/
│ ├─ playbackController.js
│ ├─ interpolation.js
│ └─ durationCalculator.js
├─ editor/
│ ├─ playerSelection.js
│ ├─ actionEditor.js
│ ├─ lookAtEditor.js
│ └─ sequenceEditor.js
├─ state/
│ └─ playStore.js
└─ ui/
├─ toolbar.js
├─ sequenceBar.js
└─ controls.js
```
불필요한 클래스화나 추상화는 피한다.
---
# 20. MVP 화면 구성
하나의 메인 화면으로 시작한다.
```text
┌───────────────────────────────────────┐
│ Play Name Defense: Man to Man │
├───────────────────────────────────────┤
│ │
│ │
│ THREE.JS COURT │
│ │
│ │
├───────────────────────────────────────┤
│ Sequence 1 | Sequence 2 | + │
├───────────────────────────────────────┤
│ Move | LookAt | Play | Player View │
└───────────────────────────────────────┘
```
편집 화면이 최대한 넓게 보이도록 한다.
---
# 21. 구현 우선순위
다음 순서대로 구현한다.
## Phase 1
Three.js 기본 Scene 구축.
- Court
- Basket
- 공격 5명
- 수비 5명
- Tactical Camera
- Player Selection
---
## Phase 2
전술 데이터 모델 구현.
- Play
- Sequence
- PlayerTrack
- Action
- State ↔ Renderer 연결
---
## Phase 3
Action 편집.
- 선수 선택
- 코트 클릭
- Action.location 추가
- 이동 경로 표시
- Action 삭제
---
## Phase 4
Sequence.
- Sequence 추가
- Sequence 선택
- 직전 Sequence 위치 상속
- Sequence 삭제
---
## Phase 5
Playback.
- Action interpolation
- PlayerTrack duration 자동 계산
- Sequence duration 자동 계산
- Sequence 순차 재생
- Play/Pause/Reset
---
## Phase 6
Facing / LookAt.
- 자동 Facing 계산
- 기본 LookAt
- 사용자 LookAt override
- LookAt Arrow 표시
---
## Phase 7
Player POV.
- Player Camera
- 선수 위치 추적
- LookAt 기반 Camera rotation
- Tactical / Player View 전환
---
# 22. MVP에서 제외
현재 단계에서는 다음 기능을 구현하지 않는다.
- 로그인
- 서버 DB
- 팀 관리
- 전술 공유
- 영상/GIF Export
- 실제 사람 3D 모델
- 수비 AI
- 자동 수비 움직임
- Read / Decision 분기
- 패스 물리
- 드리블 애니메이션
- 슛 애니메이션
- 복잡한 Timeline Editor
- 개별 Action Duration 직접 입력
- Multiplayer
- WebSocket
MVP 완성 후 단계적으로 추가한다.
---
# 23. 핵심 UX 원칙
가장 중요한 요구사항이다.
**사용자가 전술 하나를 만들기 위해 입력해야 하는 값을 최소화한다.**
기본적으로 사용자는:
```text
전술 생성
→ 수비 형태 선택
→ 선수 선택
→ 이동 위치 연속 클릭
→ 필요한 경우에만 LookAt 수정
→ 다음 Sequence
→ Play
```
정도만 수행하면 전술이 만들어져야 한다.
다음 항목은 사용자에게 기본적으로 입력시키지 않는다.
- Facing angle
- Duration
- Velocity
- Action weight
- Sequence duration
- Camera rotation
- 정확한 좌표값
이 값들은 앱이 자동 계산한다.
---
# 24. 구현 원칙
1. 먼저 동작 가능한 MVP를 만든다.
2. UI 디자인보다 편집 UX와 Playback 로직을 우선한다.
3. 데이터 모델과 Three.js 렌더링 로직을 분리한다.
4. 모든 전술 위치는 실제 Court 좌표로 저장한다.
5. Player POV 확장을 고려해 처음부터 실제 3D Scene을 사용한다.
6. Action/Sequence 데이터는 JSON Serialize 가능한 형태로 유지한다.
7. 하드코딩된 전술에 종속된 구조를 만들지 않는다.
8. 사용자의 Action 개수가 선수마다 달라도 정상 재생되어야 한다.
9. Action이 먼저 끝난 선수는 Sequence 종료 시점까지 마지막 State를 유지한다.
10. 모든 PlayerTrack이 완료된 후 다음 Sequence로 넘어간다.
---
# 25. 최초 완료 기준
다음 시나리오가 정상 동작하면 1차 MVP 완료로 판단한다.
1. 웹페이지 실행
2. 하프코트 표시
3. 공격 5명 / 수비 5명 표시
4. Man to Man / 2-3 / 3-2 중 하나 선택
5. Sequence 1 자동 생성
6. 공격 1번 선택
7. 코트상의 세 위치를 클릭
8. Action 3개 자동 생성
9. 공격 2번 선택
10. 위치 하나 클릭
11. Sequence 2 추가
12. Sequence 1의 마지막 위치가 Sequence 2 시작 위치로 유지
13. Sequence 2에서 추가 Action 작성
14. Play 실행
15. Sequence 1 → Sequence 2 자동 재생
16. 선수별 Action 개수가 달라도 Sequence 종료 타이밍 정상 처리
17. Tactical View에서 정상 재생
18. Player 1 POV로 전환
19. Player 1 이동을 카메라가 따라감
20. 기본 LookAt 방향에 맞춰 카메라가 회전
이 상태까지 우선 구현한다.
구현 중 기존 요구사항과 충돌하지 않는 범위에서는 합리적인 기술적 판단으로 진행하되, 기능을 임의로 추가해 MVP 범위를 확대하지 않는다.