feat: StationOverlay 렌더링 최적화 및 스무딩 적용 close #1

- 텍스트(측점/POI) 전 프레임 사전 계산 Map (requestIdleCallback 백그라운드)
- 드론 데이터 이동 평균 스무딩 (smoothFrame ±N프레임)
- 30fps→60fps 프레임 간 선형 보간 (performance.now() 기반)
- EMA(지수이동평균) 표시 위치 스무딩 (α=0.01 기본값)
- 글씨 2배 크기, bold, strokeText 테두리, 배경 박스 제거
- 카메라 파라미터 패널에 smooth/EMA α 슬라이더 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-01 15:11:39 +09:00
commit 2aae3d1c0d
89 changed files with 15739 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
---
name: code-reviewer
description: 변경된 코드의 품질, 보안, CLAUDE.md 규칙 준수를 검증하는 리뷰 에이전트. 코드 리뷰 요청 시 사용.
tools: Read, Grep, Glob, Bash
model: sonnet
---
You are a senior code reviewer for the abcvideo project.
## 작업 시작
1. **CLAUDE.md** 읽기 → 핵심 구현 규칙 파악
2. `git diff` 또는 `git diff HEAD~1`로 변경사항 확인
## 리뷰 체크리스트
### 보안
- [ ] Path traversal 방어: `path.resolve()` + 허용 디렉토리 검증
- [ ] 업로드 파일 검증: MIME + FFprobe 코덱 확인
- [ ] CORS 설정 적절성
- [ ] `crossorigin="anonymous"` 설정 여부 (Canvas 사용 시)
### 메모리 관리
- [ ] `URL.createObjectURL()``revokeObjectURL()` 호출
- [ ] Canvas 재사용 (매번 새로 생성하지 않음)
- [ ] hls.js `backBufferLength: 30` 설정 여부
- [ ] QuotaExceededError 핸들링
### 성능
- [ ] `timeupdate` 이벤트에서 직접 DOM 조작 없음
- [ ] `requestAnimationFrame` 또는 `requestVideoFrameCallback` 사용
- [ ] 주석 배열 이진 탐색 O(log n)
- [ ] 오버레이에 `will-change: transform` 적용
### 코드 품질
- [ ] TypeScript 타입 정확성
- [ ] 에러 핸들링 적절성
- [ ] 불필요한 코드/주석 없음
- [ ] CLAUDE.md 패턴 준수 (Range Request, FFmpeg spawn 등)
## 출력 형식
피드백을 우선순위별로 정리:
1. **Critical** — 반드시 수정 (보안 취약점, 메모리 누수, 빌드 실패)
2. **Warning** — 수정 권장 (성능 이슈, 규칙 미준수)
3. **Suggestion** — 개선 제안 (코드 스타일, 가독성)
각 항목에 파일명:라인번호와 구체적 수정 방법을 포함.

View File

@@ -0,0 +1,41 @@
---
name: ffmpeg-helper
description: FFmpeg/FFprobe 명령 생성, 실행, 디버깅을 담당하는 전문 에이전트. FFmpeg 관련 질문이나 영상 처리 작업 시 사용.
tools: Bash, Read, Grep, Glob
model: sonnet
---
You are an FFmpeg expert for the abcvideo project.
## 역할
- FFmpeg/FFprobe 명령 생성 및 실행
- HLS 변환, 프레임 추출, 코덱 분석
- 영상 메타데이터 확인
- FFmpeg 에러 디버깅
## CLAUDE.md 규칙 준수
### HLS 변환
- H.264 소스: `-c copy` (재인코딩 없이 리먹스, 수 초 내 완료)
- 비-H.264 소스: `-c:v libx264 -preset medium -crf 23 -profile:v high -level 4.1`
- 세그먼트: 6초 (`-hls_time 6`)
- 키프레임: 2초 간격 (`-force_key_frames "expr:gte(t,n_forced*2)"`)
- 반드시 `-hls_list_size 0 -hls_playlist_type vod` 포함
### 프레임 추출
- 정확 추출: `-accurate_seek -ss {time} -i {file} -frames:v 1`
- `-ss``-i` **앞에** 배치 (입력 전 시크)
- 품질: PNG (분석용) 또는 JPEG `-q:v 2` (썸네일용)
### 코덱 감지
```bash
ffprobe -v quiet -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 input.mp4
```
## 작업 방식
1. 사용자 요청을 FFmpeg 명령으로 변환
2. 명령 설명 (각 플래그의 의미)
3. 실행 전 확인 요청
4. 실행 후 결과 분석

View File

@@ -0,0 +1,37 @@
---
name: step-worker
description: PLAN.md의 특정 단계를 읽고 태스크를 순서대로 수행하는 작업 에이전트. 단계별 구현 작업을 요청받을 때 사용.
model: opus
effort: high
---
You are the primary implementation agent for the abcvideo project.
## 작업 시작 프로토콜 (반드시 순서대로)
1. **CLAUDE.md** 읽기 → 아키텍처, 기술 스택, 구현 규칙 파악
2. **PLAN.md** 읽기 → 담당 단계의 세부 태스크 확인
3. **PROGRESS.md** 읽기 → 이전 단계 완료 여부, 알려진 이슈, 인계사항 확인
## 작업 규칙
- 작업 시작 전 PROGRESS.md에 해당 단계를 "🔄 진행 중"으로 업데이트
- PLAN.md의 태스크를 위에서 아래로 순서대로 수행
- 각 태스크 완료 시 PLAN.md에서 `- [ ]``- [x]`로 변경
- 의미 있는 마일스톤마다 PROGRESS.md 업데이트 (완료 항목, 이슈)
- 이전 에이전트가 작성한 코드를 이유 없이 대폭 변경하지 않음
- CLAUDE.md의 핵심 구현 규칙을 반드시 준수
## 작업 완료 시
PROGRESS.md에 다음을 기록:
- 상태를 "✅ 완료"로 변경
- 완료 항목 목록
- 미완료/이슈 사항
- **다음 단계 참고**: 후속 에이전트가 반드시 알아야 할 사항
## 주의사항
- 산출물(완료 기준)을 충족하지 못하면 "✅ 완료"로 표시하지 않음
- 블로커 발견 시 PROGRESS.md에 기록하고 사용자에게 보고
- 한 단계에서 다른 단계의 태스크를 수행하지 않음

View File

@@ -0,0 +1,71 @@
---
name: test-runner
description: 빌드 확인, API 테스트, 단계별 산출물 검증을 수행하는 에이전트. 구현 완료 후 검증 요청 시 사용.
tools: Bash, Read, Grep, Glob
model: sonnet
---
You are the verification agent for the abcvideo project.
## 역할
구현된 코드가 PLAN.md의 산출물(완료 기준)을 충족하는지 검증.
## 검증 프로토콜
1. **PLAN.md** 읽기 → 해당 단계의 산출물(완료 기준) 확인
2. **PROGRESS.md** 읽기 → 현재 상태, 알려진 이슈 확인
3. 산출물 항목을 하나씩 검증
4. 결과를 PROGRESS.md에 기록
## 검증 항목별 방법
### 빌드 검증
```bash
# TypeScript 컴파일
cd client && npx tsc --noEmit
cd server && npx tsc --noEmit
# 빌드
npm run build
```
### 서버 검증
```bash
# 서버 기동
npm run dev:server &
sleep 3
# API 헬스 체크
curl -s http://localhost:3001/api/videos
# Range Request 테스트
curl -I -H "Range: bytes=0-1023" http://localhost:3001/api/stream/{videoId}
# HLS 변환 테스트
curl -X POST http://localhost:3001/api/hls/{videoId}/convert
# 주석 API 테스트
curl -X POST http://localhost:3001/api/annotations/{videoId} \
-H "Content-Type: application/json" \
-d '{"type":"memo","timeStart":10,"text":"test"}'
```
### 클라이언트 검증
```bash
# Vite 개발 서버 기동
npm run dev:client &
sleep 3
# 빌드 확인
cd client && npm run build
```
## 출력 형식
각 산출물 항목에 대해:
- ✅ 통과: 항목명 + 확인 방법
- ❌ 실패: 항목명 + 에러 내용 + 원인 분석
- ⚠️ 부분: 항목명 + 동작하지만 이슈 있음
최종 결과를 PROGRESS.md에 기록.

View File

@@ -0,0 +1,36 @@
#!/bin/bash
# auto-lint.sh
# PostToolUse (Edit|Write) 훅: TypeScript 파일 수정 후 컴파일 체크
#
# 수정된 파일이 .ts/.tsx인 경우 tsc --noEmit으로 타입 체크
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 파일 경로가 없으면 통과
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# TypeScript 파일이 아니면 통과
if ! echo "$FILE_PATH" | grep -qE '\.(ts|tsx)$'; then
exit 0
fi
# client/ 파일인 경우
if echo "$FILE_PATH" | grep -q 'client/'; then
cd "$CLAUDE_PROJECT_DIR/client" 2>/dev/null
if [ -f "tsconfig.json" ]; then
npx tsc --noEmit --pretty false 2>&1 | tail -5
fi
fi
# server/ 파일인 경우
if echo "$FILE_PATH" | grep -q 'server/'; then
cd "$CLAUDE_PROJECT_DIR/server" 2>/dev/null
if [ -f "tsconfig.json" ]; then
npx tsc --noEmit --pretty false 2>&1 | tail -5
fi
fi
exit 0

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
"""
PostToolUse(Write) 훅: 히스토리 파일 필수 필드 검증
path.json 의 history_path 하위 *.md 파일에
소요 시간 / Context 사용량 누락 시 exit 2로 Write 차단
"""
import sys
import json
import re
import os
# ── path.json 로드 ────────────────────────────────────────────────────────────
HOOKS_DIR = os.path.dirname(os.path.abspath(__file__))
PATH_JSON = os.path.join(HOOKS_DIR, "path.json")
try:
with open(PATH_JSON, encoding="utf-8") as f:
paths = json.load(f)
except Exception:
paths = {}
history_path = paths.get("history_path", "docs/history").replace("\\", "/").rstrip("/")
# history_path 하위 어느 깊이든 *.md 이면 검사
history_pattern = re.escape(history_path) + r"/.+\.md$"
# ── 훅 입력 파싱 ──────────────────────────────────────────────────────────────
try:
data = json.load(sys.stdin)
except Exception:
sys.exit(0)
tool_input = data.get("tool_input", {})
file_path = tool_input.get("file_path", "")
content = tool_input.get("content", "")
normalized = file_path.replace("\\", "/")
if not re.search(history_pattern, normalized):
sys.exit(0)
missing = []
if not re.search(
r"\*\*소요\s*시간\*\*|^##\s*소요\s*시간|소요\s*시간\s*:",
content,
re.MULTILINE,
):
missing.append("소요 시간")
if not re.search(
r"\*\*Context\s*사용량\*\*|^##\s*Context\s*사용량|Context\s*사용량\s*:",
content,
re.MULTILINE | re.IGNORECASE,
):
missing.append("Context 사용량")
if missing:
sys.stderr.write("[BLOCKED] 히스토리 파일 필수 항목 누락: " + ", ".join(missing) + "\n")
sys.stderr.write("\n")
sys.stderr.write("파일 상단에 다음 항목을 반드시 포함하세요:\n")
sys.stderr.write("\n")
sys.stderr.write(" **소요 시간**: X분\n")
sys.stderr.write(" **Context 사용량**: input Xk / output Xk tokens\n")
sys.stderr.write("\n")
sys.stderr.write("파일: " + file_path + "\n")
sys.exit(2)
# ── 이슈 번호 검사 (없으면 사용자에게 질문 요청) ──────────────────────────────
if not re.search(r"\*\*이슈\*\*\s*[:\s]+#\d+", content, re.MULTILINE):
sys.stderr.write("[이슈 번호 필요] 히스토리 파일에 이슈 번호가 없습니다.\n")
sys.stderr.write("\n")
sys.stderr.write("사용자에게 다음을 질문하세요:\n")
sys.stderr.write(" '이 작업과 관련된 Gitea 이슈 번호가 있나요? (예: #1 / 없으면 #0)'\n")
sys.stderr.write("\n")
sys.stderr.write("답변 후 파일 상단에 추가하고 다시 저장하세요:\n")
sys.stderr.write(" **이슈**: #N\n")
sys.stderr.write("\n")
sys.stderr.write("파일: " + file_path + "\n")
sys.exit(2)
sys.exit(0)

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# PostToolUse(Write) 훅: 히스토리 파일 필수 필드 검증
# 대상: docs/*/history/*.md
# 필수 항목(소요 시간, Context 사용량) 누락 시 exit 2로 Write 차단
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cat | python3 "$SCRIPT_DIR/guard-history-fields.py"

View File

@@ -0,0 +1,38 @@
#!/bin/bash
# Stop 훅: 작업 완료 후 히스토리 기록 리마인더
# path.json 의 history_path 에서 저장 경로를 읽어 출력
set -euo pipefail
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PATH_JSON="$HOOKS_DIR/path.json"
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(cd "$HOOKS_DIR/../.." && pwd)}"
if command -v jq &>/dev/null && [[ -f "$PATH_JSON" ]]; then
history_path=$(jq -r '.history_path // "docs/history"' "$PATH_JSON")
else
history_path="docs/history"
fi
TODAY=$(date +%Y-%m-%d)
HISTORY_ABS="$PROJECT_DIR/$history_path"
# 오늘 날짜로 시작하는 히스토리 파일이 있으면 통과
if ls "$HISTORY_ABS/${TODAY}"_*.md 2>/dev/null | grep -q .; then
exit 0
fi
cat >&2 <<EOF
[HISTORY REQUIRED] 오늘(${TODAY}) 작업 히스토리가 없습니다.
아래 형식으로 파일을 작성하고 저장하세요:
${history_path}/${TODAY}_{작업명}.md
필수 항목:
**소요 시간**: X분
**Context 사용량**: input Xk / output Xk tokens
**이슈**: #N
히스토리 파일 저장 완료 후 응답이 종료됩니다.
EOF
exit 2

4
.claude/hooks/path.json Normal file
View File

@@ -0,0 +1,4 @@
{
"_comment": "각 프로젝트에서 이 파일을 복사해 history_path 만 재정의하세요.",
"history_path": "docs/history"
}

View File

@@ -0,0 +1,23 @@
#!/bin/bash
# progress-reminder.sh
# PostToolUse (Bash) 훅: 빌드/테스트 명령 실행 후 PROGRESS.md 업데이트 리마인더
#
# npm test, npm run build 등 마일스톤 명령 감지 시 알림
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# 마일스톤 명령 감지
if echo "$COMMAND" | grep -qE '(npm (run )?(build|test|dev)|npx tsc)'; then
# additionalContext로 리마인더 전달
cat <<'EOF'
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "[리마인더] 빌드/테스트 명령이 실행되었습니다. PROGRESS.md 업데이트가 필요한지 확인하세요."
}
}
EOF
fi
exit 0

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# protect-files.sh
# PreToolUse (Edit|Write) 훅: 보호 파일 수정 차단
#
# 차단 대상:
# - CLAUDE.md (명시적 요청 없이 수정 금지)
# - .env 파일 (보안)
# - storage/ 외부에 영상/바이너리 파일 쓰기
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 파일 경로가 없으면 통과
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# .env 파일 직접 수정 차단
if echo "$FILE_PATH" | grep -qE '\.env$'; then
echo "Blocked: .env 파일 직접 수정은 보안상 차단됩니다. .env.example을 수정하세요." >&2
exit 2
fi
# storage/ 외부에 영상 파일 쓰기 차단
# 주의: .ts는 TypeScript와 HLS 세그먼트 모두에 사용됨
# src/ 하위의 .ts 파일은 TypeScript이므로 허용
if echo "$FILE_PATH" | grep -qiE '\.(mp4|mkv|webm|mov|avi|m3u8)$'; then
if ! echo "$FILE_PATH" | grep -q 'storage/'; then
echo "Blocked: 영상/HLS 파일은 storage/ 디렉토리 안에만 생성 가능합니다." >&2
exit 2
fi
fi
# HLS .ts 세그먼트 파일만 차단 (src/ 하위 TypeScript 제외)
if echo "$FILE_PATH" | grep -qE '\.ts$'; then
if ! echo "$FILE_PATH" | grep -qE '(src/|\.config\.ts|tsconfig)'; then
if echo "$FILE_PATH" | grep -q 'storage/'; then
: # storage 내 .ts 세그먼트는 허용
elif echo "$FILE_PATH" | grep -qiE 'segment|hls'; then
echo "Blocked: HLS 세그먼트 파일은 storage/ 디렉토리 안에만 생성 가능합니다." >&2
exit 2
fi
fi
fi
exit 0

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# UserPromptSubmit 훅: 프로젝트 컨텍스트 주입
# path.json 의 history_path 아래 최근 작업 문서를 읽어 출력
set -euo pipefail
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PATH_JSON="$HOOKS_DIR/path.json"
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(cd "$HOOKS_DIR/../.." && pwd)}"
if command -v jq &>/dev/null && [[ -f "$PATH_JSON" ]]; then
history_rel=$(jq -r '.history_path // "docs/history"' "$PATH_JSON")
else
history_rel="docs/history"
fi
history_path="$PROJECT_DIR/$history_rel"
echo "### Project operating context"
echo ""
echo "Recent history files (${history_rel}):"
if [[ -d "$history_path" ]]; then
find "$history_path" -maxdepth 1 -type f -name "*.md" | sort -r | head -5 | sed "s|$PROJECT_DIR/||" | sed 's#^#- #'
else
echo "- (none)"
fi
echo ""
echo "### 히스토리 기록 규칙"
echo "작업이 완료되면 반드시 ${history_rel}/YYYY-MM-DD_{작업명}.md 파일을 작성하라."
echo "필수 항목: **소요 시간**, **Context 사용량** (누락 시 저장 차단됨)"

View File

@@ -0,0 +1,25 @@
#!/bin/bash
# session-start.sh
# SessionStart 훅: 세션 시작 시 프로젝트 상태를 컨텍스트에 주입
#
# PROGRESS.md의 현재 상태 요약을 읽어서 에이전트에게 전달
PROGRESS_FILE="$CLAUDE_PROJECT_DIR/PROGRESS.md"
if [ -f "$PROGRESS_FILE" ]; then
# PROGRESS.md에서 "현재 상태 요약" 섹션 추출 (첫 20줄)
STATUS=$(head -20 "$PROGRESS_FILE")
cat <<EOF
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "=== 프로젝트 진행 상태 ===\n${STATUS}\n=== 상세 내용은 PROGRESS.md 참조 ==="
}
}
EOF
else
echo '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"PROGRESS.md가 아직 없습니다. /status로 확인하세요."}}'
fi
exit 0

91
.claude/settings.json Normal file
View File

@@ -0,0 +1,91 @@
{
"permissions": {
"allow": [
"Edit(/.claude/skills/step/**)",
"Edit(/.claude/skills/status/**)",
"Edit(/.claude/skills/verify/**)",
"Edit(/.claude/skills/ffmpeg-cmd/**)",
"Edit(/.claude/skills/review/**)",
"Edit(/.claude/agents/**)",
"Edit(/.claude/hooks/**)",
"mcp__gitea__issue_write"
]
},
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh",
"timeout": 10
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh",
"timeout": 5
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-lint.sh",
"timeout": 30
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-history-fields.sh",
"timeout": 10
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/progress-reminder.sh",
"timeout": 5
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-history-reminder.sh",
"timeout": 5
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-context.sh",
"timeout": 5
}
]
}
]
}
}

View File

@@ -0,0 +1,36 @@
---
name: ffmpeg-cmd
description: 자연어 설명을 FFmpeg/FFprobe 명령으로 변환하고 실행합니다.
argument-hint: "<설명>"
disable-model-invocation: true
---
## FFmpeg 명령 생성 및 실행
요청: **$ARGUMENTS**
### 실행 규칙
1. **CLAUDE.md**의 FFmpeg 관련 규칙을 먼저 확인하세요:
- HLS 변환: 세그먼트 6초, 키프레임 2초, H.264 소스는 `-c copy`
- 프레임 추출: `-accurate_seek -ss {time} -i {file} -frames:v 1`
- 코덱 감지: `ffprobe -v quiet -select_streams v:0 -show_entries stream=codec_name`
2. 요청 내용을 FFmpeg/FFprobe 명령으로 변환
3. 실행 전 다음을 표시:
- 생성된 명령
- 각 플래그의 의미 (한줄 설명)
- 예상 결과
4. 명령 실행 후 결과 분석:
- 성공: 출력 파일 위치, 크기, 소요 시간
- 실패: stderr 분석, 원인 설명, 수정된 명령 제안
### 자주 사용하는 패턴
- `영상 정보 확인``ffprobe -v quiet -print_format json -show_format -show_streams`
- `HLS 변환` → CLAUDE.md의 HLS 변환 명령 패턴 사용
- `프레임 추출``-accurate_seek -ss {time} -i {file} -frames:v 1`
- `코덱 확인``ffprobe -v quiet -select_streams v:0 -show_entries stream=codec_name -of csv=p=0`
- `썸네일 스프라이트` → 10초 간격 프레임 추출 후 타일링

View File

@@ -0,0 +1,40 @@
---
name: review
description: 최근 코드 변경사항을 CLAUDE.md 규칙 기준으로 리뷰합니다.
disable-model-invocation: true
context: fork
agent: code-reviewer
---
## 코드 리뷰
최근 변경사항을 CLAUDE.md의 핵심 구현 규칙 기준으로 리뷰하세요.
### 리뷰 범위
변경된 파일 확인:
!`git diff --name-only HEAD~1 2>/dev/null || echo "git diff 불가 - 전체 파일 리뷰"`
### 리뷰 기준 (CLAUDE.md에서 발췌)
**보안:**
- Path traversal 방어 (path.resolve + 허용 디렉토리 검증)
- 업로드 MIME + FFprobe 검증
- CORS 설정
**메모리:**
- URL.createObjectURL → revokeObjectURL 쌍
- Canvas 재사용
- hls.js backBufferLength: 30
**성능:**
- timeupdate 직접 DOM 조작 금지
- requestAnimationFrame/requestVideoFrameCallback 사용
- 이진 탐색 O(log n)
**패턴 준수:**
- Range Request: createReadStream + pipeline
- FFmpeg: child_process.spawn 래퍼
- Video.js: ref + useEffect 패턴
피드백을 Critical / Warning / Suggestion 으로 분류하세요.

View File

@@ -0,0 +1,25 @@
---
name: status
description: 프로젝트 진행 상태를 확인하고 다음 작업을 제안합니다.
disable-model-invocation: true
---
## 프로젝트 진행 상태 확인
아래 파일들을 읽고 현재 상태를 요약하세요:
1. **PROGRESS.md** 읽기 — 현재 상태 요약, 단계별 진행 기록
2. **PLAN.md** 읽기 — 미완료 태스크 (`- [ ]`) 개수 파악
3. 다음 내용을 표 형태로 보고:
| 단계 | 상태 | 완료 태스크 | 남은 태스크 |
|------|------|------------|------------|
4. **다음에 할 작업** 제안:
- 의존성이 충족된 다음 단계 식별
- 블로커가 있으면 강조
- 병렬 진행 가능한 단계가 있으면 알림
5. 블로커/이슈가 있으면 빨간색으로 강조

View File

@@ -0,0 +1,34 @@
---
name: step
description: PLAN.md의 특정 단계를 실행합니다. 단계 번호를 인자로 전달합니다.
argument-hint: "<단계번호>"
disable-model-invocation: true
---
## 단계 $ARGUMENTS 실행
step-worker 에이전트를 사용하여 PLAN.md의 **단계 $ARGUMENTS**를 수행합니다.
### 실행 프로토콜
1. 먼저 아래 3개 파일을 순서대로 읽으세요:
- `CLAUDE.md` — 프로젝트 규칙/아키텍처
- `PLAN.md` — 단계 $ARGUMENTS의 세부 태스크 확인
- `PROGRESS.md` — 이전 단계 완료 여부, 블로커, 인계사항
2. PROGRESS.md에서 단계 $ARGUMENTS의 상태를 "🔄 진행 중"으로 업데이트
3. PLAN.md의 단계 $ARGUMENTS 태스크를 위에서 아래로 순서대로 수행:
- 각 태스크 완료 시 PLAN.md에서 `- [ ]``- [x]`로 변경
- 의미 있는 마일스톤마다 PROGRESS.md 업데이트
4. 모든 태스크 완료 후:
- PLAN.md의 **산출물(완료 기준)**을 직접 검증
- PROGRESS.md에 최종 결과 기록 (완료 항목, 미완료/이슈, 다음 단계 참고)
- 산출물 충족 시 상태를 "✅ 완료"로 변경
### 주의사항
- 이전 단계가 완료되지 않았으면 사용자에게 알리고 중단
- 블로커 발견 시 PROGRESS.md에 기록 후 사용자에게 보고
- 이전 에이전트가 작성한 코드를 이유 없이 변경하지 않음

View File

@@ -0,0 +1,34 @@
---
name: verify
description: 특정 단계의 산출물(완료 기준)을 검증합니다. 단계 번호를 인자로 전달합니다.
argument-hint: "<단계번호>"
disable-model-invocation: true
---
## 단계 $ARGUMENTS 검증
PLAN.md의 **단계 $ARGUMENTS**에 정의된 산출물(완료 기준)을 하나씩 검증합니다.
### 검증 프로토콜
1. **PLAN.md** 읽기 → 단계 $ARGUMENTS의 "산출물 (완료 기준)" 섹션 확인
2. **PROGRESS.md** 읽기 → 현재 상태, 알려진 이슈 확인
3. 각 산출물 항목을 실제로 실행하여 검증:
- 빌드 확인: `npx tsc --noEmit`, `npm run build`
- 서버 기동: 서버 시작 후 API 엔드포인트 curl 테스트
- 클라이언트: 개발 서버 기동 확인, 빌드 성공 확인
- 기능 테스트: 해당 단계의 핵심 기능 동작 확인
4. 각 항목에 대해 결과 보고:
- ✅ 통과: 확인 방법 + 결과
- ❌ 실패: 에러 내용 + 원인 분석 + 수정 제안
- ⚠️ 부분 통과: 동작하지만 이슈 있음
5. 종합 결과를 PROGRESS.md에 기록
### 주의사항
- 실행 중인 프로세스는 검증 후 반드시 종료
- 서버 포트 충돌 시 기존 프로세스 확인 후 처리
- 검증만 수행하고 코드 수정은 하지 않음 (수정이 필요하면 보고)