976 lines
16 KiB
Markdown
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 범위를 확대하지 않는다.
|