diff --git a/docs/superpowers/specs/2026-04-07-pet-lab-design.md b/docs/superpowers/specs/2026-04-07-pet-lab-design.md new file mode 100644 index 0000000..e26f449 --- /dev/null +++ b/docs/superpowers/specs/2026-04-07-pet-lab-design.md @@ -0,0 +1,163 @@ +# Pet Lab - Desktop Pet Application Design + +## Overview + +Windows PC 바탕화면에 항상 떠있는 데스크톱 펫 애플리케이션. 캐릭터(박뚱냥)가 화면 하단에 고정되어 마우스 방향으로 시선을 추적하고, 클릭/우클릭으로 상호작용할 수 있다. + +**프로젝트 위치**: `C:\Users\jaeoh\Desktop\workspace\pet-lab` (독립 프로젝트, web-backend 모노레포 외부) + +**기술 스택**: Python 3.12 + PyQt5 + +**배포**: 로컬 Windows PC 실행 전용 (NAS 배포 불필요). 추후 PyInstaller로 .exe 패킹. + +--- + +## Architecture + +### Project Structure + +``` +pet-lab/ +├── app/ +│ ├── main.py # 엔트리포인트 (QApplication 초기화, 시스템 트레이) +│ ├── pet_widget.py # 메인 위젯 (투명 윈도우 + 캐릭터 렌더링) +│ ├── eye_tracker.py # 마우스 위치 기반 시선/기울기 계산 +│ ├── interaction.py # 클릭 반응 애니메이션 + 우클릭 컨텍스트 메뉴 +│ └── config.py # 설정값 (크기, 위치, 속도 상수) +├── assets/ +│ └── characters/ +│ └── 박뚱냥.png # 캐릭터 이미지 (투명 배경 PNG) +├── requirements.txt # PyQt5 +└── README.md +``` + +### Component Responsibilities + +| 파일 | 역할 | +|------|------| +| `main.py` | QApplication 생성, PetWidget 인스턴스화, 이벤트 루프 시작 | +| `pet_widget.py` | 투명 프레임리스 윈도우, 캐릭터 이미지 표시, QTimer 루프로 시선 업데이트 | +| `eye_tracker.py` | 마우스 좌표 → 기울기 각도/좌우 반전 여부 계산 (순수 계산 모듈) | +| `interaction.py` | 좌클릭(점프), 더블클릭(흔들기) 애니메이션, 우클릭 메뉴 생성/처리 | +| `config.py` | 상수 정의: 캐릭터 크기(소/중/대), 틸트 범위, 타이머 간격 등 | + +--- + +## Core Behavior + +### 투명 윈도우 + +PyQt5 윈도우 플래그 조합: +- `Qt.FramelessWindowHint`: 타이틀바 제거 +- `Qt.WindowStaysOnTopHint`: 항상 위 (토글 가능) +- `Qt.Tool`: 태스크바에 표시 안 함 +- `WA_TranslucentBackground`: 배경 투명 + +캐릭터 이미지 영역만 클릭 이벤트 수신. 투명 영역은 `WA_TransparentForMouseEvents`가 아닌, 위젯 크기를 캐릭터 이미지 크기에 맞춰서 처리. + +### 바닥 고정 위치 + +- Y = 화면 높이 - 태스크바 높이(기본 48px) - 캐릭터 높이 +- X = 수평 위치 프리셋: 좌(화면 10%), 중앙(50%), 우(90%) +- 기본 위치: 화면 우측(90%) +- 태스크바 높이는 Windows API 없이 기본값 48px 사용 (충분히 실용적) + +### 시선 추적 + +QTimer(30ms 간격, 약 33fps)로 글로벌 마우스 좌표 폴링: + +1. `QCursor.pos()`로 마우스 절대 좌표 획득 +2. 캐릭터 중심점과 마우스 사이의 각도 계산 (`math.atan2`) +3. 각도를 기울기로 변환: + - 마우스가 캐릭터 왼쪽 → 이미지 좌측 기울기 (음수 각도) + - 마우스가 캐릭터 오른쪽 → 이미지 우측 기울기 (양수 각도) + - 기울기 범위: -15도 ~ +15도 +4. 마우스가 캐릭터 왼쪽이면 이미지 좌우 반전 (`QTransform.scale(-1, 1)`) +5. `QTransform.rotate(angle)`로 기울기 적용 +6. 마우스 좌표 변화 없으면 렌더링 스킵 (성능 최적화) + +### 클릭 반응 + +**좌클릭 — 점프**: +- `QPropertyAnimation`으로 위젯 Y좌표를 위로 30px 이동 후 복귀 +- duration: 300ms, easing: `QEasingCurve.OutBounce` + +**더블클릭 — 흔들기**: +- `QPropertyAnimation`으로 X좌표를 좌우 진동 +- duration: 400ms, 좌(-10) → 우(+10) → 원위치 + +### 우클릭 컨텍스트 메뉴 + +| 메뉴 항목 | 동작 | +|-----------|------| +| 위치: 좌/중앙/우 | 캐릭터 수평 위치 변경 | +| 크기: 소/중/대 | 캐릭터 크기 변경 (100/150/200px) | +| 항상 위 | `WindowStaysOnTopHint` 토글 | +| 종료 | 애플리케이션 종료 | + +`QMenu`로 구현. 서브메뉴 사용하여 위치/크기를 그룹화. + +--- + +## Configuration Constants (`config.py`) + +```python +# 캐릭터 크기 (높이 기준, 너비는 비율 유지) +SIZES = {"small": 100, "medium": 150, "large": 200} +DEFAULT_SIZE = "medium" + +# 수평 위치 프리셋 (화면 너비 비율) +POSITIONS = {"left": 0.1, "center": 0.5, "right": 0.9} +DEFAULT_POSITION = "right" + +# 시선 추적 +TIMER_INTERVAL_MS = 30 # 약 33fps +MAX_TILT_ANGLE = 15.0 # 최대 기울기 (도) + +# 태스크바 +TASKBAR_HEIGHT = 48 # Windows 기본 태스크바 높이 + +# 애니메이션 +JUMP_HEIGHT = 30 # 점프 높이 (px) +JUMP_DURATION_MS = 300 +SHAKE_OFFSET = 10 # 흔들기 좌우 폭 (px) +SHAKE_DURATION_MS = 400 + +# 에셋 경로 +CHARACTER_DIR = "assets/characters" +DEFAULT_CHARACTER = "박뚱냥.png" +``` + +--- + +## Dependencies + +``` +PyQt5>=5.15,<6.0 +``` + +개발 시 추가: +``` +pyinstaller>=6.0 # .exe 패킹용 (나중에) +``` + +--- + +## Constraints + +- **Windows 전용**: PyQt5 투명 윈도우는 Windows에서 가장 안정적. macOS/Linux는 고려하지 않음. +- **이미지 1장으로 시작**: 현재 박뚱냥.png 정면 포즈 1장. 시선은 이미지 기울기 + 좌우 반전으로 표현. +- **NAS 배포 불필요**: Docker, docker-compose.yml, deploy.sh 수정 없음. +- **독립 프로젝트**: `C:\Users\jaeoh\Desktop\workspace\pet-lab`에 별도 Git 저장소. + +--- + +## Future Extensions + +- 스프라이트 시트 추가: idle, walk, sit, sleep 등 포즈별 이미지 → 상태 머신 기반 애니메이션 +- 자율 행동: 일정 시간 마우스 비활동 시 졸기/잠자기 상태 전환 +- 시스템 트레이 아이콘: 종료/설정 접근 +- 설정 파일 저장/로드: JSON으로 크기/위치/캐릭터 선택 영속화 +- 다중 캐릭터: `assets/characters/` 디렉토리에 여러 캐릭터 추가, 우클릭 메뉴에서 선택 +- PyInstaller .exe 패킹: 단독 배포용 실행파일 생성 +- 웹 서비스 연동: pet-lab API 서버 → 캐릭터 다운로드/공유