feat: batch wiki-fication of 00_Raw data
Applied double-save rule: Master Archive + Specialized Mapping for Skybound, Datacollector, and Frontend Mastery.
This commit is contained in:
+60
@@ -0,0 +1,60 @@
|
||||
# Datacollector - 인증 복구 후 자동 재개 상태 전환 수정
|
||||
|
||||
- 작성 시각: 2026-04-25 22:39:30 KST
|
||||
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
- 관련 파일: `src/components/AgentDashboard.tsx`, `src/lib/engine.ts`
|
||||
|
||||
## 상황
|
||||
|
||||
NotebookLM 인증 복구 로직을 강화했지만, 화면에서는 여전히 `CONTINUE MISSION` 버튼을 사용자가 눌러야 다음 큐가 이어지는 것처럼 보였다.
|
||||
|
||||
사용자 관찰:
|
||||
|
||||
- 작업은 일부 완료됨.
|
||||
- 큐에는 아직 작업이 많이 남아 있음.
|
||||
- 헤더 상태가 `IDLE`로 보임.
|
||||
- `CONTINUE MISSION` 버튼이 사용자의 수동 클릭을 기다림.
|
||||
|
||||
## 원인
|
||||
|
||||
프론트엔드 상태 전환에 빈틈이 있었다.
|
||||
|
||||
`AgentDashboard`의 `useEffect`는 `status !== 'running'`일 때 `KnowledgeEngine.stop()`을 호출한다. 그런데 기존 `stop()`은 내부 실행 플래그만 끄는 것이 아니라 항상 Zustand 상태까지 `idle`로 바꿨다.
|
||||
|
||||
그 결과 인증 오류 등으로 `paused` 상태를 유지해야 하는 경우에도 React effect를 지나면서 `paused -> idle`로 바뀌었다. 이렇게 되면 앱은 "복구 후 자동 재개 가능한 일시정지"가 아니라 "사용자가 다시 Continue를 눌러야 하는 대기 상태"처럼 동작했다.
|
||||
|
||||
## 조치
|
||||
|
||||
`src/lib/engine.ts`:
|
||||
|
||||
- `stop(updateStatus = true)` 형태로 변경했다.
|
||||
- 내부 엔진만 멈춰야 할 때는 UI 상태를 덮어쓰지 않도록 했다.
|
||||
|
||||
`src/components/AgentDashboard.tsx`:
|
||||
|
||||
- `status !== 'running'` effect에서는 `engine.stop(false)`를 호출하도록 변경했다.
|
||||
- `status === 'paused'`이고 큐가 남아 있으면 NotebookLM 연결 확인 후 자동으로 `running`으로 되돌리는 auto-resume effect를 추가했다.
|
||||
- 기존 버그로 이미 `idle`에 갇힌 화면도 구제하기 위해, 수동 정지나 작업 완료 로그가 없는 `idle + 남은 큐` 상태도 복구 가능한 멈춤으로 보고 자동 재개하도록 보강했다.
|
||||
- 중복 자동 재개를 막기 위해 `autoResumeRef` 잠금을 추가했다.
|
||||
|
||||
## 검증
|
||||
|
||||
다음 검증을 완료했다.
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
curl -sS -I http://127.0.0.1:3000
|
||||
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
결과:
|
||||
|
||||
- TypeScript 검사 통과
|
||||
- 프론트엔드 서버 응답 정상
|
||||
- NotebookLM 브리지 연결 확인 `success: true`
|
||||
|
||||
## 운영 메모
|
||||
|
||||
앞으로 인증 복구나 연결 복구로 인해 `paused` 상태가 되면 앱이 NotebookLM 연결을 확인하고 자동으로 다음 큐를 이어서 실행한다.
|
||||
|
||||
사용자가 직접 `STOP / PAUSE`를 누른 경우는 기존처럼 `idle`로 유지되므로, 수동 정지는 자동 재개 대상이 아니다.
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# Datacollector Bridge Connection Refused Run Script Fix
|
||||
|
||||
Date: 2026-04-25 21:07:52 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
사용자가 앱 실행 후 `POST http://127.0.0.1:3002/api/check-connection net::ERR_CONNECTION_REFUSED` 오류를 확인했다.
|
||||
이는 NotebookLM 인증 실패가 아니라 MCP Bridge 서버가 실행되지 않아 브라우저가 `3002` 포트에 연결하지 못한 상태였다.
|
||||
|
||||
## Root Cause
|
||||
|
||||
실행 경로가 여러 개였고 일부 경로는 프런트엔드 Vite 서버만 실행했다.
|
||||
|
||||
- `run_mac.command`: Bridge와 Vite를 함께 실행
|
||||
- `run_app.sh`: Vite만 실행
|
||||
- `npm run dev`: Vite만 실행
|
||||
|
||||
따라서 `run_app.sh` 또는 `npm run dev`로 앱을 켜면 UI는 열리지만 `/api/check-connection` 요청을 받을 Bridge 서버가 없어 `ERR_CONNECTION_REFUSED`가 발생했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/run_app.sh`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/api.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `run_app.sh`가 Bridge 서버와 Vite 서버를 함께 실행하도록 변경
|
||||
- `run_app.sh` 시작 시 기존 `3000`, `3002` 포트 프로세스를 정리
|
||||
- 종료 시 Bridge 백그라운드 프로세스도 함께 종료하도록 trap 추가
|
||||
- README의 실행 안내를 `npm run dev` 단독에서 `./run_mac.command` 또는 `npm run start-full`로 변경
|
||||
- `src/lib/api.ts`에 `bridgeFetch()` 추가
|
||||
- Bridge 연결 실패 시 `Failed to fetch` 대신 “Bridge 서버가 실행되지 않았다”는 안내 메시지를 표시하도록 변경
|
||||
- `VITE_BRIDGE_URL`로 Bridge 주소를 override할 수 있게 함
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 프로덕션 빌드 통과
|
||||
|
||||
## Operational Note
|
||||
|
||||
앞으로 앱은 아래 방식으로 실행해야 한다.
|
||||
|
||||
```bash
|
||||
./run_mac.command
|
||||
```
|
||||
|
||||
또는 수동으로 두 서버를 같이 실행한다.
|
||||
|
||||
```bash
|
||||
npm run start-full
|
||||
```
|
||||
|
||||
`npm run dev`만 실행하면 프런트엔드만 뜨므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
# Datacollector Codebase Structure Review and Initial Risk Assessment
|
||||
|
||||
Date: 2026-04-25 20:38:01 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
Knowledge Vault: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
|
||||
|
||||
## Summary
|
||||
|
||||
이 문서는 Datacollector 프로젝트의 첫 구조 파악 및 초기 코드 리뷰 결과를 정리한 기록이다.
|
||||
이번 검토의 목적은 이후 기능 개발 전에 현재 시스템의 책임 분리, 실행 흐름, 외부 의존성, 그리고 우선적으로 손봐야 할 위험 요소를 이해하는 데 있다.
|
||||
|
||||
현재 프로젝트는 단순한 프런트엔드 앱이 아니라, React 기반 UI와 Zustand 상태 저장소, 자율 실행 엔진, 그리고 NotebookLM MCP 및 로컬 LM을 연결하는 Express 브리지 서버가 결합된 자동화 연구 도구 형태로 구성되어 있다.
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
전체 흐름은 아래와 같다.
|
||||
|
||||
`React UI -> Zustand Store -> KnowledgeEngine -> Express Bridge -> NotebookLM MCP / Local LM / GitHub / Wiki Storage`
|
||||
|
||||
핵심 책임 분리는 다음과 같이 이해했다.
|
||||
|
||||
- `src/components/AgentDashboard.tsx`
|
||||
사용자 인터페이스, 미션 시작/중지/재개, 설정 입력, 로그 표시, 수동 커밋 등 상호작용 담당
|
||||
- `src/store/agentStore.ts`
|
||||
앱 전체 설정값과 실행 상태를 보관하는 단일 전역 상태 저장소
|
||||
- `src/lib/engine.ts`
|
||||
큐를 소비하며 연구, 합성, 링크 추출, 다음 토픽 확장을 반복하는 자율 엔진
|
||||
- `src/lib/gemini.ts`
|
||||
NotebookLM 미연결 시 사용하는 로컬 LM 프롬프트 생성 및 응답 파싱
|
||||
- `src/lib/github.ts`
|
||||
결과 Markdown을 GitHub 저장소의 `00_Raw/` 경로로 업로드
|
||||
- `scripts/mcp_bridge.mjs`
|
||||
NotebookLM MCP 서버와 통신하는 지속 프로세스형 브리지 서버
|
||||
|
||||
## Execution Flow
|
||||
|
||||
실행 흐름은 다음 순서로 이해했다.
|
||||
|
||||
1. 사용자가 `AgentDashboard`에서 주제를 입력하고 미션을 시작한다.
|
||||
2. 주제와 설정이 `agentStore`에 기록되고 상태가 `running`으로 바뀐다.
|
||||
3. `status` 변경을 감지한 UI가 `KnowledgeEngine` 싱글톤을 시작한다.
|
||||
4. `KnowledgeEngine`는 큐의 첫 항목을 읽고 현재 깊이와 루트 주제를 기준으로 처리 여부를 결정한다.
|
||||
5. NotebookLM 연결 상태가 좋으면 브리지 서버를 통해 리서치와 합성을 수행한다.
|
||||
6. NotebookLM이 없으면 로컬 LM 프록시(`/api/lm`)를 통해 대체 연구를 진행한다.
|
||||
7. 생성된 Markdown에서 위키 링크를 추출해 다음 큐를 구성한다.
|
||||
8. 결과는 pending commits, completed 목록, 로컬 위키 Raw 저장소 등에 반영된다.
|
||||
|
||||
## Current Structure Notes
|
||||
|
||||
이번 시점에서 구조적으로 눈에 띈 특징은 다음과 같다.
|
||||
|
||||
- 상태 관리가 거의 전부 Zustand store 하나에 집중되어 있어 흐름 추적은 쉽다.
|
||||
- 대신 엔진과 UI가 store를 매우 직접적으로 공유해서 결합도가 높다.
|
||||
- NotebookLM 경로와 Local LM 경로가 모두 존재해 fallback 전략은 분명하다.
|
||||
- 브리지 서버가 프런트엔드 백엔드이자 외부 도구 래퍼 역할까지 함께 맡고 있어 책임이 넓다.
|
||||
- 문서 저장 흐름이 GitHub 업로드와 로컬 위키 저장으로 이중화되어 있다.
|
||||
|
||||
## Review Findings
|
||||
|
||||
### 1. Sensitive secrets are persisted in browser storage
|
||||
|
||||
`githubToken`과 `notebookLmCookies`가 Zustand persist 설정에 포함되어 있어 브라우저 localStorage에 평문으로 저장된다.
|
||||
이 방식은 세션 쿠키나 GitHub 토큰 같은 민감 정보의 저장 위치로는 안전하지 않다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 같은 브라우저 프로필을 사용하는 다른 코드나 도구가 정보에 접근할 수 있다.
|
||||
- 장기적으로 토큰 유출 위험이 커진다.
|
||||
|
||||
### 2. Bridge server is exposed too broadly
|
||||
|
||||
브리지 서버는 `0.0.0.0:3002`로 열리고 CORS도 전부 허용한다.
|
||||
또한 `/api/lm`은 클라이언트가 전달한 임의의 URL로 요청을 프록시할 수 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
|
||||
영향:
|
||||
|
||||
- 로컬 개발용으로는 편하지만, 같은 네트워크 안에서 예상하지 않은 접근 통로가 될 수 있다.
|
||||
- 사실상 무인증 프록시처럼 동작할 여지가 있다.
|
||||
|
||||
### 3. Environment portability is weak
|
||||
|
||||
MCP 실행 파일 경로와 위키 저장 경로가 절대경로로 하드코딩되어 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
|
||||
영향:
|
||||
|
||||
- 다른 개발자 머신, 다른 사용자 계정, 다른 운영체제에서 그대로 실행하기 어렵다.
|
||||
- 배포보다는 특정 개인 작업 환경에 강하게 종속된다.
|
||||
|
||||
### 4. Manual handoff state is not fully cleared
|
||||
|
||||
`resolveManualNext`가 store에 함수 형태로 저장되는데, `clearState()`에서 정리되지 않는다.
|
||||
수동 합성 대기 중 reset 또는 새 미션 시작이 발생하면 상태 꼬임 가능성이 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 이전 미션의 대기 상태가 다음 미션에 잔존할 수 있다.
|
||||
- UI 버튼 상태와 실제 엔진 대기 상태가 어긋날 수 있다.
|
||||
|
||||
### 5. API endpoint usage is duplicated and hardcoded
|
||||
|
||||
프런트엔드에는 이미 Vite 프록시가 설정되어 있지만, UI와 엔진 코드 곳곳에서 `http://127.0.0.1:3002`를 직접 호출하고 있다.
|
||||
|
||||
관련 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
|
||||
|
||||
영향:
|
||||
|
||||
- 포트 변경이나 배포 환경 변경 시 수정 지점이 늘어난다.
|
||||
- 런타임 경로 설정이 한 군데에서 관리되지 않는다.
|
||||
|
||||
## Validation Performed
|
||||
|
||||
이번 검토 중 아래 확인을 수행했다.
|
||||
|
||||
- 저장소 파일 구조 및 진입점 확인
|
||||
- UI, store, engine, bridge, GitHub, Local LM 계층 코드 확인
|
||||
- `npm run lint` 실행
|
||||
|
||||
검증 결과:
|
||||
|
||||
- TypeScript 타입체크는 현재 통과했다.
|
||||
|
||||
## Suggested Next Priorities
|
||||
|
||||
우선순위는 아래 순서가 적절하다.
|
||||
|
||||
1. 민감 정보 저장 방식을 localStorage 바깥으로 이동하거나 최소한 분리
|
||||
2. 브리지 서버 바인딩 범위와 CORS 정책 축소
|
||||
3. 절대경로를 환경변수 또는 설정 파일로 치환
|
||||
4. `resolveManualNext`를 포함한 미션 종료 정리 로직 강화
|
||||
5. API 베이스 URL을 단일 설정 지점으로 통합
|
||||
|
||||
## Working Agreement For Future Notes
|
||||
|
||||
사용자 요청에 따라, 앞으로 Datacollector 관련 조사/분석/리뷰 결과는 가능하면 이 지식 창고 경로에 계속 기록한다.
|
||||
|
||||
기본 원칙:
|
||||
|
||||
- 위치: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
|
||||
- 파일명: `YYYY-MM-DD-<Project>_<Topic>.md` 또는 기존 저장소 관례와 유사한 읽기 쉬운 영어 제목
|
||||
- 내용: 작업 목적, 파악한 구조, 핵심 발견사항, 다음 액션을 포함
|
||||
|
||||
## Source Files Reviewed
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/package.json`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/main.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/App.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/gemini.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_caller.py`
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Datacollector Local Wiki Save Only Output Mode
|
||||
|
||||
Date: 2026-04-25 20:50:41 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
Datacollector의 생성 결과 저장 방식을 GitHub 업로드 중심에서 로컬 Wiki 저장 전용으로 정리했다.
|
||||
앞으로 앱에서 생성되는 연구 문서는 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 저장되고, Git 업로드는 사용자가 나중에 별도로 한 번에 처리하는 운영 방식으로 둔다.
|
||||
|
||||
## Previous Behavior
|
||||
|
||||
기존 흐름은 결과 생성 후 두 경로가 동시에 존재했다.
|
||||
|
||||
- 로컬 Wiki Raw 폴더에 자동 저장
|
||||
- `pendingCommits`에 결과를 쌓고 UI의 `BATCH COMMIT` 버튼으로 GitHub 업로드 가능
|
||||
|
||||
이 방식은 앱 안에 GitHub 토큰과 저장소 설정을 유지해야 했고, 사용자가 의도하지 않아도 Git 업로드 기능이 계속 노출되는 구조였다.
|
||||
|
||||
## New Behavior
|
||||
|
||||
새 흐름은 다음과 같다.
|
||||
|
||||
1. 연구 결과 Markdown 생성
|
||||
2. `savedReports`에 프리뷰용 로컬 캐시 저장
|
||||
3. 브리지 서버의 `/api/wiki/save`를 통해 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 Markdown 파일 저장
|
||||
4. GitHub 업로드 버튼이나 토큰 설정 없이 완료
|
||||
|
||||
GitHub 업로드는 앱이 수행하지 않는다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
|
||||
|
||||
삭제 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `githubToken`, `githubRepoUrl` 상태 제거
|
||||
- `pendingCommits` 제거
|
||||
- `addPendingCommit`, `clearPendingCommits` 제거
|
||||
- `savedReports`와 `addSavedReport` 추가
|
||||
- `BATCH COMMIT` 버튼 제거
|
||||
- 설정 모달의 GitHub Wiki Sync 섹션 제거
|
||||
- `.env.example`의 GitHub 설정 제거
|
||||
- 생성 결과는 기존 Wiki 저장 API를 통해 로컬 Raw 폴더에만 저장
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 프로덕션 빌드 통과
|
||||
|
||||
## Notes
|
||||
|
||||
로컬 Wiki 저장은 기존 브리지 서버의 `/api/wiki/save` 라우트를 그대로 사용한다.
|
||||
저장 대상 경로는 현재 브리지 서버에 하드코딩된 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`이다.
|
||||
추후 이 경로도 `.env` 설정으로 분리하면 다른 머신이나 폴더 구조에서도 더 쉽게 운영할 수 있다.
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Datacollector Mac Windows Launcher Scripts
|
||||
|
||||
Date: 2026-04-25 21:09:42 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
Datacollector 실행 시 Vite 프런트엔드만 뜨고 MCP Bridge 서버가 뜨지 않아 `ERR_CONNECTION_REFUSED`가 발생할 수 있었다.
|
||||
이를 막기 위해 맥용과 윈도우용 실행 파일을 명확히 정리했다.
|
||||
|
||||
## Main Launchers
|
||||
|
||||
- macOS: `/Volumes/Data/project/Antigravity/Datacollector/run_mac.command`
|
||||
- Windows: `/Volumes/Data/project/Antigravity/Datacollector/run_win.bat`
|
||||
|
||||
두 실행 파일 모두 아래를 수행한다.
|
||||
|
||||
1. 프로젝트 폴더로 이동
|
||||
2. `node_modules`가 없으면 `npm install`
|
||||
3. 기존 `3000`, `3002` 포트 프로세스 정리
|
||||
4. MCP Bridge 서버 실행
|
||||
5. Vite 앱 실행
|
||||
|
||||
## Compatibility Wrappers
|
||||
|
||||
기존 실행 파일과의 호환성을 위해 아래 파일은 메인 실행 파일로 위임하도록 단순화했다.
|
||||
|
||||
- `run_app.sh` -> `run_mac.command`
|
||||
- `run_app.bat` -> `run_win.bat`
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
bash -n run_mac.command
|
||||
bash -n run_app.sh
|
||||
npm run lint
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- macOS shell script 문법 통과
|
||||
- TypeScript 타입체크 통과
|
||||
|
||||
## Operational Note
|
||||
|
||||
앞으로 맥에서는 `run_mac.command`, 윈도우에서는 `run_win.bat`만 실행하면 된다.
|
||||
`npm run dev` 단독 실행은 프런트엔드만 켜므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
# Datacollector - NotebookLM 인증 브라우저 유지 및 오래된 .env 쿠키 우선순위 문제 해결
|
||||
|
||||
- 작성 시각: 2026-04-25 21:31:00 KST
|
||||
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
- 관련 파일: `scripts/mcp_bridge.mjs`, `auth_mac.command`, `auth_win.bat`, `.env.example`
|
||||
|
||||
## 상황
|
||||
|
||||
앱에서 `/api/check-connection` 호출이 500으로 실패했고, 화면에는 다음과 같은 메시지가 반복되었다.
|
||||
|
||||
- `Authentication expired`
|
||||
- `인증 자동 복구 실패. 브라우저 로그인이 필요한 상태일 수 있습니다.`
|
||||
- `MCP initialized: true, pending: 0`
|
||||
|
||||
사용자는 NotebookLM 인증 중 Chrome이 열렸다가 닫히는 점을 보고, 인증 브라우저를 유지해야 하는 것 아니냐고 질문했다.
|
||||
|
||||
## 확인한 내용
|
||||
|
||||
`notebooklm-mcp-auth` 소스 확인 결과, 기본 자동 실행 모드는 인증 후 자신이 띄운 Chrome 프로세스를 종료한다. 반면 `--no-auto-launch --port ... --user-data-dir ...` 모드는 이미 떠 있는 Chrome 디버깅 세션에 붙기 때문에 인증 브라우저를 유지할 수 있다.
|
||||
|
||||
브리지에서 Chrome을 유지하도록 바꾼 뒤 인증 CLI는 성공했다. 하지만 MCP 서버의 `notebook_list`는 여전히 `Authentication expired`를 반환했다.
|
||||
|
||||
추가 확인 결과, `.env`에 예전 `NOTEBOOKLM_COOKIES` 값이 남아 있었다. `scripts/mcp_bridge.mjs`가 `dotenv/config`를 로드한 뒤 MCP 서버를 자식 프로세스로 실행하면서 이 오래된 환경변수 쿠키가 `~/.notebooklm-mcp/auth.json`의 최신 인증 캐시보다 우선 적용되고 있었다.
|
||||
|
||||
즉 실제 핵심 원인은 다음 조합이었다.
|
||||
|
||||
- 인증 CLI는 최신 쿠키를 `~/.notebooklm-mcp/auth.json`에 정상 저장함.
|
||||
- 브리지는 `.env`의 오래된 `NOTEBOOKLM_COOKIES`를 MCP 자식 프로세스에 전달함.
|
||||
- MCP 서버는 캐시 파일보다 환경변수를 우선 사용함.
|
||||
- 결과적으로 새 인증 후에도 MCP는 계속 오래된 쿠키로 NotebookLM API를 호출함.
|
||||
|
||||
## 조치
|
||||
|
||||
`scripts/mcp_bridge.mjs`에서 기본적으로 MCP 자식 프로세스와 인증 CLI 자식 프로세스에 `NOTEBOOKLM_COOKIES`, `NOTEBOOKLM_CSRF_TOKEN`, `NOTEBOOKLM_SESSION_ID`를 넘기지 않도록 수정했다.
|
||||
|
||||
명시적으로 환경변수 인증을 사용해야 할 경우에는 `.env`에 아래 값을 둔다.
|
||||
|
||||
```env
|
||||
USE_NOTEBOOKLM_ENV_AUTH="true"
|
||||
```
|
||||
|
||||
기본값은 `false`이며, 이 경우 `notebooklm-mcp-auth`가 생성한 `~/.notebooklm-mcp/auth.json` 캐시를 우선 사용한다.
|
||||
|
||||
또한 `auth_mac.command`, `auth_win.bat`는 별도 Chrome 프로필과 디버깅 포트를 사용해 NotebookLM 인증 브라우저를 열어두는 방식으로 변경했다.
|
||||
|
||||
## 검증
|
||||
|
||||
다음 검증을 완료했다.
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
결과:
|
||||
|
||||
```json
|
||||
{"success":true,"count":0}
|
||||
```
|
||||
|
||||
직접 Python MCP 클라이언트로도 같은 인증 캐시를 사용해 `list_notebooks` 호출이 성공했고, 노트북 89개를 읽는 것을 확인했다.
|
||||
|
||||
## 운영 메모
|
||||
|
||||
앞으로는 `.env`에 오래된 `NOTEBOOKLM_COOKIES`가 남아 있어도 기본 브리지 실행에는 영향을 주지 않는다. 다만 혼란을 줄이려면 장기적으로 `.env`에서 `NOTEBOOKLM_COOKIES` 줄을 삭제하거나 주석 처리하는 것이 좋다.
|
||||
|
||||
NotebookLM 인증용 Chrome 창은 닫지 않는 것이 좋다. 인증이 풀렸을 때 브리지가 같은 디버깅 포트의 Chrome 세션에 붙어 자동 복구를 시도할 수 있다.
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# Datacollector NotebookLM Automatic Auth Recovery
|
||||
|
||||
Date: 2026-04-25 20:47:05 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
컴퓨터 포맷 이후 NotebookLM MCP 인증이 자주 실패하고, 20-30분마다 `auth_mac.command`를 수동 실행해야 하는 문제가 있었다.
|
||||
이번 작업에서는 인증 만료 시 브리지 서버가 자동으로 복구를 시도하도록 개선했다.
|
||||
|
||||
## Root Cause Hypothesis
|
||||
|
||||
기존 구조는 MCP 서버의 `refresh_auth` 도구 호출에만 의존했다.
|
||||
하지만 포맷 이후 로컬 토큰 저장 위치나 Chrome 세션 상태가 달라지면서 `refresh_auth`만으로 복구되지 않는 상황이 발생할 수 있다.
|
||||
|
||||
사용자가 직접 실행하던 파일은 다음 명령의 래퍼였다.
|
||||
|
||||
```bash
|
||||
/Users/g1nation_mac/.local/bin/notebooklm-mcp-auth
|
||||
```
|
||||
|
||||
따라서 자동 복구 흐름에도 이 CLI 인증 명령을 포함시키는 것이 가장 직접적인 개선 방향이다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- 브리지 서버가 `.env`를 읽도록 `dotenv/config`를 추가했다.
|
||||
- `AUTH_PATH`, `AUTH_ARGS`, `AUTH_TIMEOUT_MS`, `AUTH_REFRESH_INTERVAL_MS` 설정을 추가했다.
|
||||
- MCP 인증 에러 발생 시 `refresh_auth`를 먼저 시도한다.
|
||||
- `refresh_auth` 실패 시 MCP 프로세스를 재시작하고 다시 갱신을 시도한다.
|
||||
- 그래도 실패하면 `notebooklm-mcp-auth` CLI를 브리지 서버가 직접 실행한다.
|
||||
- CLI 인증 후 MCP 프로세스를 재시작해 새 토큰을 읽게 만든다.
|
||||
- 장시간 실행 중에는 15분 간격으로 요청이 없는 시점에 인증 상태를 사전 갱신한다.
|
||||
- UI 안내 문구를 수동 재인증 중심에서 자동 복구 중심으로 수정했다.
|
||||
|
||||
## Runtime Behavior
|
||||
|
||||
새 인증 복구 순서:
|
||||
|
||||
1. NotebookLM MCP 요청 실패
|
||||
2. 에러 메시지가 인증 관련인지 판단
|
||||
3. `refresh_auth` 호출
|
||||
4. MCP 프로세스 재시작 후 `refresh_auth` 재시도
|
||||
5. `notebooklm-mcp-auth` CLI 자동 실행
|
||||
6. MCP 프로세스 재시작
|
||||
7. 원래 실패했던 NotebookLM 요청 재시도
|
||||
|
||||
주기적 갱신:
|
||||
|
||||
- 기본 간격: 15분
|
||||
- 설정값: `AUTH_REFRESH_INTERVAL_MS=900000`
|
||||
- 진행 중인 MCP 요청이 있을 때는 건드리지 않고 건너뛴다.
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run bridge
|
||||
curl -s http://127.0.0.1:3002/api/health
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- `node --check` 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- 브리지 서버 시작 성공
|
||||
- MCP 서버 초기화 성공
|
||||
- `/api/health`에서 `connected: true`, `version: 3.3.0`, `authPath` 확인
|
||||
|
||||
## Notes
|
||||
|
||||
완전히 백그라운드 인증이 가능한지는 Google/Chrome 세션 상태에 의존한다.
|
||||
브라우저 로그인이 만료되어 실제 사용자 로그인이 필요한 상태라면 자동 CLI 실행도 브라우저 로그인을 요구할 수 있다.
|
||||
다만 기존처럼 매번 사용자가 batch 파일을 직접 실행하는 흐름보다, 일반적인 토큰 만료와 MCP refresh 실패 상황은 브리지 서버가 먼저 복구하도록 개선되었다.
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# Datacollector - NotebookLM 자동 재인증 검증 강화 및 동시 복구 잠금
|
||||
|
||||
- 작성 시각: 2026-04-25 22:17:33 KST
|
||||
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
- 관련 파일: `scripts/mcp_bridge.mjs`
|
||||
|
||||
## 상황
|
||||
|
||||
인증 브라우저 유지와 오래된 `.env` 쿠키 우선순위 문제를 해결한 뒤에도, 실제 작업 중 인증이 풀렸을 때 완전히 자동으로 재인증되지 않는 문제가 남아 있었다.
|
||||
|
||||
화면에서는 작업은 진행되지만 사용자가 기대한 "인증 만료 감지 -> 자동 재인증 -> 원래 작업 재시도" 흐름이 안정적으로 보장되지 않았다.
|
||||
|
||||
## 원인
|
||||
|
||||
브리지에는 자동 복구 로직이 있었지만 두 가지 빈틈이 있었다.
|
||||
|
||||
- `refresh_auth` 호출이 성공해도 실제 NotebookLM API 호출이 가능한지 검증하지 않았다.
|
||||
- `/api/re-auth`와 `/api/check-connection` 같은 요청이 동시에 들어오면 각각 MCP 재시작과 인증 복구를 시도해서 프로세스 재시작 경합이 생길 수 있었다.
|
||||
|
||||
추가로 인증 오류 판별 문자열에 `expired`, `RPC Error 16`, `csrf`, `만료` 같은 케이스가 충분히 포함되지 않아 일부 인증 만료 메시지가 일반 오류로 처리될 가능성이 있었다.
|
||||
|
||||
## 조치
|
||||
|
||||
`scripts/mcp_bridge.mjs`에서 다음을 수정했다.
|
||||
|
||||
- 재인증 성공 기준을 `refresh_auth` 성공이 아니라 실제 `notebook_list` 호출 성공으로 강화했다.
|
||||
- 인증 만료 감지 시 `refreshAuth({ allowExternalAuth: true })`를 통해 자동 CLI 인증 복구까지 이어지도록 정리했다.
|
||||
- 주기적 인증 점검도 필요 시 외부 인증 CLI 복구를 허용하도록 변경했다.
|
||||
- `_refreshAuthPromise` 잠금을 추가해 동시 재인증/재시작 요청이 서로 충돌하지 않게 했다.
|
||||
- 인증 오류 감지 키워드에 `expired`, `rpc error 16`, `csrf`, `unauthorized`, `forbidden`, `인증`, `만료`를 추가했다.
|
||||
|
||||
## 검증
|
||||
|
||||
다음 검증을 완료했다.
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
curl -sS -X POST http://127.0.0.1:3002/api/re-auth
|
||||
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
결과:
|
||||
|
||||
- `/api/re-auth`: `success: true`
|
||||
- `/api/check-connection`: `success: true`
|
||||
|
||||
또한 `/api/re-auth`와 `/api/check-connection`을 동시에 호출해도 둘 다 성공하는 것을 확인했다.
|
||||
|
||||
## 운영 메모
|
||||
|
||||
이제 인증이 풀린 상태에서 NotebookLM MCP 호출이 인증 오류를 반환하면 브리지가 다음 순서로 자동 복구한다.
|
||||
|
||||
1. MCP의 `refresh_auth` 실행
|
||||
2. 실제 `notebook_list` 호출로 인증 유효성 검증
|
||||
3. 실패 시 MCP 프로세스 재시작 후 재검증
|
||||
4. 그래도 실패하면 `notebooklm-mcp-auth` CLI 실행
|
||||
5. 인증 캐시 정리 후 MCP 재시작 및 실제 호출 검증
|
||||
|
||||
NotebookLM 브라우저 세션이 완전히 로그아웃된 상태라면 자동 CLI도 브라우저 로그인을 요구할 수 있다. 이 경우 사용자가 열린 NotebookLM Chrome 창에서 로그인만 해두면 이후 자동 복구가 다시 이어질 수 있다.
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Datacollector NotebookLM Connection Guard and MCP Restart Fix
|
||||
|
||||
Date: 2026-04-25 21:02:35 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
실행 중 NotebookLM 연결 체크가 500 에러를 반환한 뒤에도 미션이 계속 시작되어 Local LM fallback으로 넘어가고, 결국 `Local LM returned an empty or invalid response` 에러가 발생했다.
|
||||
또한 브리지의 MCP 재시작 로직에서 자동 재시작과 수동 재시작이 겹쳐 여러 `notebooklm-mcp` 프로세스가 남는 문제가 확인되었다.
|
||||
|
||||
## Observed Errors
|
||||
|
||||
브라우저 콘솔:
|
||||
|
||||
```text
|
||||
:3000/favicon.ico 404 (Not Found)
|
||||
127.0.0.1:3002/api/check-connection 500 (Internal Server Error)
|
||||
```
|
||||
|
||||
앱 로그:
|
||||
|
||||
```text
|
||||
NotebookLM 연결 실패: 인증 자동 복구 실패...
|
||||
GENERAL MODE
|
||||
ENGINE ERROR Local LM returned an empty or invalid response.
|
||||
```
|
||||
|
||||
## Root Causes
|
||||
|
||||
1. `testNotebookLmConnection()`이 성공 여부를 반환하지 않았다.
|
||||
2. `handleStart`, `handleResume`, `handleGlobalResume`이 연결 실패 후에도 그대로 `running` 상태로 넘어갔다.
|
||||
3. `restart()`가 MCP 프로세스 종료 이벤트를 기다리지 않고 바로 새 프로세스를 띄울 수 있었다.
|
||||
4. `close` 이벤트의 자동 재시작이 수동 재시작과 겹쳐 MCP 하위 프로세스가 누적될 수 있었다.
|
||||
5. favicon 파일이 없어서 브라우저가 `/favicon.ico` 기본 요청을 404로 표시했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/index.html`
|
||||
|
||||
추가 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/public/favicon.svg`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- `testNotebookLmConnection()`이 `Promise<boolean>`을 반환하도록 변경
|
||||
- NotebookLM 연결 실패 시 신규 미션 시작, 개별 재개, 전체 재개를 보류
|
||||
- 연결 실패 후 Local LM fallback으로 자동 진행되는 흐름 차단
|
||||
- MCP 프로세스를 종료할 때 `close` 이벤트를 기다리는 `_stopCurrentProcess()` 추가
|
||||
- 재시작 중 자동 재시작이 중복 실행되지 않도록 제어
|
||||
- 재시작 테스트 후 MCP 하위 프로세스가 하나만 남는지 확인
|
||||
- SVG favicon 추가 및 `index.html`에 명시
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
npm run bridge
|
||||
curl -s http://127.0.0.1:3002/api/health
|
||||
curl -s -X POST http://127.0.0.1:3002/api/restart
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 빌드 통과
|
||||
- 브리지 시작 성공
|
||||
- `/api/health` 응답 정상
|
||||
- `/api/restart` 후 `notebooklm-mcp` 프로세스가 하나만 남는 것 확인
|
||||
|
||||
## Operational Note
|
||||
|
||||
현재 실행 중이던 오래된 브리지와 누적된 MCP 하위 프로세스는 종료했다.
|
||||
앱은 다시 실행해야 새 브리지 로직이 적용된다.
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
# Datacollector NotebookLM Progress Visibility and Auth Diagnosis
|
||||
|
||||
Date: 2026-04-25 21:17:24 KST
|
||||
Project: Datacollector
|
||||
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
|
||||
|
||||
## Summary
|
||||
|
||||
사용자가 UI에서 `NotebookLM 연결 상태 점검 중...` 로그만 반복되고 실제 진행 상황을 알 수 없다고 보고했다.
|
||||
확인 결과 앱이 프로젝트 생성 단계까지 가지 못하고 있었으며, 원인은 NotebookLM 연결 확인 단계에서 MCP 인증이 만료 상태로 판단되기 때문이었다.
|
||||
|
||||
## Observed State
|
||||
|
||||
확인한 상태:
|
||||
|
||||
- Vite 서버 `3000` 실행 중
|
||||
- MCP Bridge 서버 `3002` 실행 중
|
||||
- `notebooklm-mcp` 프로세스 실행 중
|
||||
- `/api/health` 응답 가능
|
||||
- `/api/check-connection`은 NotebookLM 인증 만료 오류 반환
|
||||
|
||||
브리지 로그상 자동 인증 CLI는 Chrome을 열고 로그인 및 토큰 추출까지 수행했다.
|
||||
그러나 MCP 서버는 이후에도 `Authentication expired`로 판단하여 NotebookLM notebook list 호출에 실패했다.
|
||||
|
||||
## Changes Made
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
|
||||
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
|
||||
|
||||
핵심 변경:
|
||||
|
||||
- MCP 초기화 타임아웃 추가: `MCP_INIT_TIMEOUT_MS`
|
||||
- NotebookLM 연결 확인 타임아웃 추가: `MCP_HEALTH_TIMEOUT_MS`
|
||||
- `/api/health`에 상세 상태 추가
|
||||
- `initialized`, `processRunning`, `processPid`, `pendingRequests`, `authStatus` 노출
|
||||
- 인증 CLI 진행 단계(`starting`, `running`, `restarting`, `success`, `failed`) 추적
|
||||
- UI 연결 점검 중 5초마다 Bridge/MCP/auth 진행 상태 로그 출력
|
||||
- 중복 연결 점검 요청은 기존 Promise를 재사용하도록 변경
|
||||
|
||||
## Verification
|
||||
|
||||
실행한 검증:
|
||||
|
||||
```bash
|
||||
node --check scripts/mcp_bridge.mjs
|
||||
npm run lint
|
||||
npm run build
|
||||
curl -sS --max-time 5 http://127.0.0.1:3002/api/health
|
||||
curl -sS --max-time 25 -X POST -H 'Content-Type: application/json' -d '{}' http://127.0.0.1:3002/api/check-connection
|
||||
```
|
||||
|
||||
검증 결과:
|
||||
|
||||
- 브리지 문법 체크 통과
|
||||
- TypeScript 타입체크 통과
|
||||
- Vite 빌드 통과
|
||||
- Bridge/MCP 프로세스는 실행됨
|
||||
- NotebookLM 연결 확인은 인증 만료 오류로 실패
|
||||
|
||||
## Current Diagnosis
|
||||
|
||||
현재 문제는 앱 실행이나 Bridge 연결 문제가 아니라 NotebookLM MCP 인증 상태 문제다.
|
||||
자동 인증 CLI가 토큰을 저장해도 MCP 서버가 계속 만료로 판단하므로, 다음 단계에서는 NotebookLM MCP 패키지의 인증 저장 형식 또는 권장 인증 방식(`--file` 모드 등)을 확인해야 한다.
|
||||
|
||||
## Operational Note
|
||||
|
||||
확인용으로 실행했던 Bridge/Vite/MCP 프로세스는 종료했다.
|
||||
새 진행 상태 로그를 보려면 앱을 `run_mac.command`로 다시 실행해야 한다.
|
||||
@@ -0,0 +1,19 @@
|
||||
# [[React가 빠른 이유]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React는 실제 DOM을 직접 조작할 때 발생하는 비용(Reflow 및 Repaint)을 최소화하기 위해 가상 DOM(Virtual DOM)과 효율적인 재조정(Reconciliation) 알고리즘을 사용합니다 [1]. 또한 Fiber 아키텍처를 도입하여 렌더링 작업을 잘게 쪼개고 우선순위에 따라 동시성(Concurrent) 렌더링을 처리함으로써 UI의 반응성을 극대화합니다 [2-4]. 최근 버전에서는 자동 배칭(Automatic Batching)과 React Compiler의 자동 메모이제이션을 통해 불필요한 재렌더링을 획기적으로 줄여 더욱 빠르고 최적화된 성능을 제공합니다 [5-8].
|
||||
|
||||
## 📖 Core Content
|
||||
* **가상 DOM(Virtual DOM)과 재조정(Reconciliation):** 실제 DOM을 직접 수정하는 작업은 브라우저 렌더링 경로(CRP)에서 레이아웃(Reflow)과 페인트(Repaint) 과정을 유발하여 본질적으로 느립니다 [1]. React는 메모리 내에 가벼운 UI 표현인 가상 DOM을 유지합니다 [1, 9, 10]. UI 상태가 변경되면 새로운 가상 DOM을 생성하고 이전 상태와 비교(Diffing)한 뒤, 실제 DOM을 최소한으로만 업데이트(Patch)하는 재조정 과정을 거쳐 불필요한 연산을 방지합니다 [1, 9, 10].
|
||||
* **O(n) 휴리스틱 Diffing 알고리즘:** 두 트리를 비교하는 일반적인 알고리즘은 $O(n^3)$의 복잡도를 가지므로 실시간 애플리케이션에 부적합합니다 [11, 12]. React는 서로 다른 타입의 요소는 전혀 다른 트리를 생성한다고 가정하고, 개발자가 제공하는 'Key'를 통해 요소를 식별하는 방식을 사용하여 복잡도를 $O(n)$으로 낮춘 휴리스틱 알고리즘을 사용합니다 [11, 12]. 이를 통해 기존 DOM 노드를 최대한 보존하며 속도를 높입니다 [2, 13].
|
||||
* **Fiber 아키텍처와 동시성(Concurrent) 렌더링:** 과거 React의 스택 재조정자(Stack Reconciler)는 동기적으로 전체 트리를 처리하여 메인 스레드를 차단하는 문제가 있었습니다 [3]. React 16부터 도입된 Fiber 아키텍처는 렌더링 작업을 '작업 단위(Unit of work)'로 분할합니다 [3, 14]. 우선순위 차선(Lane) 모델과 타임 슬라이싱(Time-slicing)을 사용하여 높은 우선순위의 작업(예: 사용자 입력)이 들어오면 기존의 렌더링을 일시 중지하고 양보(Yield)한 뒤 나중에 재개할 수 있도록 해 UI 차단을 방지합니다 [3, 4, 15, 16].
|
||||
* **자동 배칭(Automatic Batching):** React 18은 브라우저 이벤트뿐만 아니라 Promise나 setTimeout과 같은 비동기 작업 내에서 발생하는 여러 상태 업데이트를 단일 재렌더링으로 묶어 처리합니다 [5, 17, 18]. 결과적으로 가상 DOM Diffing 과정과 CPU 작업이 줄어들어 렌더링 횟수가 급감하고 프레임 속도가 향상됩니다 [5, 7, 19, 20].
|
||||
* **React Compiler에 의한 자동 메모이제이션:** React 19에 도입된 컴파일러는 빌드 시점에 추상 구문 트리(AST)를 분석하여 컴포넌트와 훅 내의 계산 비용이 높은 작업에 자동으로 메모이제이션 경계를 삽입합니다 [6, 21-23]. 이는 개발자의 수동 메모이제이션(useMemo, useCallback 등) 부담을 없애고, 입력값이 변경될 때만 세밀하게 재렌더링을 유도하여 폭포수 같은 연쇄 재렌더링 성능 저하를 방지합니다 [6, 8, 23, 24].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** `[[Virtual DOM]]`, `[[Reconciliation]]`, `[[Fiber Architecture]]`, `[[Automatic Batching]]`, `[[React Compiler]]`, `[[Reflow & Repaint]]`
|
||||
- **Projects/Contexts:** `[[프론트엔드 렌더링 최적화(Rendering Optimization)]]`, `[[브라우저 렌더링 파이프라인(Critical Rendering Path)]]`
|
||||
- **Contradictions/Notes:** 상태 트리를 비교할 때 발생하는 기존 알고리즘의 O(n³) 복잡도 한계를 O(n)으로 해결한 것이 속도의 주요 기반입니다 [11, 12]. 또한, Fiber 아키텍처에서 렌더링(Render) 단계는 중단하고 재개할 수 있는 순수 계산 과정이지만, 커밋(Commit) 단계는 DOM을 실제로 조작해야 하므로 동기식으로 차단되어 실행된다는 점이 아키텍처의 핵심적인 구분입니다 [25-27].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
# Skybound Code Structure Audit and Stabilization Plan
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw analysis logged before implementation
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This document records the first code-level audit after reviewing Skybound-related wiki documents. The goal was to compare the documented architecture with the actual code path in `/Volumes/Data/project/Antigravity/Skybound`, identify design and feature risks, and define the first stabilization pass.
|
||||
|
||||
## 2. Documents Reviewed
|
||||
|
||||
- `Topics/Skybound/Skybound-Knowledge-Hub.md`
|
||||
- `Topics/Skybound/01_Core_Engine/Skybound-Modular-Game-Architecture.md`
|
||||
- `Topics/Skybound/01_Core_Engine/Game-Engine-Loop-and-System-Orchestration.md`
|
||||
- `Topics/Skybound/05_Project_Issues/2026-04-22_Engine_Stability_Audit.md`
|
||||
- `Topics/Skybound/02_Combat_AI/Combat-System-and-Bullet-Interaction-Pipeline.md`
|
||||
- `Topics/Skybound/04_Mechanics_Progression/Campaign_and_Dual_Loop_System.md`
|
||||
- `Topics/Skybound/04_Mechanics_Progression/InGame_Progression_System.md`
|
||||
- `Technical_Reports/2026-04-22_Boss_Battle_System_Implementation.md`
|
||||
|
||||
## 3. Code Structure Observations
|
||||
|
||||
Skybound's actual runtime center is `src/features/game/hooks/useGameEngine.ts`. It directly instantiates and updates `EntityManager`, `StageDirectorSystem`, `SpawnerSystem`, `CombatSystem`, `ProgressionSystem`, `ModularWeaponSystem`, `TacticalSystem`, `HazardSystem`, `BossSystem`, `EffectSystem`, and `GameRenderer`.
|
||||
|
||||
`SystemManager.ts` exists and documents a centralized orchestration pattern, but the active engine path does not use it. This is not inherently broken, but it creates a mismatch between the documented orchestrator and the actual execution path.
|
||||
|
||||
React is primarily responsible for scene composition and modal/UI handling through `GameSceneRenderer.tsx`, while Zustand state is centralized in `useGameStore.ts`.
|
||||
|
||||
## 4. Confirmed Problems
|
||||
|
||||
### 4.1 Build Gate Is Broken
|
||||
|
||||
`npm run build` fails. Representative causes:
|
||||
|
||||
- `App.tsx` imports `useGameEngine` but does not use it.
|
||||
- Legacy `src/features/game/combatSystem.ts` is still included in TypeScript compilation and has type drift against current domain models.
|
||||
- `useSceneAudio.ts` does not include `HANGAR` in `SCENE_AUDIO`, despite `Scene` including `HANGAR`.
|
||||
- `SystemBoss.phase` is typed as `1 | 2 | 3`, while `bossRegistry.ts` contains a 4-phase boss.
|
||||
- `GameRenderer.ts` calls `CanvasRenderingContext2D.close()`, which should be `closePath()`.
|
||||
- `EntityManager` initializes enemies with `movePattern: 'NONE'`, which is not part of the current `Enemy.movePattern` union.
|
||||
|
||||
### 4.2 Timeline Spawn Intents Are Not Wired
|
||||
|
||||
`StageDirectorSystem` dispatches `SCRIPTED_SPAWN` and `SPAWN_MODE` intents, but `useGameEngine.ts` does not route those intents to `SpawnerSystem`.
|
||||
|
||||
`SpawnerSystem` already provides `notifyScriptedSpawn()` and `activateSwarmBurst()`, so the design exists but the active dispatch wiring is missing.
|
||||
|
||||
Expected impact: scripted waves and burst events may not appear as designed, leaving procedural spawning to carry too much of the combat pacing.
|
||||
|
||||
### 4.3 Campaign Stage State Is Not a Single Source of Truth
|
||||
|
||||
`StageDirectorSystem` receives `campaignStageIndex` when created, but `GameState.currentStage` still defaults to `1` and is not initialized from the selected campaign stage.
|
||||
|
||||
Expected impact: Standard campaign can show stage progression in UI while the engine continues to evaluate boss selection, damage curves, backgrounds, rewards, and tech-part rolls as Stage 1.
|
||||
|
||||
### 4.4 StageManager Mode Can Drift from Store Mode
|
||||
|
||||
`StageManager` has its own internal `mode`, defaulting to `BLITZ`. The UI updates Zustand `stageMode`, but `stageManager.setMode()` is not called from the store action.
|
||||
|
||||
Expected impact: Standard campaign clear can call `stageManager.onStageClear()` while the singleton still believes it is in Blitz mode, preventing next-stage campaign progression.
|
||||
|
||||
### 4.5 COMMS Events Are Not Rendered
|
||||
|
||||
`COMMS` events are emitted by engine systems, and `CommsOverlay.tsx` exists, but `useGameEngine.ts` does not map `COMMS` events to `useGameStore.setComms()`. `CommsOverlay` is also not rendered by `App.tsx`.
|
||||
|
||||
Expected impact: mission dialogue, warning text, and tactical pacing messages are silently dropped.
|
||||
|
||||
### 4.6 Starter Weapon Timer Is Not Cleaned Up
|
||||
|
||||
`useGameEngine.ts` starts a `setTimeout()` for starter weapon selection, but cleanup does not clear the timer.
|
||||
|
||||
Expected impact: if the engine unmounts quickly, a stale timer can emit a level-up modal or pause signal from an old engine instance.
|
||||
|
||||
### 4.7 Skill Sync Boundary Is Fragile
|
||||
|
||||
`GameSceneRenderer.tsx` calls store `addSkill()` and then engine `applySkill()`. `ProgressionSystem.applySkillSelection()` says Zustand owns skill increments, but also mutates `state.skills` as a fallback.
|
||||
|
||||
Expected impact: this usually works because of the store subscription bridge, but the ownership boundary is not clean and may cause missed or inconsistent skill levels under timing stress.
|
||||
|
||||
## 5. Stabilization Plan
|
||||
|
||||
Priority order:
|
||||
|
||||
1. Restore TypeScript build by removing obvious compile blockers and isolating legacy drift.
|
||||
2. Wire `SCRIPTED_SPAWN` and `SPAWN_MODE` intents from `StageDirectorSystem` into `SpawnerSystem`.
|
||||
3. Initialize engine `currentStage` from `stageMode` and `campaignStageIndex`.
|
||||
4. Keep `StageManager` mode synchronized with Zustand `stageMode`.
|
||||
5. Route `COMMS` events into the store and render `CommsOverlay`.
|
||||
6. Clear the starter weapon timer during engine cleanup.
|
||||
|
||||
## 6. Verification Targets
|
||||
|
||||
- `npm run build`
|
||||
- `npm run lint` as a visibility check, with the expectation that broad historical lint debt may remain after the first stabilization pass.
|
||||
|
||||
## 7. Implementation Result
|
||||
|
||||
The first stabilization pass was applied immediately after this raw audit.
|
||||
|
||||
### 7.1 Build Recovery
|
||||
|
||||
- Removed an unused `useGameEngine` import from `App.tsx`.
|
||||
- Added `HANGAR` to `SCENE_AUDIO` in `useSceneAudio.ts`.
|
||||
- Excluded legacy `src/features/game/combatSystem.ts` from `tsconfig.app.json` because the active runtime path uses `src/features/game/systems/CombatSystem.ts`.
|
||||
- Expanded boss phase typing from `1 | 2 | 3` to `number` so 4-phase registry bosses are valid.
|
||||
- Fixed `EntityManager` default enemy `movePattern` from invalid `NONE` to `SIDE_TO_SIDE`.
|
||||
- Fixed `CanvasRenderingContext2D.close()` to `closePath()`.
|
||||
- Removed compile-blocking unused locals from active systems.
|
||||
|
||||
### 7.2 Runtime Wiring Recovery
|
||||
|
||||
- `SCRIPTED_SPAWN` intents now call `SpawnerSystem.notifyScriptedSpawn()`.
|
||||
- `SPAWN_MODE` intents now activate `SWARM_BURST` or enqueue `MINI_BOSS` spawns.
|
||||
- Engine `currentStage` now initializes from `campaignStageIndex + 1` in Standard mode.
|
||||
- Zustand `setStageMode()` now synchronizes the `StageManager` singleton mode.
|
||||
- `COMMS` engine events now populate `useGameStore.activeComms`.
|
||||
- `CommsOverlay` is rendered while playing.
|
||||
- Starter weapon selection timer is cleared during engine cleanup.
|
||||
|
||||
### 7.3 Verification Result
|
||||
|
||||
- `npm run build`: passed.
|
||||
- `npm run lint`: still fails due broad pre-existing lint debt, mostly `@typescript-eslint/no-explicit-any`, older helper files, and React hook lint findings. The first pass reduced the functional blockers but did not attempt a large-scale type cleanup.
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# Skybound Final Stylized Casual Magitech Redirection
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw art direction correction after final concept change
|
||||
|
||||
## 1. Reason for Redirection
|
||||
|
||||
The previous pass moved Skybound toward **Semirealistic Magitech Fantasy**, but the latest direction returns the project to a clearer and more immediately readable mobile-survival style.
|
||||
|
||||
The new target is **Stylized Casual Magitech** for a top-down survival shooter inspired by Survivor.io.
|
||||
|
||||
This direction prioritizes:
|
||||
|
||||
- maximum in-game visibility
|
||||
- bold silhouettes
|
||||
- thick readable outlines
|
||||
- flat lighting
|
||||
- vivid magical accents
|
||||
- consistent UI language from intro to mission result
|
||||
|
||||
## 2. Core Concept
|
||||
|
||||
Skybound should feel like a polished casual magitech action game rather than a dark semirealistic fantasy title.
|
||||
|
||||
Primary gameplay readability goals:
|
||||
|
||||
- player vehicle must be instantly identifiable
|
||||
- enemies must remain readable in dense hordes
|
||||
- pickups and weapon icons must be recognizable at small sizes
|
||||
- background grid must support movement clarity without competing with combat
|
||||
- every exposed screen should share the same playful magitech frame language
|
||||
|
||||
## 3. Tone and Manner
|
||||
|
||||
### Stylized Casual Magitech
|
||||
|
||||
Visual language:
|
||||
|
||||
- bold navy outlines
|
||||
- clean top-down silhouettes
|
||||
- flat color blocks
|
||||
- minimal material noise
|
||||
- bright arcane cyan
|
||||
- gold/orange mechanical accents
|
||||
- purple and pink enemy/corruption accents
|
||||
- chunky UI frames
|
||||
- high contrast buttons and progress bars
|
||||
|
||||
Avoid:
|
||||
|
||||
- gritty brushed metal
|
||||
- heavy realistic shadows
|
||||
- low-contrast dark UI
|
||||
- thin semireal linework
|
||||
- noisy texture detail
|
||||
- external non-project image dependencies
|
||||
|
||||
## 4. Palette
|
||||
|
||||
Base colors:
|
||||
|
||||
- deep navy outline
|
||||
- saturated royal blue panels
|
||||
- readable sapphire floor tiles
|
||||
- bright brass and gold trim
|
||||
|
||||
Magic accents:
|
||||
|
||||
- arcane cyan for player and positive energy
|
||||
- crystal white-blue for highlights
|
||||
- vivid purple for advanced magic
|
||||
- hot pink for danger and enemy cores
|
||||
- mint green for healing and positive pickups
|
||||
- orange/gold for calls to action
|
||||
|
||||
## 5. Screen Coverage
|
||||
|
||||
The exposed user-facing screens were reviewed and targeted by the final theme pass:
|
||||
|
||||
- Intro title screen
|
||||
- Airframe select screen
|
||||
- Hangar / upgrade overlay
|
||||
- In-game HUD
|
||||
- Quick start overlay
|
||||
- Tutorial overlay
|
||||
- Comms overlay
|
||||
- Level up modal
|
||||
- Mission success / failed / complete result screen
|
||||
|
||||
## 6. Asset Coverage
|
||||
|
||||
The procedural asset generator now outputs the final Stylized Casual Magitech library while preserving runtime file paths.
|
||||
|
||||
Generated categories:
|
||||
|
||||
- Magitech player airframes
|
||||
- normal enemies
|
||||
- elite enemies
|
||||
- bosses
|
||||
- modular stage tiles
|
||||
- title and result local backdrops
|
||||
- item drop sprite sheet
|
||||
- turret sheet
|
||||
- weapon and skill icons
|
||||
- projectiles
|
||||
- shield and currency icons
|
||||
- muzzle flash, impact, explosion, and laser VFX
|
||||
- commander and pilot portraits
|
||||
- contact sheet preview
|
||||
|
||||
## 7. Implementation Notes
|
||||
|
||||
The generator was redirected away from semirealistic material rendering and toward flat, readable shapes.
|
||||
|
||||
Main implementation choices:
|
||||
|
||||
- palette updated to bright casual magitech colors
|
||||
- default shape helpers now draw bold navy outlines
|
||||
- material texture strength reduced to keep assets flat
|
||||
- background tiles use readable grid blocks and low-competition arcane circuitry
|
||||
- local title and result background images were generated
|
||||
- title and result screens no longer depend on external Google image URLs
|
||||
- global magitech CSS override was rewritten for the final casual tone
|
||||
|
||||
## 8. Changed Runtime Paths
|
||||
|
||||
Important changed or generated paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/scripts/generate_magitech_assets.py`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/styles/magitechArt.css`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/TitleScreen.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/ResultCard.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/magitech_art_contact_sheet.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/background/title_magitech.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/background/result_magitech.png`
|
||||
|
||||
## 9. Verification
|
||||
|
||||
Asset generation completed successfully.
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The build still reports that `/sprites/player.png` is left unresolved at build time, which is a Vite static asset warning and was already non-blocking. The production bundle was generated successfully.
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Skybound HUD and TAC Level Up Stylized Casual Magitech Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay HUD screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed gameplay screenshots showed that the HUD and TAC Level Up modal still leaned heavily into the previous cyber-terminal style.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- side HUD panels used thin cyan lines and transparent glass styling
|
||||
- top TAC level widget looked like a cold terminal module
|
||||
- control buttons were dark monochrome blocks
|
||||
- TAC Level Up modal used glitch text and blue terminal cards
|
||||
- skill cards did not share the bold casual magitech frame language
|
||||
|
||||
## 2. Cause
|
||||
|
||||
The global `magitechArt.css` provided the broad art direction, but component-level CSS files still applied later or more specific styles.
|
||||
|
||||
Main affected files:
|
||||
|
||||
- `HUDOverlay.css`
|
||||
- `LevelUpModal.css`
|
||||
|
||||
These files preserved the original Stitch/cyber UI look and overrode parts of the new tone.
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### HUD
|
||||
|
||||
HUD styling was redirected to Stylized Casual Magitech:
|
||||
|
||||
- chunky navy outlines
|
||||
- rounded blue magitech panels
|
||||
- gold active highlights
|
||||
- mint/cyan resource bars
|
||||
- less transparent glass
|
||||
- stronger mobile-game button affordance
|
||||
- side modules grouped into readable cards
|
||||
- top TAC level widget converted to a framed casual panel
|
||||
|
||||
### TAC Level Up Modal
|
||||
|
||||
The level-up modal was restyled:
|
||||
|
||||
- removed glitch pseudo text
|
||||
- removed aggressive terminal skew animation
|
||||
- converted the modal into a rounded blue magitech reward panel
|
||||
- added thick dark outline and drop-shadow depth
|
||||
- changed skill cards to chunky selectable cards
|
||||
- changed icon boxes to framed magitech sockets
|
||||
- converted level dots into brighter readable pips
|
||||
- kept EVO cards gold/orange for special hierarchy
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HUDOverlay.css`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/LevelUpModal.css`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
@@ -0,0 +1,83 @@
|
||||
# Skybound Nova Burst Icon and Effect Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix for skill-specific visual mismatch
|
||||
|
||||
## 1. Screenshot Issue
|
||||
|
||||
`Nova Burst` looked like a lemon-shaped projectile icon.
|
||||
|
||||
This did not match the actual skill behavior.
|
||||
|
||||
## 2. Skill Meaning
|
||||
|
||||
`Nova Burst` is not a missile, crystal shard, or thrown projectile.
|
||||
|
||||
Actual gameplay behavior:
|
||||
|
||||
- automatic radial AoE shockwave
|
||||
- triggers around the player
|
||||
- damages enemies inside the radius
|
||||
- knocks enemies outward
|
||||
- cooldown-based burst every few seconds
|
||||
- evolves into `Nova Guardian`, which adds stronger golden guardian behavior
|
||||
|
||||
## 3. Art Direction Correction
|
||||
|
||||
The icon should communicate:
|
||||
|
||||
- central arcane core
|
||||
- circular shockwave expansion
|
||||
- radial force
|
||||
- rune-like magitech energy
|
||||
- area control around the player
|
||||
|
||||
It should not communicate:
|
||||
|
||||
- lemon
|
||||
- fruit
|
||||
- single projectile
|
||||
- gem pickup
|
||||
- missile tip
|
||||
|
||||
## 4. Fixes Applied
|
||||
|
||||
The procedural generator now creates `Nova Burst.png` with a dedicated `nova` icon shape.
|
||||
|
||||
New visual structure:
|
||||
|
||||
- cyan circular shockwave rings
|
||||
- central navy magitech core
|
||||
- arcane core light
|
||||
- radial spokes showing outward force
|
||||
- subtle purple secondary energy ring
|
||||
|
||||
The in-game Nova Burst renderer was also adjusted:
|
||||
|
||||
- center sprite is smaller and treated as a rune core
|
||||
- expanding shockwave ring is now the main visual read
|
||||
- added translucent pressure disk
|
||||
- added segmented rune ring
|
||||
- kept Guardian variant as gold/orange
|
||||
|
||||
## 5. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/scripts/generate_magitech_assets.py`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/missiles/Nova Burst.png`
|
||||
|
||||
## 6. Verification
|
||||
|
||||
Asset generation completed successfully.
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static asset warning remains non-blocking.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Skybound Particle and Supply Readability Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed screenshot exposed two readability problems.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- Mint/cyan square particles were scattered across the floor and looked like items even though they could not be collected.
|
||||
- The supply crate asset looked good, but it was not clear whether it was a player pickup or an enemy projectile/debris object.
|
||||
|
||||
## 2. Cause
|
||||
|
||||
### Mint Floor Squares
|
||||
|
||||
The mint squares were runtime particles from `EffectSystem`.
|
||||
|
||||
They were rendered in `GameRenderer.renderEffects()` using `fillRect()`, so every spark appeared as a small collectible-looking square.
|
||||
|
||||
These particles can come from combat hits, skill effects, EMP interactions, exp pickup feedback, or other short-lived feedback systems.
|
||||
|
||||
### Supply Ambiguity
|
||||
|
||||
The supply crate sprite itself was readable as an object, but the gameplay affordance was weak.
|
||||
|
||||
It needed explicit pickup language:
|
||||
|
||||
- pickup color
|
||||
- capture ring
|
||||
- directional marker
|
||||
- short label
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### Particle Shape
|
||||
|
||||
Runtime particles now render as small rotated diamond sparks instead of square floor blocks.
|
||||
|
||||
This keeps the magical spark feedback while reducing item confusion.
|
||||
|
||||
Normal shard fragments were also changed from square blocks to triangular fragments.
|
||||
|
||||
### Supply Pickup Readability
|
||||
|
||||
Supply drops now render with:
|
||||
|
||||
- mint-green dashed pickup ring
|
||||
- soft pickup fill
|
||||
- bobbing downward arrow
|
||||
- retained supply crate sprite
|
||||
- `PICK UP` label
|
||||
|
||||
This separates supply drops from enemy bullets, hazards, and cosmetic particles.
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed path:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# Skybound Semirealistic Magitech Fantasy Redirection
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw art direction correction before second asset pass
|
||||
|
||||
## 1. Reason for Redirection
|
||||
|
||||
The first generated art pack leaned too far into childish cartoon readability: thick outlines, flat toy-like shapes, and simplified symbolic silhouettes.
|
||||
|
||||
The new target is **Semirealistic Magitech Fantasy** for a top-down horde survival-shmup inspired by Survivor.io, aimed at players aged 12-18 and casual adults.
|
||||
|
||||
## 2. Core Concept
|
||||
|
||||
The visual library should feel detailed, grounded, and cool rather than cute.
|
||||
|
||||
Primary references by feel:
|
||||
|
||||
- League of Legends-like readable fantasy detail
|
||||
- Warhammer-like dark material weight
|
||||
- Survivor.io-like top-down clarity and grid readability
|
||||
|
||||
This is still a game with high enemy density, so readability remains critical, but contrast should come from lighting, value, and energy color rather than thick black outlines.
|
||||
|
||||
## 3. Tone and Manner
|
||||
|
||||
### Semirealistic Magitech
|
||||
|
||||
Visual language:
|
||||
|
||||
- dark iron
|
||||
- aged brass
|
||||
- brushed metal
|
||||
- weathered stone
|
||||
- glowing crystals
|
||||
- engraved runes
|
||||
- arcane circuitry
|
||||
- controlled deep shadows
|
||||
- focused magical highlights
|
||||
|
||||
Avoid:
|
||||
|
||||
- childish cartoon shapes
|
||||
- toy-like flat icons
|
||||
- heavy black outlines
|
||||
- overly bright candy palettes
|
||||
- large simplified emblem-only designs
|
||||
|
||||
## 4. Palette
|
||||
|
||||
Base colors:
|
||||
|
||||
- dark sapphire
|
||||
- dark iron
|
||||
- forest green
|
||||
- weathered brass
|
||||
- basalt gray
|
||||
- deep crimson
|
||||
|
||||
Magic accents:
|
||||
|
||||
- arcane blue for player energy
|
||||
- neon purple for corruption
|
||||
- plasma red for enemy/boss danger
|
||||
- molten orange for forge/lava accents
|
||||
|
||||
## 5. Asset Rules
|
||||
|
||||
### Player Vehicle
|
||||
|
||||
The player vehicle should read as a Magitech airship rather than a simple airplane.
|
||||
|
||||
Required traits:
|
||||
|
||||
- complex symmetrical or slightly asymmetrical hull
|
||||
- dark iron and brass material mix
|
||||
- intense crystalline power core
|
||||
- smaller gun turrets
|
||||
- visible engine components, gears, vents, and rune plates
|
||||
- subtle energy glow readable from top-down view
|
||||
|
||||
### Enemies
|
||||
|
||||
Enemies should be threatening corrupted creatures or ancient mechanical horrors.
|
||||
|
||||
Examples:
|
||||
|
||||
- clockwork spiders with poison sacks
|
||||
- rune golems made of dark stone
|
||||
- corrupted winged drakes
|
||||
- ancient mechanical horrors with plasma-red cores
|
||||
|
||||
### Background
|
||||
|
||||
Background should preserve Survivor.io-style grid readability but feel like an immersive fantasy environment.
|
||||
|
||||
Target environments:
|
||||
|
||||
- ancient overgrown Magitech city ruin
|
||||
- subterranean magma forge
|
||||
|
||||
Rules:
|
||||
|
||||
- weathered stone pavement
|
||||
- broken magitech circuitry embedded in the floor
|
||||
- basalt structures
|
||||
- subtle lava or arcane channels
|
||||
- background contrast lower than enemies and player
|
||||
|
||||
### Effects
|
||||
|
||||
Player effects should be arcane blue or crystal cyan.
|
||||
|
||||
Enemy effects should lean plasma red, purple, or corrupted crimson.
|
||||
|
||||
Death effects should be optimized and satisfying:
|
||||
|
||||
- scrap metal shards
|
||||
- dark crystal fragments
|
||||
- arcane dust
|
||||
- controlled flashes, not full-screen clutter
|
||||
|
||||
### UI
|
||||
|
||||
UI should use Survivor.io-like directness with a refined dark iron and crystal shell.
|
||||
|
||||
Required traits:
|
||||
|
||||
- heavy dark iron frames
|
||||
- crystal level bar
|
||||
- rune and gear details
|
||||
- minimal but detailed HUD
|
||||
- clean modern gothic / steampunk-inspired readability
|
||||
|
||||
## 6. Implementation Notes
|
||||
|
||||
The next pass should replace the first cartoony art pack with a darker semirealistic procedural raster set while preserving runtime file paths.
|
||||
|
||||
The existing generator should be rewritten so future iterations can adjust palette, materials, and silhouettes consistently.
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
# Skybound Semirealistic Magitech Fantasy Art Pack
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Superseded by semirealistic second pass
|
||||
|
||||
## 1. Direction
|
||||
|
||||
Skybound's 2D visual identity was first redirected toward **Stylized Casual Magitech**, then corrected into **Semirealistic Magitech Fantasy** after visual review.
|
||||
|
||||
The corrected target tone is a top-down survival shooter inspired by clear mobile action readability, but with more mature fantasy material treatment:
|
||||
|
||||
- reduced outlines
|
||||
- dark iron and brass material language
|
||||
- controlled lighting
|
||||
- glowing crystalline cores
|
||||
- corrupted magical enemies
|
||||
- ancient magitech ruin backgrounds
|
||||
- high contrast at small gameplay sizes
|
||||
- color-coded enemy and weapon readability
|
||||
- playful magitech forms instead of realistic military hardware
|
||||
|
||||
## 2. Core Art Rules
|
||||
|
||||
### Silhouette
|
||||
|
||||
Every gameplay object must remain readable at 36-72px on canvas.
|
||||
|
||||
- Player vehicles use triangular forward-facing silhouettes.
|
||||
- Normal enemies use compact diamond/bug-like silhouettes.
|
||||
- Elite enemies use wider, more decorated silhouettes.
|
||||
- Bosses use tall central hulls with visible side modules and glowing cores.
|
||||
- Weapons and drops use symbolic icons instead of detailed illustrations.
|
||||
|
||||
### Linework
|
||||
|
||||
Use value contrast and glow separation instead of heavy cartoon outlines.
|
||||
|
||||
Purpose:
|
||||
|
||||
- separates sprites from busy scrolling backgrounds through lighting
|
||||
- keeps bullets, drops, and enemies visible during VFX-heavy combat
|
||||
- supports a grounded semirealistic style
|
||||
|
||||
### Lighting
|
||||
|
||||
Lighting is controlled and directional. Avoid noisy photorealism, but use subtle brushed metal, stone, and crystal texture.
|
||||
|
||||
Allowed:
|
||||
|
||||
- small inner highlights
|
||||
- soft magical glow behind important objects
|
||||
- subtle bevels
|
||||
- material grain
|
||||
- controlled shadow
|
||||
|
||||
Avoid:
|
||||
|
||||
- toy-like flat panels
|
||||
- low-contrast smoke
|
||||
- tiny greeble details
|
||||
|
||||
### Palette
|
||||
|
||||
Corrected palette:
|
||||
|
||||
- Void: `#080a12`
|
||||
- Dark iron: `#1c2029`
|
||||
- Aged brass: `#a57a37`
|
||||
- Dark sapphire: `#102a52`
|
||||
- Forest green: `#164535`
|
||||
- Crimson: `#671a20`
|
||||
- Arcane blue: `#36cdff`
|
||||
- Neon purple: `#b03eff`
|
||||
- Plasma red: `#ff4149`
|
||||
- Molten orange: `#ff7a21`
|
||||
|
||||
## 3. Generated Asset Coverage
|
||||
|
||||
The following runtime assets were regenerated in-place under `public/sprites`:
|
||||
|
||||
- player airframes: `Falcon.png`, `rayce.png`
|
||||
- charge shot: `chargeshot.png`
|
||||
- normal enemies: `normal_enemy/enemy01.png` through `enemy09.png`
|
||||
- elite enemies: `elite_enemy/elite01.png` through `elite16.png`
|
||||
- bosses: `boss/tile000.png` through `tile010.png`
|
||||
- turret atlas: `turret/turret_sprites.png`
|
||||
- item drops: `item_drops_sprite.png`
|
||||
- stage backgrounds: `background/stage_tile_1.png` through `stage_tile_8.png`
|
||||
- weapon and skill icons under `sprites/missiles`
|
||||
- core bullet, shield, currency, VFX sprites
|
||||
- comms portraits: `portraits/hq_commander.png`, `portraits/pilot_standard.png`
|
||||
|
||||
## 4. UI Skin Coverage
|
||||
|
||||
The UI skin was added through:
|
||||
|
||||
- `src/features/game/styles/magitechArt.css`
|
||||
- imported from `src/App.css`
|
||||
|
||||
The skin aligns:
|
||||
|
||||
- HUD panels
|
||||
- level-up cards
|
||||
- comms overlay
|
||||
- hangar/action buttons
|
||||
- warning text
|
||||
- canvas saturation/contrast
|
||||
|
||||
## 5. Generator
|
||||
|
||||
The art pack is reproducible through:
|
||||
|
||||
`scripts/generate_magitech_assets.py`
|
||||
|
||||
This script uses the bundled Python runtime with Pillow and generates vector-like raster PNGs. It intentionally avoids relying on one-off manual image files so future palette or silhouette changes can be regenerated consistently.
|
||||
|
||||
## 6. Preview Sheet
|
||||
|
||||
Generated preview sheet:
|
||||
|
||||
`public/sprites/magitech_art_contact_sheet.png`
|
||||
|
||||
The preview sheet is for art review only and is not currently consumed by the game runtime.
|
||||
|
||||
## 7. Follow-up Art Tasks
|
||||
|
||||
Recommended next art pass:
|
||||
|
||||
1. Add animation frame variants for normal and elite enemies.
|
||||
2. Split skill icons into a formal UI icon atlas instead of relying on individual PNGs.
|
||||
3. Add boss-specific silhouettes matching the narrative names in `bossRegistry.ts`.
|
||||
4. Add projectile color language documentation for player, enemy, boss, and gimmick bullets.
|
||||
5. Replace remaining CSS vocabulary from older cyber-neon UI with magitech naming over time.
|
||||
|
||||
## 8. Second Pass Correction
|
||||
|
||||
After user review, the first art pack was judged too childish/cartoon-like. The generator and UI skin were rewritten.
|
||||
|
||||
Second pass changes:
|
||||
|
||||
- removed thick outlines
|
||||
- added brushed metal / stone noise
|
||||
- added stronger shadows and glow-based separation
|
||||
- changed vehicles into darker magitech airships
|
||||
- changed enemies into corrupted mechanical/stone silhouettes
|
||||
- changed backgrounds into darker stone grid ruins with broken circuitry
|
||||
- changed UI from bright toy-card framing to dark iron/crystal framing
|
||||
|
||||
The reproducible generator remains:
|
||||
|
||||
`scripts/generate_magitech_assets.py`
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Skybound Stylized Casual Magitech Ingame Asset Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed screenshots exposed three in-game visual problems.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- `SUPPLY` air drop was rendered as a simple cyan ring and text label instead of a proper magitech supply crate.
|
||||
- Enemy sprites showed a faint rectangular transparency box around the aircraft body.
|
||||
- Large falling translucent circular hazards were rendered as plain gray circles and did not match the Stylized Casual Magitech tone.
|
||||
|
||||
## 2. Cause
|
||||
|
||||
### Supply Drop
|
||||
|
||||
The supply drop was not using an image asset.
|
||||
|
||||
It was drawn directly in `GameRenderer.renderAirDrops()` as:
|
||||
|
||||
- animated circle stroke
|
||||
- translucent cyan fill
|
||||
- white `SUPPLY` text
|
||||
|
||||
### Enemy Rectangle Artifact
|
||||
|
||||
The procedural generator used glow layers and Lanczos downsampling.
|
||||
|
||||
This left very low alpha pixels across the image canvas. In gameplay, those tiny alpha values became visible as a faint rectangular box around enemies.
|
||||
|
||||
### Falling Circular Hazard
|
||||
|
||||
The falling translucent circle was an `EMP_CLOUD` hazard.
|
||||
|
||||
It was drawn directly in `GameRenderer.renderHazards()` as a generic gray filled circle.
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### Supply Drop Asset
|
||||
|
||||
A new stylized magitech crate sprite was generated:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/supply_crate.png`
|
||||
|
||||
The renderer now draws this crate for air drops while preserving a small dashed cyan capture ring.
|
||||
|
||||
### Alpha Cleanup
|
||||
|
||||
The procedural asset generator now clamps very low alpha values to `0` during PNG export.
|
||||
|
||||
This removes transparent rectangle artifacts while keeping intended outlines, glow, and silhouettes.
|
||||
|
||||
Verified enemy sprite alpha:
|
||||
|
||||
- normal enemy corner alpha: `0`
|
||||
- elite enemy corner alpha: `0`
|
||||
- boss corner alpha: `0`
|
||||
- no alpha values below the cleanup threshold remain
|
||||
|
||||
### Hazard Assets
|
||||
|
||||
New hazard sprites were generated:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_emp.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_asteroid.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_debris.png`
|
||||
|
||||
`EMP_CLOUD` now renders as an arcane rune-field instead of a plain gray circle.
|
||||
|
||||
`ASTEROID` and `DEBRIS` can render as stylized magitech rock fragments instead of fallback circles.
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed or generated paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/scripts/generate_magitech_assets.py`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameAssets.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/utils/SpriteUtils.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/supply_crate.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_emp.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_asteroid.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_debris.png`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Asset generation completed successfully.
|
||||
|
||||
Alpha inspection confirmed transparent corners and no low-alpha rectangle residue for the checked enemy/boss/supply/hazard sprites.
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The build still reports the existing `/sprites/player.png` static path warning, but it remains non-blocking and the production bundle was generated successfully.
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skybound Survivor-Like Balance Curve Pass
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw gameplay balance pass from user playtest feedback
|
||||
|
||||
## 1. Playtest Feedback
|
||||
|
||||
The game shell looked close to Survivor.io / Vampire Survivors, but the actual gameplay did not feel like that genre.
|
||||
|
||||
Reported issues:
|
||||
|
||||
- gameplay did not deliver enough horde-survival pressure
|
||||
- stage balance felt uneven
|
||||
- TAC Level Up pacing felt unbalanced
|
||||
- growth did not form a satisfying user-facing curve
|
||||
|
||||
## 2. Diagnosis
|
||||
|
||||
The previous balance leaned closer to a shmup / tactical shooter.
|
||||
|
||||
Main causes found in code:
|
||||
|
||||
- simultaneous enemy cap was too low for a horde-survival feel
|
||||
- procedural spawn did not fully use the timeline `spawnIntervalMult`
|
||||
- early EXP requirement was too high
|
||||
- EXP growth multiplier was too steep
|
||||
- stage difficulty scaled enemy/bullet stats too aggressively
|
||||
- stage scripted events were compressed too early in the timeline
|
||||
- TAC Level Up card offers were weighted but not structured, so the user could receive awkward choices
|
||||
- starter skill offers could omit key horde-survival archetypes
|
||||
|
||||
## 3. Target Curve
|
||||
|
||||
New target:
|
||||
|
||||
- first meaningful upgrade should arrive quickly
|
||||
- player should see more enemies on screen
|
||||
- enemies should be individually weaker
|
||||
- danger should come from density and positioning, not bullet stat spikes
|
||||
- level-up choices should consistently support build formation
|
||||
- stage progression should rise smoothly rather than jump sharply
|
||||
|
||||
## 4. Applied Balance Changes
|
||||
|
||||
### EXP and Level-Up
|
||||
|
||||
Changes:
|
||||
|
||||
- initial required EXP lowered from `100` to `45`
|
||||
- normal enemy EXP increased from `5` to `7`
|
||||
- elite EXP increased from `25` to `32`
|
||||
- level-up EXP multiplier changed from steep `1.60 / 1.72 / 1.85` to smoother `1.24 / 1.30 / 1.36 / 1.42`
|
||||
|
||||
Expected result:
|
||||
|
||||
- early TAC Level Ups arrive faster
|
||||
- the player can form a build before the first spike
|
||||
- later progression still slows down without becoming a wall
|
||||
|
||||
### TAC Level Up Card Structure
|
||||
|
||||
The card generator now tries to offer:
|
||||
|
||||
- one owned skill upgrade
|
||||
- one synergy / spike-counter / EVO-supporting option
|
||||
- one flexible option
|
||||
|
||||
Expected result:
|
||||
|
||||
- fewer dead-choice screens
|
||||
- higher chance of completing coherent builds
|
||||
- less frustration from random-only card pools
|
||||
|
||||
### Starter Selection
|
||||
|
||||
Starter cards now come from three archetype buckets:
|
||||
|
||||
- primary damage
|
||||
- area / crowd control
|
||||
- utility / defense
|
||||
|
||||
Expected result:
|
||||
|
||||
- every run begins with a usable horde-survival foundation
|
||||
- the first choice feels strategic without becoming punishing
|
||||
|
||||
### Enemy Density and Spawning
|
||||
|
||||
Changes:
|
||||
|
||||
- hard enemy cap increased from `30` to `90`
|
||||
- timeline phase caps increased by stage and phase
|
||||
- procedural spawn interval now uses `spawnIntervalMult`
|
||||
- procedural spawns can arrive in small batches
|
||||
- formation spawns now occur more often
|
||||
- individual enemy HP and speed were reduced to support higher density
|
||||
- elite chance is now a gradual probability instead of flipping too hard by difficulty
|
||||
|
||||
Expected result:
|
||||
|
||||
- more screen-filling horde pressure
|
||||
- less empty movement time
|
||||
- more satisfying weapon-clearing moments
|
||||
|
||||
### Stage Curve
|
||||
|
||||
Changes:
|
||||
|
||||
- stage duration curve changed from `120 + stage * 30s` to `150 + stage * 18s`
|
||||
- stage difficulty scaling reduced from steep `+0.4 per stage` to smoother `+0.18 per stage`
|
||||
- phase difficulty multipliers were lowered
|
||||
- phase enemy caps were increased
|
||||
- scripted wave events are distributed across the stage instead of firing too early
|
||||
|
||||
Expected result:
|
||||
|
||||
- stages feel less spiky and more readable
|
||||
- difficulty rises through density and phase rhythm
|
||||
- player has time to grow before major pressure events
|
||||
|
||||
### Enemy Bullet and Damage Pressure
|
||||
|
||||
Changes:
|
||||
|
||||
- enemy bullet speed curves were reduced
|
||||
- damage curves were reduced
|
||||
- bullet caps were reduced
|
||||
- global enemy bullet speed multiplier reduced
|
||||
- enemy projectile damage multipliers reduced
|
||||
|
||||
Expected result:
|
||||
|
||||
- gameplay moves away from bullet-hell punishment
|
||||
- movement pressure still exists, but horde positioning becomes the main focus
|
||||
|
||||
### Weapon Rhythm
|
||||
|
||||
Several weapon cooldowns were shortened so early picks feel active sooner.
|
||||
|
||||
Nova Burst was also adjusted to trigger sooner and scale more clearly as an AoE crowd-control tool.
|
||||
|
||||
## 5. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/balance.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/CombatTimeline.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
|
||||
|
||||
## 6. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
|
||||
## 7. Next Playtest Questions
|
||||
|
||||
Recommended next playtest checks:
|
||||
|
||||
- Does the first level-up happen within a satisfying time window?
|
||||
- Does the screen feel populated without becoming unreadable?
|
||||
- Do weapons feel like they clear hordes?
|
||||
- Do stage spikes feel earned rather than sudden?
|
||||
- Does TAC Level Up usually offer at least one desirable choice?
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# Skybound Core Gameplay Rebalance and Purpose Reset
|
||||
|
||||
**Date**: 2026-04-25
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw corrective gameplay pass after balance regression
|
||||
|
||||
## 1. User Playtest Feedback
|
||||
|
||||
The previous balance pass made the game worse.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- TAC Level Up triggered repeatedly and too quickly.
|
||||
- Campaign and Blitz did not communicate a clear purpose.
|
||||
- It was unclear whether the player should dodge bullets, collect upgrades, survive waves, or simply idle.
|
||||
- Standing near the center could clear the stage with little interaction.
|
||||
- Skill choice did not feel strategic because almost any pickup worked.
|
||||
- The foundation felt like it had grown without a clear gameplay plan.
|
||||
|
||||
## 2. Diagnosis
|
||||
|
||||
The previous pass overcorrected toward reward frequency and enemy density.
|
||||
|
||||
Main problems:
|
||||
|
||||
- initial EXP requirement was too low
|
||||
- EXP gem values were too high
|
||||
- level-up carryover allowed too much momentum
|
||||
- no cooldown existed between TAC Level Up events
|
||||
- base magnet radius was too generous
|
||||
- base damage multiplier was too high
|
||||
- weapon cooldowns became too generous
|
||||
- enemy caps became too high for the current combat model
|
||||
- enemies were too weak for the amount of automatic player damage
|
||||
|
||||
The result was a reward flood without enough danger, movement, or tactical pressure.
|
||||
|
||||
## 3. New Gameplay Purpose
|
||||
|
||||
Skybound should not be a pure bullet hell and should not be an idle auto-clear game.
|
||||
|
||||
The intended player loop should be:
|
||||
|
||||
1. Survive incoming enemy formations and hazard pressure.
|
||||
2. Move deliberately to collect EXP gems and supply rewards.
|
||||
3. Choose upgrades that solve the current pressure pattern.
|
||||
4. Build toward synergies and evolutions.
|
||||
5. Enter boss or spike phases with a build that feels earned.
|
||||
|
||||
The main fun should come from:
|
||||
|
||||
- movement under pressure
|
||||
- risk-reward EXP collection
|
||||
- tactical skill choices
|
||||
- visible power growth
|
||||
- stage pressure that asks for different answers
|
||||
|
||||
The player should not be able to win reliably by standing still.
|
||||
|
||||
## 4. Corrective Fixes Applied
|
||||
|
||||
### TAC Level Up Flood Control
|
||||
|
||||
Applied:
|
||||
|
||||
- initial required EXP increased from `45` to `90`
|
||||
- normal enemy EXP reduced from `7` to `4`
|
||||
- elite EXP reduced from `32` to `20`
|
||||
- level-up multiplier increased to `1.42 / 1.48 / 1.55 / 1.62`
|
||||
- added a `360 frame` TAC Level Up lockout after each level-up
|
||||
- EXP carryover is capped to `35%` of the next requirement
|
||||
|
||||
Expected result:
|
||||
|
||||
- level-up moments become meaningful beats
|
||||
- no rapid-fire modal spam
|
||||
- players must keep playing between upgrades
|
||||
|
||||
### Movement Incentive
|
||||
|
||||
Applied:
|
||||
|
||||
- base magnet radius reduced from `180` to `90`
|
||||
- magnet passive now adds `35` per level instead of `60`
|
||||
|
||||
Expected result:
|
||||
|
||||
- EXP collection requires movement
|
||||
- standing still misses more progression
|
||||
- magnet becomes a strategic comfort/passive choice rather than free global collection
|
||||
|
||||
### Idle-Clear Reduction
|
||||
|
||||
Applied:
|
||||
|
||||
- base effective damage reduced from `1.5` to `1.0`
|
||||
- damage passive now provides growth from deliberate investment
|
||||
- several weapon cooldowns were pulled back from the previous overly generous pass
|
||||
- Nova Burst was returned closer to a periodic tactical tool rather than constant auto-clear
|
||||
|
||||
Expected result:
|
||||
|
||||
- early weapons no longer erase all pressure automatically
|
||||
- skill investment matters more
|
||||
- AoE tools help but do not replace positioning
|
||||
|
||||
### Enemy Pressure Recentered
|
||||
|
||||
Applied:
|
||||
|
||||
- hard enemy cap reduced from `90` to `56`
|
||||
- phase caps reduced from the previous overcorrection
|
||||
- enemy HP increased from the previous too-low values
|
||||
- enemies enter deeper into the playfield
|
||||
- enemy speed and bullet pressure were slightly restored
|
||||
- procedural spawn cadence reduced from the flood state
|
||||
|
||||
Expected result:
|
||||
|
||||
- fewer meaningless bodies
|
||||
- enemies apply actual positional pressure
|
||||
- player must dodge, reposition, and collect intentionally
|
||||
|
||||
## 5. Design Rule Going Forward
|
||||
|
||||
Future balance changes should follow this rule:
|
||||
|
||||
Do not increase rewards unless a matching risk or movement requirement exists.
|
||||
|
||||
Examples:
|
||||
|
||||
- faster level-up needs harder collection or less carryover
|
||||
- more enemies need weaker auto-clear or stronger enemy pathing
|
||||
- stronger skills need clearer spike counters or enemy behaviors
|
||||
- more pickups need better pickup affordance and danger around pickup zones
|
||||
|
||||
## 6. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/CombatTimeline.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/balance.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
|
||||
## 7. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static asset warning remains non-blocking.
|
||||
|
||||
## 8. Next Necessary Design Work
|
||||
|
||||
This corrective patch stabilizes the worst problems, but the project still needs a stronger core design pass.
|
||||
|
||||
Recommended next work:
|
||||
|
||||
- define Campaign as objective-based stages with unique pressure patterns
|
||||
- define Blitz as score/survival mode with explicit risk-reward scoring
|
||||
- add clear stage objectives to HUD
|
||||
- add enemy archetypes that force movement differently
|
||||
- add pickup-risk zones so rewards are not free
|
||||
- review every skill for role identity: damage, crowd control, defense, mobility, economy
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# Skybound Player Airframe and 8 Stage Boss Continuity Rework
|
||||
|
||||
작성일: 2026-04-25 09:51 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- 사용자 기체가 엔진에서 그린 도형 조립처럼 보여 시각적 완성도가 낮아 보이는 문제를 개선한다.
|
||||
- Stage 1 클리어 후 Stage 2로 넘어가는 흐름이 결과 화면으로 끊겨 게임이 단절되는 문제를 개선한다.
|
||||
- Aero Fighters처럼 보스를 처치하고 같은 런 안에서 다음 스테이지로 자연스럽게 이어지는 구조를 만든다.
|
||||
- 총 8개 스테이지를 유지하고, 스테이지가 올라갈수록 난이도가 올라가도록 보스 HP, 파츠, 패턴을 재조정한다.
|
||||
- 각 스테이지 보스가 서로 다른 공격 패턴을 체감할 수 있도록 실행부를 보강한다.
|
||||
|
||||
## 확인한 문제
|
||||
|
||||
### 플레이어 기체 렌더링
|
||||
|
||||
- `GameRenderer.renderPlayer()`에서 플레이어 스프라이트 위에 랜덤 원형 엔진 글로우를 직접 그려서, 기체 뒤쪽이 매 프레임 흔들리는 임시 도형처럼 보였다.
|
||||
- `renderWeaponAttachments()`에서 일부 장착 무기를 `fillRect`, `strokeRect`, 랜덤 원형 플래시로 그려서 톤앤매너에 맞는 완성형 파츠가 아니라 디버그 박스처럼 보일 수 있었다.
|
||||
- 특히 Hyper Sonic Vulcan, Gatling fallback, Missile Pod fallback이 사용자 기체 실루엣과 잘 섞이지 않았다.
|
||||
|
||||
### 스테이지 전환
|
||||
|
||||
- 보스 처치 후 `STAGE_CLEAR`가 되고, 300프레임 뒤 `BOSS_ACTION NEXT_STAGE` 이벤트가 발생한다.
|
||||
- 기존 `useGameEngine`은 이 이벤트를 곧바로 `finishMission('CLEAR')`로 연결했다.
|
||||
- 그 결과 Standard 캠페인에서도 Stage 1 보스 처치 후 결과 화면으로 끊기고, 다음 스테이지는 별도 런처럼 느껴졌다.
|
||||
|
||||
### 보스 패턴
|
||||
|
||||
- `bossActions.ts`에는 Stage 1부터 Stage 8까지 액션 테이블이 있다.
|
||||
- 하지만 `BossSystem.executePattern()`은 일부 액션만 처리하고 있었기 때문에, 실제 전투에서는 많은 액션이 기본 단발 탄으로 떨어질 수 있었다.
|
||||
- `StageDirectorSystem.instantiateBoss()`의 보스 파츠 turretId가 `T-CORE`, `T-WING`, `T-HEAVY`처럼 실제 `TURRET_CATALOG`에 없는 값이라 파츠 포탑이 의도대로 발사되지 않을 수 있었다.
|
||||
- 기존 보스 HP는 Stage 2부터 `5000 * currentStage`로 급격히 올라가 캠페인 커브가 자연스럽지 않았다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### 플레이어 기체 완성도 개선
|
||||
|
||||
- 플레이어 엔진 글로우를 랜덤 원형에서 고정된 마기테크 추진 플룸으로 변경했다.
|
||||
- 스프라이트 크기를 72px에서 78px로 약간 키워 중심 기체의 존재감을 높였다.
|
||||
- `drawMagitechPod()` 헬퍼를 추가해 장착 무기를 작은 마기테크 포드 형태로 통일했다.
|
||||
- Vulcan, Gatling fallback, Missile Pod fallback을 박스 도형 대신 다크 블루 메탈 바디, 시안/옐로/핑크 액센트, 라운드 포드 실루엣으로 렌더링한다.
|
||||
- 장착 파츠의 랜덤 플래시를 줄이고 프레임 기반 pulse로 바꿔 덜 튀고 더 의도적으로 보이게 했다.
|
||||
|
||||
### 연속 캠페인 전환
|
||||
|
||||
- Standard 캠페인에서 Stage 1-7 보스 처치 후 `finishMission`을 호출하지 않고, 같은 엔진 런 안에서 다음 스테이지로 전환하도록 변경했다.
|
||||
- 전환 시 다음 작업을 수행한다.
|
||||
- `currentStage` 증가
|
||||
- `campaignStageIndex` 저장
|
||||
- `StageDirectorSystem.advanceToStage()`로 새 타임라인 로드
|
||||
- 활성 총알, 적, 파티클 풀 정리
|
||||
- 스포너 큐 초기화
|
||||
- 보스, 탄막, hazard, airdrop, exp gem, vortex 정리
|
||||
- `INTRO` 페이즈로 재시작
|
||||
- 체력 25% 회복과 120프레임 무적 부여
|
||||
- Stage 안내 텍스트와 HQ comms 출력
|
||||
- Stage 8 보스 처치 시에는 `GAME_COMPLETE`로 결과 화면에 진입한다.
|
||||
- Blitz 모드는 기존처럼 단일 전투 클리어로 유지한다.
|
||||
|
||||
### 8스테이지 보스 커브
|
||||
|
||||
- 보스 HP를 선형 폭증에서 완만한 곡선형 성장으로 변경했다.
|
||||
- Stage 1은 낮게 시작하고, Stage 8은 누적 성장과 보스 패턴 난이도를 고려해 높은 난이도를 갖도록 설계했다.
|
||||
- 보스 파츠 HP도 같은 stage curve를 사용해 코어, 날개, 포탑이 함께 성장한다.
|
||||
- 각 스테이지에 실제 `TURRET_CATALOG`에 존재하는 turretId loadout을 지정했다.
|
||||
|
||||
### 보스 패턴 실행 보강
|
||||
|
||||
- 다음 액션들이 실제 탄막/기믹으로 실행되도록 매핑했다.
|
||||
- `FAN_PART`, `DASH_PART`: 부채꼴 조준 사격
|
||||
- `SIDE_WAVE`: 좌우 측면 웨이브
|
||||
- `ZONE_BOMB`: 안전 구역 압박과 링 탄막
|
||||
- `WALL_WAVE`: 틈이 있는 벽 형태 탄막
|
||||
- `MISSILE_BARRAGE`, `HOMING_CHASE`: 유도성 탄막
|
||||
- `CROSS_CHASE`: 네 방향 교차 추격 탄
|
||||
- `SPIRAL_WEB`, `REVOLVING_FLAME`: 나선 탄막
|
||||
- `BURST_SPLITTER`: 분열형 부채 탄
|
||||
- `GEAR_STORM`: 고밀도 나선과 링 조합
|
||||
- `PRECISION_LOCK`, `SNIPE_GRID`, `LASER_AIM`, `LASER_SWEEP`: 크로스헤어 기반 고속 압박
|
||||
- `TELEPORT_STRIKE`: 보스 위치 변경 후 기습 사격
|
||||
- `GIMMICK_PULSE`, `CC_REVERSE`, `ZONE_COLLAPSE`: 중력장/페이즈존 기믹과 링 탄막
|
||||
- `ULTIMATE_SYMPHONY`: 기존 고난도 복합 패턴 유지
|
||||
|
||||
## 수정 파일
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/StageDirectorSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/BossSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/EntityManager.ts`
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- Vite 경고: `/sprites/player.png referenced in /sprites/player.png didn't resolve at build time`
|
||||
- 위 경고는 기존 런타임 경로 관련 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
|
||||
|
||||
## 후속 플레이테스트 포인트
|
||||
|
||||
- Stage 1 보스 처치 후 결과 화면 없이 Stage 2 INTRO로 자연스럽게 이어지는지 확인한다.
|
||||
- Stage 8 보스 처치 후 `GAME_COMPLETE` 결과로 진입하는지 확인한다.
|
||||
- 장착 무기 파츠가 기체와 과하게 분리되어 보이지 않는지 확인한다.
|
||||
- Stage 3 이후 `ZONE_BOMB`, `WALL_WAVE`, `HOMING_CHASE`, `PRECISION_LOCK` 계열이 회피 목적을 명확히 만드는지 확인한다.
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# Skybound Skill Concept and Hangar Layout Overlap Fix
|
||||
|
||||
작성일: 2026-04-25 10:09 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- 스킬 업그레이드 후 화면에 긴 라이트 기둥만 보이는 문제가 있어 스킬 개념과 연출을 수정한다.
|
||||
- HUD/UI 관점에서 왼쪽에 여러 UI가 겹쳐 나오는 문제가 있어 필요하면 전체적으로 재설계한다.
|
||||
|
||||
## 확인한 문제
|
||||
|
||||
### Hyper-Sonic Vulcan 컨셉 불일치
|
||||
|
||||
- `Hyper-Sonic Vulcan`은 이름상 고속 벌컨/캐논 계열인데 실제 구현은 영구 지속되는 긴 레이저 빔이었다.
|
||||
- `GameRenderer`가 플레이어 기준으로 화면 끝까지 이어지는 두꺼운 시안 빔을 그려서, 스킬이 무기라기보다 긴 조명처럼 보였다.
|
||||
- `ModularWeaponSystem.updateHyperLaser()`도 라인 판정으로 지속 데미지를 넣고 있어 플레이어가 발사/탄막을 체감하기 어려웠다.
|
||||
|
||||
### Hangar UI 겹침
|
||||
|
||||
- `HangarOverlay.tsx`에서 `UPGRADE`와 `PASS` 탭 콘텐츠가 오른쪽 `craft-area` 패널 밖에 렌더링되고 있었다.
|
||||
- 그 결과 CSS Grid의 세 번째 아이템처럼 배치되어 왼쪽 패널/재료 영역과 겹쳐 보였다.
|
||||
- 특히 `UPGRADE` 탭 선택 시 `PERMANENT UPGRADES` 콘텐츠가 왼쪽 재료 패널 위로 올라오는 문제가 발생했다.
|
||||
|
||||
### 전투 보상 텍스트 겹침
|
||||
|
||||
- 적 처치 보상 텍스트가 화면 가장자리에서 생성될 경우 `TechMats`, `+TAC` 같은 텍스트가 잘리거나 서로 겹쳐 보일 수 있었다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### Twin Arc Vulcan으로 스킬 컨셉 변경
|
||||
|
||||
- `HYPER_SONIC_VULCAN` 메타데이터 이름을 `Twin Arc Vulcan`으로 변경했다.
|
||||
- 설명도 `Twin magitech cannons fire rapid piercing arc rounds.`로 바꿔 실제 플레이 감각과 맞췄다.
|
||||
- 기존의 영구 레이저 빔 컨셉을 제거하고, 전방 관통 아크 탄환을 빠르게 발사하는 무기로 재설계했다.
|
||||
- 플레이어 좌우 포드에서 3갈래 관통탄을 빠르게 발사해 “벌컨 업그레이드” 느낌을 강화했다.
|
||||
- 스킬이 화면을 덮는 긴 빛이 아니라, 방향성과 탄막 밀도가 있는 공격으로 보이게 했다.
|
||||
|
||||
### 긴 라이트 렌더링 제거
|
||||
|
||||
- `GameRenderer`의 full-screen beam `fillRect()` 렌더링을 제거했다.
|
||||
- 대신 기체 앞쪽 포드에 짧은 muzzle bloom과 짧은 시안 streak만 표시하도록 변경했다.
|
||||
- 화면 전체를 가리는 시각 노이즈를 줄이고, 실제 공격은 projectile 렌더링이 담당하게 했다.
|
||||
|
||||
### Hangar 탭 레이아웃 수정
|
||||
|
||||
- `UPGRADE`와 `PASS` 탭 콘텐츠를 오른쪽 `craft-area` 내부로 이동했다.
|
||||
- 이제 탭 콘텐츠가 왼쪽 `Airframe Telemetry`/`Materials` 패널과 겹치지 않는다.
|
||||
- 기존 스타일을 유지하면서 구조적 렌더링 오류를 먼저 제거했다.
|
||||
|
||||
### Floating Text 안전 영역 처리
|
||||
|
||||
- `ctx.spawnText()`에서 텍스트 생성 위치를 화면 안전 영역 안으로 clamp한다.
|
||||
- 왼쪽 끝/오른쪽 끝에서 적이 죽어도 보상 텍스트가 화면 밖으로 잘리거나 HUD 영역에 과하게 겹치는 현상을 줄였다.
|
||||
|
||||
## 수정 파일
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/evolutions.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HangarOverlay.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- Vite 경고: `/sprites/player.png referenced in /sprites/player.png didn't resolve at build time`
|
||||
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
|
||||
|
||||
## 후속 플레이테스트 포인트
|
||||
|
||||
- Gatling 진화 후 더 이상 긴 레이저 기둥이 보이지 않는지 확인한다.
|
||||
- `Twin Arc Vulcan`이 빠른 관통 탄막 무기로 체감되는지 확인한다.
|
||||
- Hangar에서 `UPGRADES`, `EVENT PASS` 탭 선택 시 왼쪽 패널과 콘텐츠가 겹치지 않는지 확인한다.
|
||||
- 전투 보상 텍스트가 화면 가장자리에서 잘리지 않는지 확인한다.
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
# Skybound Tac EXP Direct Kill and UI Productization Pass
|
||||
|
||||
작성일: 2026-04-25 10:01 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- Tac Level 경험치는 적기를 처치했을 때 바로 획득하게 한다.
|
||||
- 바닥에 경험치 파티클/젬이 떨어져 화면을 어지럽히지 않게 한다.
|
||||
- 너무 빠른 레벨업으로 난이도 밸런스가 무너지는 문제를 완화한다.
|
||||
- Hangar, HUD, Tac Level Up 등 아직 남아 있는 예전 UI 톤을 Stylized Casual Magitech 톤앤매너에 맞게 통일한다.
|
||||
- `THRUST_OUTPUT`처럼 작동하지 않거나 내부 시스템 문자열처럼 보이는 UI 문구를 상품성 있게 정리한다.
|
||||
|
||||
## 확인한 문제
|
||||
|
||||
### Tac EXP
|
||||
|
||||
- `CombatSystem`이 적 사망 시 `spawnExpGem()`을 호출해 바닥에 경험치 젬을 생성하고 있었다.
|
||||
- `ProgressionSystem`은 바닥 젬의 이동, 자석 흡수, 수집을 통해 경험치를 지급했다.
|
||||
- 적 밀도가 올라갈수록 젬이 많이 쌓이고, 화면 가독성과 레벨업 속도 모두 불안정해질 수 있었다.
|
||||
- 기존 젬 값은 일반몹/엘리트몹 기준으로 레벨업을 빠르게 밀어 올리는 구조였다.
|
||||
|
||||
### HUD 문구
|
||||
|
||||
- `SYSTEM_ACTIVE`, `TAC_LEVEL`, `HIGH_SCORE_SYNC`, `COMBO_LINK`, `ENERGY_CELL`, `LOCK_ON`, `HEAT_SIG`, `SHIELD_OS`, `THRUST_OUTPUT` 같은 내부 변수명 스타일 문구가 사용자에게 그대로 노출되고 있었다.
|
||||
- `THRUST_OUTPUT`은 `dodgeCooldownPct`를 읽지만 엔진에서 값을 갱신하지 않아 실질적으로 반응하지 않는 상태였다.
|
||||
|
||||
### Hangar UI
|
||||
|
||||
- 장비 카드가 빈 박스처럼 보이며 아이템명/레벨/스탯 정보가 충분히 드러나지 않았다.
|
||||
- 탭 이름과 슬롯 이름이 기능적이지만 상품 화면처럼 자연스럽지는 않았다.
|
||||
- 전체 스타일이 이전의 얇은 선, 어두운 반투명 박스 중심이라 현재 게임의 굵은 외곽선/밝은 마법 액센트 톤과 어긋났다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### Tac EXP 직접 지급
|
||||
|
||||
- `CombatSystem`에서 적 사망 시 더 이상 `spawnExpGem()`을 호출하지 않는다.
|
||||
- 대신 `ctx.grantTacExp()`를 통해 처치 즉시 경험치를 지급한다.
|
||||
- 일반 적: `+1 TAC`
|
||||
- 엘리트 적: `+5 TAC`
|
||||
- 미드 보스: `+16 TAC`
|
||||
- 엘리트 이상만 짧은 `+TAC` 텍스트 피드백을 표시해 화면 노이즈를 줄였다.
|
||||
- 바닥 경험치 젬은 신규 생성되지 않으므로, 플레이 중 먹을 수 없는 파란 점/구슬이 쌓이는 문제가 사라진다.
|
||||
|
||||
### 레벨업 속도 완화
|
||||
|
||||
- `ProgressionSystem.grantExp()`를 추가해 직접 경험치 지급과 기존 젬 수집 지급을 한 곳에서 처리한다.
|
||||
- Spike 전 EXP 부스트는 최대 `x1.25`로 제한했다.
|
||||
- 기존 레벨업 lockout과 carryover cap은 유지해 연속 레벨업 폭주를 방지한다.
|
||||
|
||||
### HUD 상품성 개선
|
||||
|
||||
- `HIGH_SCORE_SYNC` → `Best Run`
|
||||
- `SYSTEM_ACTIVE` → `Falcon Online`
|
||||
- `TAC_LEVEL` → `Tactical Level`
|
||||
- `THRUST_OUTPUT` → `Afterburner`
|
||||
- `ENERGY_CELL` → `Hull Core`
|
||||
- `COMBO_LINK` → `Chain Bonus`
|
||||
- `LOCK_ON` → `Lock-On`
|
||||
- `HEAT_SIG` → `Heat Trace`
|
||||
- `SHIELD_OS` → `Guard Field`
|
||||
- 페이즈 표시도 `BOSS_WARNING` 같은 내부 enum 대신 `Boss Incoming`, `Horde Surge`, `Route Secured` 같은 플레이어용 문구로 매핑했다.
|
||||
- 엔진에서 `setDodgeCooldownPct()`를 실제 dodge 상태에 맞게 갱신해 Afterburner 게이지가 부스트 중 반응하도록 연결했다.
|
||||
|
||||
### Hangar UI 톤 통일
|
||||
|
||||
- Hangar 배경과 패널을 Stylized Casual Magitech 톤으로 보강했다.
|
||||
- 굵은 네이비 외곽선, 청록/민트/골드 마법 액센트, 둥근 카드, 명확한 hover 피드백을 적용했다.
|
||||
- 장비 카드에 아이템 타입, 이름, 레벨, ATK, HP가 보이도록 개선했다.
|
||||
- 탭 이름을 `LOADOUT`, `SYNTHESIS`, `SALVAGE`, `ASTRAL FORGE`, `UPGRADES` 등 더 자연스러운 메뉴명으로 바꿨다.
|
||||
- 빈 슬롯 문구를 `NO MODULE`에서 `Available mount`로 바꿨다.
|
||||
- `SYSTEM MOUNTS`, `MODULE STORAGE`를 각각 `Mount Bays`, `Module Storage`로 정리했다.
|
||||
|
||||
### Level Up 모달 문구 개선
|
||||
|
||||
- `TAC LV`, `TAC LEVEL UP!`, `SELECT TACTICAL ENHANCEMENT` 중심의 시스템 문자열 느낌을 줄였다.
|
||||
- 일반 레벨업: `Tactical Upgrade`
|
||||
- 시작 선택: `Choose First Weapon`
|
||||
- 보급 선택: `Emergency Supply`
|
||||
- 카드 문구도 `NEW ACQUISITION`에서 `New module`로 완화했다.
|
||||
|
||||
## 수정 파일
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HUDOverlay.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HangarOverlay.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HangarOverlay.css`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/LevelUpModal.tsx`
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- Vite 경고: `/sprites/player.png referenced in /sprites/player.png didn't resolve at build time`
|
||||
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
|
||||
- 주요 내부 문자열 검색 결과, 요청에서 지적된 `SYSTEM_ACTIVE`, `THRUST_OUTPUT`, `TAC_LEVEL`, `HIGH_SCORE_SYNC`, `COMBO_LINK`, `ENERGY_CELL`, `LOCK_ON`, `HEAT_SIG`, `SHIELD_OS`는 현재 게임 UI 코드에서 제거되었다.
|
||||
|
||||
## 후속 플레이테스트 포인트
|
||||
|
||||
- 적 처치 후 바닥에 경험치 젬이 신규로 생성되지 않는지 확인한다.
|
||||
- 일반몹을 많이 잡아도 Tac Level이 연속 폭주하지 않는지 확인한다.
|
||||
- Afterburner 게이지가 회피/부스트 중 시각적으로 반응하는지 확인한다.
|
||||
- Hangar 장비 카드가 더 이상 빈 회색 박스처럼 보이지 않고 아이템 정보를 명확히 보여주는지 확인한다.
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Skybound Stylized Casual Magitech Ingame Asset Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed screenshots exposed three in-game visual problems.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- `SUPPLY` air drop was rendered as a simple cyan ring and text label instead of a proper magitech supply crate.
|
||||
- Enemy sprites showed a faint rectangular transparency box around the aircraft body.
|
||||
- Large falling translucent circular hazards were rendered as plain gray circles and did not match the Stylized Casual Magitech tone.
|
||||
|
||||
## 2. Cause
|
||||
|
||||
### Supply Drop
|
||||
|
||||
The supply drop was not using an image asset.
|
||||
|
||||
It was drawn directly in `GameRenderer.renderAirDrops()` as:
|
||||
|
||||
- animated circle stroke
|
||||
- translucent cyan fill
|
||||
- white `SUPPLY` text
|
||||
|
||||
### Enemy Rectangle Artifact
|
||||
|
||||
The procedural generator used glow layers and Lanczos downsampling.
|
||||
|
||||
This left very low alpha pixels across the image canvas. In gameplay, those tiny alpha values became visible as a faint rectangular box around enemies.
|
||||
|
||||
### Falling Circular Hazard
|
||||
|
||||
The falling translucent circle was an `EMP_CLOUD` hazard.
|
||||
|
||||
It was drawn directly in `GameRenderer.renderHazards()` as a generic gray filled circle.
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### Supply Drop Asset
|
||||
|
||||
A new stylized magitech crate sprite was generated:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/supply_crate.png`
|
||||
|
||||
The renderer now draws this crate for air drops while preserving a small dashed cyan capture ring.
|
||||
|
||||
### Alpha Cleanup
|
||||
|
||||
The procedural asset generator now clamps very low alpha values to `0` during PNG export.
|
||||
|
||||
This removes transparent rectangle artifacts while keeping intended outlines, glow, and silhouettes.
|
||||
|
||||
Verified enemy sprite alpha:
|
||||
|
||||
- normal enemy corner alpha: `0`
|
||||
- elite enemy corner alpha: `0`
|
||||
- boss corner alpha: `0`
|
||||
- no alpha values below the cleanup threshold remain
|
||||
|
||||
### Hazard Assets
|
||||
|
||||
New hazard sprites were generated:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_emp.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_asteroid.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_debris.png`
|
||||
|
||||
`EMP_CLOUD` now renders as an arcane rune-field instead of a plain gray circle.
|
||||
|
||||
`ASTEROID` and `DEBRIS` can render as stylized magitech rock fragments instead of fallback circles.
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed or generated paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/scripts/generate_magitech_assets.py`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameAssets.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/utils/SpriteUtils.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/supply_crate.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_emp.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_asteroid.png`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/vfx/vfx_hazard_debris.png`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Asset generation completed successfully.
|
||||
|
||||
Alpha inspection confirmed transparent corners and no low-alpha rectangle residue for the checked enemy/boss/supply/hazard sprites.
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The build still reports the existing `/sprites/player.png` static path warning, but it remains non-blocking and the production bundle was generated successfully.
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Skybound HUD and TAC Level Up Stylized Casual Magitech Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay HUD screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed gameplay screenshots showed that the HUD and TAC Level Up modal still leaned heavily into the previous cyber-terminal style.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- side HUD panels used thin cyan lines and transparent glass styling
|
||||
- top TAC level widget looked like a cold terminal module
|
||||
- control buttons were dark monochrome blocks
|
||||
- TAC Level Up modal used glitch text and blue terminal cards
|
||||
- skill cards did not share the bold casual magitech frame language
|
||||
|
||||
## 2. Cause
|
||||
|
||||
The global `magitechArt.css` provided the broad art direction, but component-level CSS files still applied later or more specific styles.
|
||||
|
||||
Main affected files:
|
||||
|
||||
- `HUDOverlay.css`
|
||||
- `LevelUpModal.css`
|
||||
|
||||
These files preserved the original Stitch/cyber UI look and overrode parts of the new tone.
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### HUD
|
||||
|
||||
HUD styling was redirected to Stylized Casual Magitech:
|
||||
|
||||
- chunky navy outlines
|
||||
- rounded blue magitech panels
|
||||
- gold active highlights
|
||||
- mint/cyan resource bars
|
||||
- less transparent glass
|
||||
- stronger mobile-game button affordance
|
||||
- side modules grouped into readable cards
|
||||
- top TAC level widget converted to a framed casual panel
|
||||
|
||||
### TAC Level Up Modal
|
||||
|
||||
The level-up modal was restyled:
|
||||
|
||||
- removed glitch pseudo text
|
||||
- removed aggressive terminal skew animation
|
||||
- converted the modal into a rounded blue magitech reward panel
|
||||
- added thick dark outline and drop-shadow depth
|
||||
- changed skill cards to chunky selectable cards
|
||||
- changed icon boxes to framed magitech sockets
|
||||
- converted level dots into brighter readable pips
|
||||
- kept EVO cards gold/orange for special hierarchy
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HUDOverlay.css`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/LevelUpModal.css`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
@@ -0,0 +1,23 @@
|
||||
# [[Concurrent Rendering]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Concurrent Rendering(동시성 렌더링)은 메인 스레드를 블로킹하지 않고 UI의 여러 부분을 병렬로 렌더링할 수 있게 해주는 React의 핵심 아키텍처 기능입니다 [1]. 렌더링 작업을 'Time Slicing(시간 분할)'을 통해 작은 단위로 쪼개고 중요도에 따라 우선순위를 부여하여, 긴급한 사용자 입력에 반응하기 위해 렌더링을 일시 중지하거나 재개할 수 있습니다 [1, 2]. 이를 통해 무거운 연산 중에도 UI가 멈추지 않고 즉각적으로 반응하도록 하여 애플리케이션의 체감 성능을 극대화합니다 [3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
|
||||
* **Fiber 아키텍처와 Work Loop**
|
||||
Concurrent Rendering은 React 16에서 처음 도입된 Fiber 아키텍처를 기반으로 작동합니다 [5, 6]. 기존의 단일 재귀 호출 기반 동기식 렌더링과 달리, 렌더링 작업을 'Fiber 노드'라는 작은 작업 단위(Unit of Work)로 분할합니다 [2, 7]. React는 Work Loop를 통해 이 트리를 점진적으로 순회하며, 각 작업 단위가 끝날 때마다 브라우저에 제어권을 양보(yield)하여 클릭과 같은 고우선순위 상호작용을 처리할 수 있는지 확인합니다 [8, 9].
|
||||
* **우선순위 기반 스케줄링 (Lane Model)**
|
||||
동시성 작업의 우선순위는 'Lane'이라는 비트마스크 시스템을 통해 체계적으로 관리됩니다 [10, 11]. 타이핑이나 클릭처럼 사용자가 즉각적인 반응을 기대하는 긴급한 업데이트(Sync Lane)는 최우선으로 즉시 처리되며, 스크롤(InputContinuous Lane), 네트워크 응답(Default Lane), 백그라운드 렌더링(Idle Lane) 등은 각각 낮은 우선순위를 부여받아 스케줄링됩니다 [12-14]. 이 과정에서 렌더링 단계(Render phase)는 중단 가능(Interruptible)하므로, 더 높은 우선순위의 작업이 도착하면 기존의 렌더링 작업을 일시 중지, 폐기 또는 재시작할 수 있습니다 [15, 16].
|
||||
* **Concurrent Hooks 활용 (`useTransition`, `useDeferredValue`)**
|
||||
React 18 및 19에서는 개발자가 동시성 렌더링을 직접 제어할 수 있는 훅을 제공합니다 [17, 18]. **`useTransition`**은 개발자가 상태 업데이트를 직접 긴급하지 않은 것(low-priority)으로 지정하여, 수천 개의 데이터 필터링 연산이 백그라운드에서 도는 중에도 사용자의 타이핑 입력이 즉시 반영되도록 돕습니다 [17, 19, 20]. **`useDeferredValue`**는 외부에서 전달받는 값 자체의 렌더링을 지연시켜, 새로운 결과가 준비될 때까지 UI가 동결되는 것을 막고 이전 결과를 표시하게 해줍니다 [19, 21].
|
||||
* **성능 최적화 메커니즘 (체감 성능 향상)**
|
||||
Concurrent Rendering의 핵심은 코드의 실제 연산 속도를 물리적으로 가속하는 것이 아닙니다 [3]. 무거운 연산이 즉각적인 사용자 피드백을 방해하지 않도록 처리 순서를 최적화하여 앱이 **"더 빠르게 느껴지게(feel faster)"** 만드는 데 목적이 있습니다 [3]. 이러한 비차단형(Non-Blocking) 렌더링 방식은 사용자의 입력이 다음 화면 페인트로 이어지는 속도를 측정하는 핵심 웹 지표인 **INP(Interaction to Next Paint)**를 향상시키는 데 직접적으로 기여합니다 [21, 22].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** `[[Fiber Architecture]]`, `[[Time Slicing]]`, `[[Lane Model]]`, `[[useTransition]]`, `[[useDeferredValue]]`
|
||||
- **Projects/Contexts:** `[[React 18 & 19 Performance Optimization]]`
|
||||
- **Contradictions/Notes:** 소스에 따르면 `useTransition` 및 `useDeferredValue`와 같은 동시성 훅은 코드 자체의 속도를 높여주지는 않지만, 무거운 연산이 사용자 피드백을 방해하지 않도록 스케줄링하여 앱의 "체감 성능"을 개선하는 방식으로 작동한다는 점을 명확히 하고 있습니다 [3].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,20 @@
|
||||
# [[Critical Rendering Path]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Critical Rendering Path (CRP)는 브라우저가 HTML, CSS, JavaScript를 수신하여 화면의 픽셀로 변환하기 위해 거치는 일련의 단계적 과정을 의미합니다[1]. 이 과정은 DOM 트리 및 CSSOM 트리 구축, Render Tree 합성, Layout(Reflow), 그리고 Paint(Repaint) 및 Compositing 단계로 진행됩니다[1, 2]. CRP를 이해하고 최적화하는 것은 렌더링 차단 요소를 줄이고 불필요한 Reflow 및 Repaint를 최소화하여 빠른 초기 렌더링과 매끄러운 사용자 상호작용을 보장하는 프론트엔드 성능 엔지니어링의 핵심입니다[3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **DOM (Document Object Model) 구축:** 브라우저는 서버로부터 HTML 데이터를 점진적으로 파싱하여 DOM 트리를 구축합니다[2, 5]. 수신된 바이트는 토큰 및 노드로 변환되어 계층 구조를 형성하며, 노드의 수가 많을수록 이후 렌더링 경로의 연산 시간이 길어집니다[2, 5, 6].
|
||||
* **CSSOM (CSS Object Model) 구축:** DOM과 달리 CSSOM 구축은 점진적으로 이루어지지 않으며, 파싱이 완료될 때까지 렌더링을 차단(Render-blocking)합니다[6-8]. 이는 스타일이 뒤늦게 덮어씌워지면서 스타일이 적용되지 않은 콘텐츠가 화면에 번쩍이는 현상(FOUC)을 방지하기 위함입니다[6, 7].
|
||||
* **Render Tree 합성:** DOM과 CSSOM이 완성되면, 브라우저는 이 둘을 결합해 화면에 실제로 그려지는 가시적 노드(Visible nodes)만 포함하는 Render Tree를 만듭니다[9-11]. `<script>`, `<meta>` 요소나 `display: none` 스타일이 적용된 노드는 렌더 트리에서 완전히 제외되지만, 레이아웃 공간을 차지하는 `visibility: hidden` 요소는 포함됩니다[9-12].
|
||||
* **Layout (Reflow):** Render Tree를 기반으로 뷰포트 크기와 박스 모델에 맞춰 각 요소의 정확한 기하학적 위치와 크기를 계산하는 단계입니다[13-15]. 창 크기가 변하거나, DOM 요소의 추가/제거, 혹은 너비나 여백 등 레이아웃에 영향을 주는 속성이 변경될 경우 Reflow가 발생하며 이는 매우 큰 연산 비용을 수반합니다[16-19].
|
||||
* **Paint (Repaint) 및 Compositing:** Layout 계산이 끝나면 각 요소를 픽셀로 화면에 그리는 Paint(또는 Rasterizing) 과정이 진행됩니다[20-23]. 레이아웃 변화 없이 배경색 등 시각적 속성만 변할 때는 Repaint만 촉발됩니다[18, 20, 24]. 이후 서로 다른 레이어들을 하나의 화면으로 합치는 Compositing 단계를 거치며, 특정 효과(예: transform)는 GPU로 오프로드하여 성능을 최적화할 수 있습니다[20, 25].
|
||||
* **React 도입과의 연관성:** 전통적으로 브라우저의 DOM을 직접 조작하는 것은 필연적으로 비용이 큰 Reflow와 Repaint 과정을 연쇄적으로 유발하여 속도 저하를 일으킵니다[26]. React는 이 한계를 극복하기 위해 메모리에 경량화된 Virtual DOM을 구축하고, 상태 변경 시 휴리스틱 Diffing 알고리즘(Reconciliation)을 통해 변경된 최소한의 노드만 실제 DOM에 반영하여 렌더링 경로의 비효율을 크게 줄입니다[3, 26, 27].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[브라우저 렌더링 과정 (HTML → CSSOM → Render Tree)]], [[Reflow / Repaint 최소화 방법]], [[DOM vs Virtual DOM]]
|
||||
- **Projects/Contexts:** [[렌더링 최적화 개념 설명 자료]], [[“React가 빠른 이유”]]
|
||||
- **Contradictions/Notes:** CSS 선택자(Selector)의 복잡도는 파싱 속도에 영향을 주지만, 최신 브라우저 엔진은 매우 빠르기 때문에 선택자 구체성을 최적화해서 얻는 성능적 이득은 마이크로초 단위에 불과합니다. 따라서 실질적인 최적화를 위해서는 선택자 구조 개선보다는 불필요한 렌더링 차단 리소스 크기를 줄이거나 로딩 순서를 제어하는 것이 성능 개선(CRP 최적화)에 훨씬 효과적입니다[28, 29].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,25 @@
|
||||
# [[React 18 동시성 렌더링 (Concurrent Rendering)]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React 18 동시성 렌더링(Concurrent Rendering)은 React가 렌더링 작업을 여러 단위로 나누고, 작업의 우선순위를 평가하여 브라우저의 메인 스레드를 차단하지 않고 UI를 부드럽게 업데이트할 수 있도록 설계된 아키텍처적 패러다임입니다 [1-3]. 이는 Fiber 아키텍처와 스케줄러의 타임 슬라이싱(Time-Slicing) 및 우선순위 레인(Lanes) 시스템을 기반으로 동작합니다 [2, 4, 5]. 이를 통해 개발자는 무거운 데이터 연산 중에도 사용자 입력과 같은 긴급한 상호작용을 즉각적으로 처리하여 애플리케이션의 체감 응답성을 크게 향상시킬 수 있습니다 [6-8].
|
||||
|
||||
## 📖 Core Content
|
||||
* **동기식 블로킹의 한계 극복 (Fiber 아키텍처 도입):**
|
||||
과거의 React는 한 번 렌더링이 시작되면 전체 컴포넌트 트리가 처리될 때까지 멈출 수 없어, 무거운 작업 시 메인 스레드가 차단되고 UI가 응답하지 않는 문제가 있었습니다 [4]. 이를 해결하기 위해 설계된 Fiber 아키텍처는 렌더링 작업을 'Fiber 노드'라는 단위로 잘게 분할하여, 스케줄러가 여러 프레임에 걸쳐 작업을 점진적으로 분산 처리할 수 있도록 지원합니다 [2].
|
||||
|
||||
* **타임 슬라이싱(Time-Slicing)과 렌더링 단계의 분리:**
|
||||
동시성 렌더링은 타임 슬라이싱을 사용하여 렌더링 작업을 나누고, 필요 시 브라우저에 제어권을 양보(yield)합니다 [4, 9]. 렌더링은 두 가지 단계로 나뉘는데, 변경 사항의 목록을 계산하는 '렌더(Render) 단계'는 언제든 일시 중지, 재개 또는 폐기될 수 있습니다 [10, 11]. 반면 실제 DOM에 변경 사항을 적용하는 '커밋(Commit) 단계'는 동기적이고 중단할 수 없는 형태로 한 번에 실행됩니다 [11-13].
|
||||
|
||||
* **우선순위 기반 관리 (Lane 모델):**
|
||||
React는 비트마스크 시스템을 활용한 'Lanes'라는 모델을 통해 작업의 우선순위를 관리합니다 [14, 15]. 클릭이나 타이핑 같은 긴급한 사용자 입력은 'Sync Lane'으로 분류되어 즉시 처리되며, 화면 외부 렌더링이나 무거운 데이터 필터링은 'Idle Lane' 등의 낮은 우선순위로 분류됩니다 [14, 16]. 이 모델을 통해 진행 중이던 낮은 우선순위 작업은 더 중요한 업데이트가 도착하면 중단되거나 우선순위가 조정될 수 있습니다 [17].
|
||||
|
||||
* **동시성 제어를 위한 API (`useTransition`, `useDeferredValue` 등):**
|
||||
개발자는 React에서 제공하는 훅을 활용해 긴급하지 않은 업데이트를 백그라운드로 지연시킬 수 있습니다 [6]. `startTransition`이나 `useTransition`은 특정 상태 업데이트의 우선순위를 낮추어 사용자 입력 같은 긴급한 작업이 먼저 처리되게 합니다 [6, 18]. 상태 업데이트 코드를 직접 제어할 수 없는 경우(예: props로 값을 전달받는 경우)에는 `useDeferredValue`를 사용하여 렌더링 연산을 지연시킴으로써 UI가 멈추는 것을 방지할 수 있습니다 [19, 20]. 긴급히 동기적으로 업데이트를 강제해야 할 때에는 `flushSync`를 사용할 수 있습니다 [21].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[React Fiber]], [[Time-Slicing]], [[Lanes Model]], [[Automatic Batching]], [[Virtual DOM]]
|
||||
- **Projects/Contexts:** [[무거운 데이터 리스트 필터링 구현]], [[타이핑에 즉각 반응해야 하는 검색창 (Search-as-you-type)]]
|
||||
- **Contradictions/Notes:** 소스 [6]에서는 `useTransition` 및 `useDeferredValue` 등 동시성 제어 훅을 "React 19의 기능"으로 설명하고 있으나, 소스 [21]와 [18]에서는 `startTransition`과 `flushSync`를 통한 렌더링 제어가 "React 18에 도입되었다"고 서술합니다. 이는 React 18에서 도입된 동시성 렌더링 기능이 후속 버전에서도 계속 확장 및 핵심 성능 최적화 패턴으로 사용되고 있음을 시사합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,23 @@
|
||||
# [[React Performance Optimization]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React 성능 최적화는 브라우저의 렌더링 과정에서 발생하는 레이아웃 계산과 페인팅 비용을 최소화하고, 효과적인 렌더링 전략을 통해 애플리케이션의 반응성을 극대화하는 과정입니다 [1, 2]. 이를 위해 React는 가상 DOM(Virtual DOM)과 휴리스틱 Diffing 알고리즘, 그리고 Fiber 아키텍처를 도입하여 UI 업데이트를 효율적으로 관리합니다 [3-5]. 궁극적으로 개발자는 CSR, SSR, SSG와 같은 렌더링 방식을 서비스의 특성에 맞게 선택하고, 컴포넌트 기반 설계와 최적화 도구를 활용해 사용자 경험을 획기적으로 향상시킬 수 있습니다 [6, 7].
|
||||
|
||||
## 📖 Core Content
|
||||
* **브라우저 렌더링 과정 및 Reflow/Repaint 최소화:** 브라우저는 HTML과 CSS를 파싱하여 DOM과 CSSOM을 각각 생성하고, 이를 결합하여 화면에 표시될 요소만 담은 Render Tree를 구축합니다 [8-11]. 이후 각 요소의 정확한 크기와 위치를 계산하는 Layout(Reflow) 단계와 화면에 픽셀로 변환해 그리는 Paint(Repaint) 단계를 거칩니다 [12-15]. 직접적인 DOM 조작은 연산 비용이 높은 Reflow와 Repaint를 반복적으로 유발해 애플리케이션 성능을 저하시킵니다 [1, 16, 17]. 이를 방지하기 위해 CSS transform 속성을 활용하거나 불필요한 DOM 깊이를 줄이고, 리스트 렌더링 시 가상화 기법을 적용하는 최적화 방법이 권장됩니다 [13, 18-20].
|
||||
* **DOM vs Virtual DOM과 React의 속도 향상 메커니즘:** React는 실제 DOM을 직접 수정하는 대신, 메모리 내에 가벼운 객체 형태인 Virtual DOM을 유지합니다 [1, 5, 21, 22]. 상태가 변경되면 새로운 Virtual DOM을 만들고, 휴리스틱 기반의 O(n) Diffing 알고리즘을 통해 이전 트리와 비교(Reconciliation)합니다 [3, 5, 23]. 이 알고리즘은 요소의 타입과 Key 속성을 바탕으로 변경된 최소한의 노드만 식별한 뒤 실제 DOM에 일괄 적용하므로, 불필요한 Reflow를 막고 렌더링 성능을 크게 높입니다 [3, 24, 25].
|
||||
* **React 엔진 최적화 (Fiber 아키텍처 및 최근 기능):** React 16부터 도입된 Fiber 아키텍처는 렌더링 작업을 중단 및 재개 가능한 작은 '작업 단위'로 나누고, 우선순위(Lane 모델)에 따라 처리하는 동시성 렌더링(Concurrent Rendering)을 지원합니다 [4, 26-30]. 또한 React 18에 도입된 자동 일괄 처리(Automatic Batching)는 Promise, setTimeout 등의 비동기 작업 내 여러 상태 업데이트를 단일 리렌더링으로 묶어 효율성을 극대화합니다 [31-34]. 최근 도입된 React Compiler는 빌드 단계에서 구문 트리를 분석하여 수동 처리 없이 자동으로 메모이제이션을 삽입해 개발자의 성능 최적화 부담을 줄여줍니다 [35-38].
|
||||
* **CSR vs SSR vs SSG 전략적 렌더링:**
|
||||
* **CSR (Client-Side Rendering):** 브라우저가 빈 HTML과 JavaScript를 다운로드해 UI를 구성하며, 초기 로딩과 SEO에는 불리하지만 이후 빠르고 매끄러운 상호작용을 제공하여 단일 페이지 애플리케이션(SPA)에 적합합니다 [39-42].
|
||||
* **SSR (Server-Side Rendering):** 서버에서 완전한 HTML을 미리 생성하여 브라우저에 전달하므로 초기 콘텐츠 렌더링(FCP)이 빠르고 SEO에 매우 유리합니다 [43-46].
|
||||
* **SSG (Static Site Generation):** 빌드 시점에 모든 HTML을 미리 렌더링하여 CDN을 통해 즉시 제공하므로 가장 빠르지만, 실시간 데이터 반영이 어렵습니다 [47-50].
|
||||
* **React Server Components (RSC):** 오직 서버에서만 실행되어 클라이언트에 JavaScript 번들을 전혀 전송하지 않는 컴포넌트 구조로, 클라이언트 번들 크기를 대폭 줄이고 서버 리소스에 직접 접근할 수 있습니다 [51-54].
|
||||
* **컴포넌트 기반 아키텍처 (CBA):** React의 핵심 설계 원칙으로, 애플리케이션을 독립적이고 캡슐화된 재사용 가능한 컴포넌트 단위로 나눕니다 [55-58]. 이는 시스템의 복잡성을 낮추고, 병렬 개발을 가능하게 하며, 특정 컴포넌트의 렌더링 주기만을 독립적으로 관리 및 최적화할 수 있도록 지원합니다 [59-64].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Critical Rendering Path]], [[Virtual DOM]], [[React Fiber Architecture]], [[React Compiler]], [[Hydration]]
|
||||
- **Projects/Contexts:** [[SPA (Single Page Application)]], [[Next.js]]
|
||||
- **Contradictions/Notes:** SSR은 검색 엔진 최적화(SEO) 및 빠른 초기 콘텐츠 렌더링(FCP) 측면에서 유리하지만 [43, 65], 사용자가 시각적으로 완성된 페이지를 보더라도 클라이언트가 JavaScript 번들을 다운로드하고 실행하는 Hydration(수화) 과정이 완료되기 전까지는 상호작용이 불가능하므로, TTI(Time to Interactive) 지표에서는 CSR보다 수치가 낮게 나타나는 렌더링 병목 현상이 존재합니다 [66-69].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,22 @@
|
||||
# [[Server-Side Rendering (SSR)]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Server-Side Rendering (SSR)은 사용자의 요청이 있을 때마다 서버 측에서 웹 페이지의 전체 HTML을 렌더링하여 클라이언트 브라우저로 전송하는 웹 렌더링 방식입니다 [1-3]. 브라우저는 완성된 HTML을 받아 즉시 화면에 표시하며, 이후 JavaScript를 다운로드하여 페이지를 상호작용 가능하게 만드는 하이드레이션(Hydration) 과정을 거치게 됩니다 [1, 4-6]. 이 방식은 검색 엔진 최적화(SEO)와 초기 화면 표시에 매우 유리하지만, 서버 부하 증가와 상호작용 지연(TTI)이라는 성능적 트레이드오프를 동반합니다 [1, 7-9].
|
||||
|
||||
## 📖 Core Content
|
||||
* **작동 원리와 하이드레이션 (Hydration):**
|
||||
SSR 환경에서 사용자가 페이지를 요청하면, 서버는 라우팅 로직을 처리하고 데이터베이스나 API로부터 데이터를 가져와 완성된 HTML 문서를 생성하여 응답합니다 [2, 6]. 브라우저는 이 HTML을 즉시 화면에 렌더링하므로 사용자는 콘텐츠를 바로 볼 수 있지만, 이 시점의 페이지는 상호작용할 수 없는 정적인 상태입니다 [6]. 이후 브라우저가 JavaScript 번들을 다운로드하고 실행하면, React와 같은 프레임워크가 가상 DOM(Virtual DOM)을 렌더링된 HTML 구조에 매핑하여 이벤트 리스너를 연결하고 상태를 동기화합니다. 이 과정을 '하이드레이션'이라고 부릅니다 [1, 5, 10].
|
||||
|
||||
* **성능 및 사용자 경험적 이점:**
|
||||
SSR의 가장 큰 장점 중 하나는 탁월한 검색 엔진 최적화(SEO)입니다. 검색 엔진 크롤러가 JavaScript 실행을 기다리거나 빈 화면을 볼 필요 없이 완전히 렌더링된 HTML 콘텐츠에 즉시 접근하여 색인을 생성할 수 있기 때문입니다 [1, 11, 12]. 또한 첫 콘텐츠 풀 페인트(FCP) 성능이 우수하여 사용자가 빈 화면 대신 즉각적으로 시각적 요소를 볼 수 있으며, 이는 대역폭이 제한된 모바일이나 느린 3G 네트워크 환경에서 사용자 경험을 크게 개선합니다 [9, 11, 12]. 매 요청마다 서버에서 렌더링이 이루어지므로, 뉴스 사이트나 전자상거래의 제품 페이지처럼 항상 최신의 동적 데이터를 제공해야 하는 환경에 이상적입니다 [13-15].
|
||||
|
||||
* **인프라 한계 및 성능 트레이드오프:**
|
||||
모든 사용자 상호작용이나 페이지 요청 시 서버가 렌더링 연산을 수행해야 하므로 트래픽 급증 시 서버 컴퓨팅 부하가 급격히 커지며, 이는 호스팅 인프라 비용 증가와 복잡성 확대로 이어집니다 [7, 8, 16]. 서버 측에서의 HTML 생성 작업으로 인해 첫 바이트 도달 시간(TTFB)이 약 100~300ms가량 늘어날 수 있습니다 [9, 17]. 무엇보다 사용자가 가장 불편함을 느낄 수 있는 단점은 '상호작용 지연'입니다. 화면의 시각적 요소는 빠르게 로드되지만, JavaScript가 다운로드되고 하이드레이션이 완료될 때까지(기기에 따라 2~5초가량 소요될 수 있음) 페이지가 클릭이나 입력 등의 상호작용에 반응하지 않는 상호작용 시간(TTI) 저하 현상이 발생합니다 [1, 9, 10, 16].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Client-Side Rendering (CSR)]], [[Static Site Generation (SSG)]], [[Hydration]], [[Virtual DOM]], [[Search Engine Optimization (SEO)]], [[First Contentful Paint (FCP)]], [[Time to Interactive (TTI)]]
|
||||
- **Projects/Contexts:** [[Next.js]], [[React Server Components (RSC)]], [[E-commerce Platforms]]
|
||||
- **Contradictions/Notes:** 소스 문헌들은 공통적으로 SSR이 시각적 로드(FCP)를 빠르게 만들어 사용자에게 즉각적인 응답을 제공하지만, 하이드레이션 병목 현상으로 인해 실질적인 상호작용(TTI)은 CSR보다 지연된다는 성능적 역설을 주의해야 한다고 지적합니다 [9, 18].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,18 @@
|
||||
# [[Time to Interactive (TTI)]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Time to Interactive (TTI)는 사용자의 초기 페이지 요청(DNS 조회 및 TCP 연결) 시점부터 웹 페이지가 50ms 이내에 사용자의 상호작용에 응답할 수 있는 상태가 되기까지 걸리는 시간을 측정하는 성능 지표입니다 [1]. 시각적인 콘텐츠가 화면에 표시되는 것을 넘어, 필요한 JavaScript가 모두 다운로드되고 실행되어 버튼 클릭 등의 입력에 즉각적으로 반응할 수 있는 시점을 의미합니다 [1, 2]. 특히 서버 사이드 렌더링(SSR) 환경에서는 화면이 먼저 보이지만 JavaScript가 연결(Hydration)될 때까지 상호작용이 불가능한 지연 현상이 발생하므로 TTI 최적화가 매우 중요합니다 [2, 3].
|
||||
|
||||
## 📖 Core Content
|
||||
* **TTI의 정의와 메인 스레드의 역할:** TTI는 페이지의 First Contentful Paint (FCP) 이후, 사용자의 입력(스크롤, 터치 등)에 50ms 이내로 응답할 수 있게 되는 시점을 측정합니다 [1]. 브라우저의 메인 스레드가 JavaScript를 파싱, 컴파일, 실행하느라 점유되어 있다면, 페이지는 시각적으로 완성되었더라도 상호작용할 수 없는 상태가 됩니다 [1, 4].
|
||||
* **SSR(Server-Side Rendering)과 Hydration에 따른 TTI 지연:** SSR은 서버에서 미리 렌더링된 HTML을 제공하므로 초기 콘텐츠 표시(FCP)가 빠르지만, TTI 측면에서는 불리할 수 있습니다 [2, 3, 5]. 화면의 요소가 클릭 가능해 보이더라도, JavaScript 번들이 다운로드되고 정적 HTML에 이벤트 리스너와 상태를 연결하는 'Hydration' 과정이 완료될 때까지는 반응하지 않기 때문입니다 [2, 3, 6]. JavaScript 번들 크기가 크거나 기기 성능이 낮을 경우 이 과정에 2~5초가 소요될 수 있으며, 이는 사용자에게 답답한 경험을 제공할 수 있습니다 [2, 5-7].
|
||||
* **CSR(Client-Side Rendering)과의 비교:** CSR의 경우, 초기에 브라우저가 빈 HTML 셸을 받고 JavaScript를 다운로드해야 하므로 초기 화면 표시는 느릴 수 있습니다 [8, 9]. 하지만 JavaScript 로드 후 클라이언트 측에서 렌더링이 완료되면 즉각적인 상호작용이 가능해지므로 초기 로드 이후의 TTI는 향상되는 특징을 가집니다 [10, 11].
|
||||
* **성능 최적화 관점:** TTI를 개선하기 위해서는 메인 스레드의 점유 시간을 최소화해야 합니다 [4]. 이를 위해 점진적/선택적 Hydration 기법을 적용하여 중요한 상호작용 요소를 먼저 로드하거나 [12, 13], React Server Components(RSC)를 활용하여 브라우저로 전송되는 JavaScript 번들 크기 자체를 줄임으로써 Hydration에 소요되는 비용을 원천적으로 제거할 수 있습니다 [14, 15].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Hydration]], [[Server-Side Rendering (SSR)]], [[Client-Side Rendering (CSR)]], [[First Contentful Paint (FCP)]], [[메인 스레드 (Main Thread)]]
|
||||
- **Projects/Contexts:** [[렌더링 최적화 개념 설명 자료]], [[React가 빠른 이유]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 SSR과 CSR은 뚜렷한 트레이드오프를 가집니다. SSR은 FCP(초기 콘텐츠 표시)가 빠르지만 Hydration 오버헤드로 인해 TTI가 느려지는 반면, CSR은 초기 로드 속도는 느리지만 로드 이후의 상호작용(TTI 향상)은 더 부드럽고 즉각적이라는 특징이 있습니다 [11, 16-18].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
@@ -0,0 +1,26 @@
|
||||
# [[Total Blocking Time (TBT)]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Total Blocking Time(TBT)는 브라우저의 메인 스레드가 자바스크립트 실행 등으로 인해 차단되어 사용자 상호작용(입력, 클릭 등)을 처리할 수 없는 시간을 측정하는 핵심 성능 지표입니다 [1, 2]. 이 지표는 Lighthouse 성능 점수의 30%를 차지하며, 사용자 경험과 SEO 순위에 직접적인 영향을 미칩니다 [1]. 특히 React 환경에서는 서버 사이드 렌더링(SSR) 이후 전체 페이지를 한 번에 하이드레이션(Hydration)할 때 TBT가 급증하여 심각한 성능 저하와 입력 지연을 유발할 수 있습니다 [1, 3].
|
||||
|
||||
## 📖 Core Content
|
||||
|
||||
* **하이드레이션(Hydration)과 TBT의 상관관계**
|
||||
* React는 기본적으로 사용자 화면에 즉시 보이지 않는 컴포넌트까지 포함하여 전체 페이지를 동시에 하이드레이션합니다 [1].
|
||||
* 이러한 접근 방식은 불필요한 자바스크립트 실행을 유발하여 브라우저의 메인 스레드를 차단(Block)하게 되고, 결과적으로 긴 TBT와 Lighthouse 점수 하락으로 이어집니다 [1, 3].
|
||||
* TBT가 길어지면 사용자가 페이지 로드 직후 버튼을 클릭해도 즉각적으로 반응하지 않는 심각한 입력 지연(Input lag)을 경험하게 됩니다 [1, 4].
|
||||
* **중요 렌더링 경로(CRP)에서의 차단 시간**
|
||||
* TBT는 하이드레이션뿐만 아니라 브라우저의 초기 렌더링 과정과도 관련이 있습니다.
|
||||
* CSSOM을 구축하는 과정에서 CSS 선택자(Selector)의 복잡성은 렌더링 속도에 영향을 미치므로, 선택자의 명시성(specificity)을 최적화하고 CSS를 최소화(minify)하는 것은 중요 렌더링 경로(CRP)의 총 차단 시간을 줄이는 기본적인 최적화 기술입니다 [5].
|
||||
* **TBT를 최소화하는 렌더링 최적화 전략**
|
||||
* **선택적 하이드레이션 및 점진적 로딩 (Selective Hydration & Progressive Loading):** 모든 것을 한 번에 하이드레이션하는 대신, 스크롤 상단(above-the-fold) 콘텐츠를 우선 처리하고 덜 중요한 컴포넌트는 지연시킵니다 [6]. Next.js의 동적 가져오기(`next/dynamic`)를 활용하면 자바스크립트 실행을 분산시켜 메인 스레드 차단을 막고 TBT를 크게 줄일 수 있습니다 [6, 7].
|
||||
* **가시성 기반 지연 하이드레이션 (Lazy Hydration Based on Visibility):** 화면 하단 콘텐츠가 뷰포트에 들어올 때만 하이드레이션되도록 지연시키는 방법(예: IntersectionObserver 활용)을 통해 특정 애플리케이션에서 TBT를 최대 40%까지 단축할 수 있습니다 [7, 8].
|
||||
* **React 서버 컴포넌트 (React Server Components) 활용:** App Router와 같은 환경에서 서버 컴포넌트를 사용하면 클라이언트 측에서 전혀 자바스크립트가 실행되지 않으므로 하이드레이션 과정 자체가 필요 없어져 TBT와 자바스크립트 페이로드를 획기적으로 줄일 수 있습니다 [8].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Hydration]], [[Critical Rendering Path (CRP)]], [[Server-Side Rendering (SSR)]], [[React Server Components]]
|
||||
- **Projects/Contexts:** [[Next.js]], [[Lighthouse]]
|
||||
- **Contradictions/Notes:** 소스의 내용 간 상충되는 부분은 없으며, 모든 소스가 자바스크립트의 과도한 실행이 메인 스레드를 차단하여 TBT를 악화시킨다는 점에 동의합니다. 또한, 이를 방지하기 위해 렌더링 최적화(점진적 하이드레이션, 서버 컴포넌트 사용 등)가 필수적임을 강조합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# Skybound Nova Burst Icon and Effect Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix for skill-specific visual mismatch
|
||||
|
||||
## 1. Screenshot Issue
|
||||
|
||||
`Nova Burst` looked like a lemon-shaped projectile icon.
|
||||
|
||||
This did not match the actual skill behavior.
|
||||
|
||||
## 2. Skill Meaning
|
||||
|
||||
`Nova Burst` is not a missile, crystal shard, or thrown projectile.
|
||||
|
||||
Actual gameplay behavior:
|
||||
|
||||
- automatic radial AoE shockwave
|
||||
- triggers around the player
|
||||
- damages enemies inside the radius
|
||||
- knocks enemies outward
|
||||
- cooldown-based burst every few seconds
|
||||
- evolves into `Nova Guardian`, which adds stronger golden guardian behavior
|
||||
|
||||
## 3. Art Direction Correction
|
||||
|
||||
The icon should communicate:
|
||||
|
||||
- central arcane core
|
||||
- circular shockwave expansion
|
||||
- radial force
|
||||
- rune-like magitech energy
|
||||
- area control around the player
|
||||
|
||||
It should not communicate:
|
||||
|
||||
- lemon
|
||||
- fruit
|
||||
- single projectile
|
||||
- gem pickup
|
||||
- missile tip
|
||||
|
||||
## 4. Fixes Applied
|
||||
|
||||
The procedural generator now creates `Nova Burst.png` with a dedicated `nova` icon shape.
|
||||
|
||||
New visual structure:
|
||||
|
||||
- cyan circular shockwave rings
|
||||
- central navy magitech core
|
||||
- arcane core light
|
||||
- radial spokes showing outward force
|
||||
- subtle purple secondary energy ring
|
||||
|
||||
The in-game Nova Burst renderer was also adjusted:
|
||||
|
||||
- center sprite is smaller and treated as a rune core
|
||||
- expanding shockwave ring is now the main visual read
|
||||
- added translucent pressure disk
|
||||
- added segmented rune ring
|
||||
- kept Guardian variant as gold/orange
|
||||
|
||||
## 5. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/scripts/generate_magitech_assets.py`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/public/sprites/missiles/Nova Burst.png`
|
||||
|
||||
## 6. Verification
|
||||
|
||||
Asset generation completed successfully.
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static asset warning remains non-blocking.
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# Skybound Particle and Supply Readability Fix
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw follow-up fix from gameplay screenshot review
|
||||
|
||||
## 1. Screenshot Issues
|
||||
|
||||
The reviewed screenshot exposed two readability problems.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- Mint/cyan square particles were scattered across the floor and looked like items even though they could not be collected.
|
||||
- The supply crate asset looked good, but it was not clear whether it was a player pickup or an enemy projectile/debris object.
|
||||
|
||||
## 2. Cause
|
||||
|
||||
### Mint Floor Squares
|
||||
|
||||
The mint squares were runtime particles from `EffectSystem`.
|
||||
|
||||
They were rendered in `GameRenderer.renderEffects()` using `fillRect()`, so every spark appeared as a small collectible-looking square.
|
||||
|
||||
These particles can come from combat hits, skill effects, EMP interactions, exp pickup feedback, or other short-lived feedback systems.
|
||||
|
||||
### Supply Ambiguity
|
||||
|
||||
The supply crate sprite itself was readable as an object, but the gameplay affordance was weak.
|
||||
|
||||
It needed explicit pickup language:
|
||||
|
||||
- pickup color
|
||||
- capture ring
|
||||
- directional marker
|
||||
- short label
|
||||
|
||||
## 3. Fixes Applied
|
||||
|
||||
### Particle Shape
|
||||
|
||||
Runtime particles now render as small rotated diamond sparks instead of square floor blocks.
|
||||
|
||||
This keeps the magical spark feedback while reducing item confusion.
|
||||
|
||||
Normal shard fragments were also changed from square blocks to triangular fragments.
|
||||
|
||||
### Supply Pickup Readability
|
||||
|
||||
Supply drops now render with:
|
||||
|
||||
- mint-green dashed pickup ring
|
||||
- soft pickup fill
|
||||
- bobbing downward arrow
|
||||
- retained supply crate sprite
|
||||
- `PICK UP` label
|
||||
|
||||
This separates supply drops from enemy bullets, hazards, and cosmetic particles.
|
||||
|
||||
## 4. Changed Runtime Paths
|
||||
|
||||
Important changed path:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
|
||||
## 5. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skybound Survivor-Like Balance Curve Pass
|
||||
|
||||
**Date**: 2026-04-24
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw gameplay balance pass from user playtest feedback
|
||||
|
||||
## 1. Playtest Feedback
|
||||
|
||||
The game shell looked close to Survivor.io / Vampire Survivors, but the actual gameplay did not feel like that genre.
|
||||
|
||||
Reported issues:
|
||||
|
||||
- gameplay did not deliver enough horde-survival pressure
|
||||
- stage balance felt uneven
|
||||
- TAC Level Up pacing felt unbalanced
|
||||
- growth did not form a satisfying user-facing curve
|
||||
|
||||
## 2. Diagnosis
|
||||
|
||||
The previous balance leaned closer to a shmup / tactical shooter.
|
||||
|
||||
Main causes found in code:
|
||||
|
||||
- simultaneous enemy cap was too low for a horde-survival feel
|
||||
- procedural spawn did not fully use the timeline `spawnIntervalMult`
|
||||
- early EXP requirement was too high
|
||||
- EXP growth multiplier was too steep
|
||||
- stage difficulty scaled enemy/bullet stats too aggressively
|
||||
- stage scripted events were compressed too early in the timeline
|
||||
- TAC Level Up card offers were weighted but not structured, so the user could receive awkward choices
|
||||
- starter skill offers could omit key horde-survival archetypes
|
||||
|
||||
## 3. Target Curve
|
||||
|
||||
New target:
|
||||
|
||||
- first meaningful upgrade should arrive quickly
|
||||
- player should see more enemies on screen
|
||||
- enemies should be individually weaker
|
||||
- danger should come from density and positioning, not bullet stat spikes
|
||||
- level-up choices should consistently support build formation
|
||||
- stage progression should rise smoothly rather than jump sharply
|
||||
|
||||
## 4. Applied Balance Changes
|
||||
|
||||
### EXP and Level-Up
|
||||
|
||||
Changes:
|
||||
|
||||
- initial required EXP lowered from `100` to `45`
|
||||
- normal enemy EXP increased from `5` to `7`
|
||||
- elite EXP increased from `25` to `32`
|
||||
- level-up EXP multiplier changed from steep `1.60 / 1.72 / 1.85` to smoother `1.24 / 1.30 / 1.36 / 1.42`
|
||||
|
||||
Expected result:
|
||||
|
||||
- early TAC Level Ups arrive faster
|
||||
- the player can form a build before the first spike
|
||||
- later progression still slows down without becoming a wall
|
||||
|
||||
### TAC Level Up Card Structure
|
||||
|
||||
The card generator now tries to offer:
|
||||
|
||||
- one owned skill upgrade
|
||||
- one synergy / spike-counter / EVO-supporting option
|
||||
- one flexible option
|
||||
|
||||
Expected result:
|
||||
|
||||
- fewer dead-choice screens
|
||||
- higher chance of completing coherent builds
|
||||
- less frustration from random-only card pools
|
||||
|
||||
### Starter Selection
|
||||
|
||||
Starter cards now come from three archetype buckets:
|
||||
|
||||
- primary damage
|
||||
- area / crowd control
|
||||
- utility / defense
|
||||
|
||||
Expected result:
|
||||
|
||||
- every run begins with a usable horde-survival foundation
|
||||
- the first choice feels strategic without becoming punishing
|
||||
|
||||
### Enemy Density and Spawning
|
||||
|
||||
Changes:
|
||||
|
||||
- hard enemy cap increased from `30` to `90`
|
||||
- timeline phase caps increased by stage and phase
|
||||
- procedural spawn interval now uses `spawnIntervalMult`
|
||||
- procedural spawns can arrive in small batches
|
||||
- formation spawns now occur more often
|
||||
- individual enemy HP and speed were reduced to support higher density
|
||||
- elite chance is now a gradual probability instead of flipping too hard by difficulty
|
||||
|
||||
Expected result:
|
||||
|
||||
- more screen-filling horde pressure
|
||||
- less empty movement time
|
||||
- more satisfying weapon-clearing moments
|
||||
|
||||
### Stage Curve
|
||||
|
||||
Changes:
|
||||
|
||||
- stage duration curve changed from `120 + stage * 30s` to `150 + stage * 18s`
|
||||
- stage difficulty scaling reduced from steep `+0.4 per stage` to smoother `+0.18 per stage`
|
||||
- phase difficulty multipliers were lowered
|
||||
- phase enemy caps were increased
|
||||
- scripted wave events are distributed across the stage instead of firing too early
|
||||
|
||||
Expected result:
|
||||
|
||||
- stages feel less spiky and more readable
|
||||
- difficulty rises through density and phase rhythm
|
||||
- player has time to grow before major pressure events
|
||||
|
||||
### Enemy Bullet and Damage Pressure
|
||||
|
||||
Changes:
|
||||
|
||||
- enemy bullet speed curves were reduced
|
||||
- damage curves were reduced
|
||||
- bullet caps were reduced
|
||||
- global enemy bullet speed multiplier reduced
|
||||
- enemy projectile damage multipliers reduced
|
||||
|
||||
Expected result:
|
||||
|
||||
- gameplay moves away from bullet-hell punishment
|
||||
- movement pressure still exists, but horde positioning becomes the main focus
|
||||
|
||||
### Weapon Rhythm
|
||||
|
||||
Several weapon cooldowns were shortened so early picks feel active sooner.
|
||||
|
||||
Nova Burst was also adjusted to trigger sooner and scale more clearly as an AoE crowd-control tool.
|
||||
|
||||
## 5. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/balance.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/CombatTimeline.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
|
||||
|
||||
## 6. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static path warning remains non-blocking.
|
||||
|
||||
## 7. Next Playtest Questions
|
||||
|
||||
Recommended next playtest checks:
|
||||
|
||||
- Does the first level-up happen within a satisfying time window?
|
||||
- Does the screen feel populated without becoming unreadable?
|
||||
- Do weapons feel like they clear hordes?
|
||||
- Do stage spikes feel earned rather than sudden?
|
||||
- Does TAC Level Up usually offer at least one desirable choice?
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# Skybound Core Gameplay Rebalance and Purpose Reset
|
||||
|
||||
**Date**: 2026-04-25
|
||||
**Project**: Skybound Protocol
|
||||
**Author**: Codex
|
||||
**Status**: Raw corrective gameplay pass after balance regression
|
||||
|
||||
## 1. User Playtest Feedback
|
||||
|
||||
The previous balance pass made the game worse.
|
||||
|
||||
Observed issues:
|
||||
|
||||
- TAC Level Up triggered repeatedly and too quickly.
|
||||
- Campaign and Blitz did not communicate a clear purpose.
|
||||
- It was unclear whether the player should dodge bullets, collect upgrades, survive waves, or simply idle.
|
||||
- Standing near the center could clear the stage with little interaction.
|
||||
- Skill choice did not feel strategic because almost any pickup worked.
|
||||
- The foundation felt like it had grown without a clear gameplay plan.
|
||||
|
||||
## 2. Diagnosis
|
||||
|
||||
The previous pass overcorrected toward reward frequency and enemy density.
|
||||
|
||||
Main problems:
|
||||
|
||||
- initial EXP requirement was too low
|
||||
- EXP gem values were too high
|
||||
- level-up carryover allowed too much momentum
|
||||
- no cooldown existed between TAC Level Up events
|
||||
- base magnet radius was too generous
|
||||
- base damage multiplier was too high
|
||||
- weapon cooldowns became too generous
|
||||
- enemy caps became too high for the current combat model
|
||||
- enemies were too weak for the amount of automatic player damage
|
||||
|
||||
The result was a reward flood without enough danger, movement, or tactical pressure.
|
||||
|
||||
## 3. New Gameplay Purpose
|
||||
|
||||
Skybound should not be a pure bullet hell and should not be an idle auto-clear game.
|
||||
|
||||
The intended player loop should be:
|
||||
|
||||
1. Survive incoming enemy formations and hazard pressure.
|
||||
2. Move deliberately to collect EXP gems and supply rewards.
|
||||
3. Choose upgrades that solve the current pressure pattern.
|
||||
4. Build toward synergies and evolutions.
|
||||
5. Enter boss or spike phases with a build that feels earned.
|
||||
|
||||
The main fun should come from:
|
||||
|
||||
- movement under pressure
|
||||
- risk-reward EXP collection
|
||||
- tactical skill choices
|
||||
- visible power growth
|
||||
- stage pressure that asks for different answers
|
||||
|
||||
The player should not be able to win reliably by standing still.
|
||||
|
||||
## 4. Corrective Fixes Applied
|
||||
|
||||
### TAC Level Up Flood Control
|
||||
|
||||
Applied:
|
||||
|
||||
- initial required EXP increased from `45` to `90`
|
||||
- normal enemy EXP reduced from `7` to `4`
|
||||
- elite EXP reduced from `32` to `20`
|
||||
- level-up multiplier increased to `1.42 / 1.48 / 1.55 / 1.62`
|
||||
- added a `360 frame` TAC Level Up lockout after each level-up
|
||||
- EXP carryover is capped to `35%` of the next requirement
|
||||
|
||||
Expected result:
|
||||
|
||||
- level-up moments become meaningful beats
|
||||
- no rapid-fire modal spam
|
||||
- players must keep playing between upgrades
|
||||
|
||||
### Movement Incentive
|
||||
|
||||
Applied:
|
||||
|
||||
- base magnet radius reduced from `180` to `90`
|
||||
- magnet passive now adds `35` per level instead of `60`
|
||||
|
||||
Expected result:
|
||||
|
||||
- EXP collection requires movement
|
||||
- standing still misses more progression
|
||||
- magnet becomes a strategic comfort/passive choice rather than free global collection
|
||||
|
||||
### Idle-Clear Reduction
|
||||
|
||||
Applied:
|
||||
|
||||
- base effective damage reduced from `1.5` to `1.0`
|
||||
- damage passive now provides growth from deliberate investment
|
||||
- several weapon cooldowns were pulled back from the previous overly generous pass
|
||||
- Nova Burst was returned closer to a periodic tactical tool rather than constant auto-clear
|
||||
|
||||
Expected result:
|
||||
|
||||
- early weapons no longer erase all pressure automatically
|
||||
- skill investment matters more
|
||||
- AoE tools help but do not replace positioning
|
||||
|
||||
### Enemy Pressure Recentered
|
||||
|
||||
Applied:
|
||||
|
||||
- hard enemy cap reduced from `90` to `56`
|
||||
- phase caps reduced from the previous overcorrection
|
||||
- enemy HP increased from the previous too-low values
|
||||
- enemies enter deeper into the playfield
|
||||
- enemy speed and bullet pressure were slightly restored
|
||||
- procedural spawn cadence reduced from the flood state
|
||||
|
||||
Expected result:
|
||||
|
||||
- fewer meaningless bodies
|
||||
- enemies apply actual positional pressure
|
||||
- player must dodge, reposition, and collect intentionally
|
||||
|
||||
## 5. Design Rule Going Forward
|
||||
|
||||
Future balance changes should follow this rule:
|
||||
|
||||
Do not increase rewards unless a matching risk or movement requirement exists.
|
||||
|
||||
Examples:
|
||||
|
||||
- faster level-up needs harder collection or less carryover
|
||||
- more enemies need weaker auto-clear or stronger enemy pathing
|
||||
- stronger skills need clearer spike counters or enemy behaviors
|
||||
- more pickups need better pickup affordance and danger around pickup zones
|
||||
|
||||
## 6. Changed Runtime Paths
|
||||
|
||||
Important changed paths:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/CombatTimeline.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/balance.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
|
||||
## 7. Verification
|
||||
|
||||
Production build completed successfully with:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The existing `/sprites/player.png` static asset warning remains non-blocking.
|
||||
|
||||
## 8. Next Necessary Design Work
|
||||
|
||||
This corrective patch stabilizes the worst problems, but the project still needs a stronger core design pass.
|
||||
|
||||
Recommended next work:
|
||||
|
||||
- define Campaign as objective-based stages with unique pressure patterns
|
||||
- define Blitz as score/survival mode with explicit risk-reward scoring
|
||||
- add clear stage objectives to HUD
|
||||
- add enemy archetypes that force movement differently
|
||||
- add pickup-risk zones so rewards are not free
|
||||
- review every skill for role identity: damage, crowd control, defense, mobility, economy
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# Skybound Player Airframe and 8 Stage Boss Continuity Rework
|
||||
|
||||
작성일: 2026-04-25 09:51 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- 사용자 기체가 엔진에서 그린 도형 조립처럼 보여 시각적 완성도가 낮아 보이는 문제를 개선한다.
|
||||
- Stage 1 클리어 후 Stage 2로 넘어가는 흐름이 결과 화면으로 끊겨 게임이 단절되는 문제를 개선한다.
|
||||
- Aero Fighters처럼 보스를 처치하고 같은 런 안에서 다음 스테이지로 자연스럽게 이어지는 구조를 만든다.
|
||||
- 총 8개 스테이지를 유지하고, 스테이지가 올라갈수록 난이도가 올라가도록 보스 HP, 파츠, 패턴을 재조정한다.
|
||||
- 각 스테이지 보스가 서로 다른 공격 패턴을 체감할 수 있도록 실행부를 보강한다.
|
||||
|
||||
## 확인한 문제
|
||||
|
||||
### 플레이어 기체 렌더링
|
||||
|
||||
- `GameRenderer.renderPlayer()`에서 플레이어 스프라이트 위에 랜덤 원형 엔진 글로우를 직접 그려서, 기체 뒤쪽이 매 프레임 흔들리는 임시 도형처럼 보였다.
|
||||
- `renderWeaponAttachments()`에서 일부 장착 무기를 `fillRect`, `strokeRect`, 랜덤 원형 플래시로 그려서 톤앤매너에 맞는 완성형 파츠가 아니라 디버그 박스처럼 보일 수 있었다.
|
||||
- 특히 Hyper Sonic Vulcan, Gatling fallback, Missile Pod fallback이 사용자 기체 실루엣과 잘 섞이지 않았다.
|
||||
|
||||
### 스테이지 전환
|
||||
|
||||
- 보스 처치 후 `STAGE_CLEAR`가 되고, 300프레임 뒤 `BOSS_ACTION NEXT_STAGE` 이벤트가 발생한다.
|
||||
- 기존 `useGameEngine`은 이 이벤트를 곧바로 `finishMission('CLEAR')`로 연결했다.
|
||||
- 그 결과 Standard 캠페인에서도 Stage 1 보스 처치 후 결과 화면으로 끊기고, 다음 스테이지는 별도 런처럼 느껴졌다.
|
||||
|
||||
### 보스 패턴
|
||||
|
||||
- `bossActions.ts`에는 Stage 1부터 Stage 8까지 액션 테이블이 있다.
|
||||
- 하지만 `BossSystem.executePattern()`은 일부 액션만 처리하고 있었기 때문에, 실제 전투에서는 많은 액션이 기본 단발 탄으로 떨어질 수 있었다.
|
||||
- `StageDirectorSystem.instantiateBoss()`의 보스 파츠 turretId가 `T-CORE`, `T-WING`, `T-HEAVY`처럼 실제 `TURRET_CATALOG`에 없는 값이라 파츠 포탑이 의도대로 발사되지 않을 수 있었다.
|
||||
- 기존 보스 HP는 Stage 2부터 `5000 * currentStage`로 급격히 올라가 캠페인 커브가 자연스럽지 않았다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### 플레이어 기체 완성도 개선
|
||||
|
||||
- 플레이어 엔진 글로우를 랜덤 원형에서 고정된 마기테크 추진 플룸으로 변경했다.
|
||||
- 스프라이트 크기를 72px에서 78px로 약간 키워 중심 기체의 존재감을 높였다.
|
||||
- `drawMagitechPod()` 헬퍼를 추가해 장착 무기를 작은 마기테크 포드 형태로 통일했다.
|
||||
- Vulcan, Gatling fallback, Missile Pod fallback을 박스 도형 대신 다크 블루 메탈 바디, 시안/옐로/핑크 액센트, 라운드 포드 실루엣으로 렌더링한다.
|
||||
- 장착 파츠의 랜덤 플래시를 줄이고 프레임 기반 pulse로 바꿔 덜 튀고 더 의도적으로 보이게 했다.
|
||||
|
||||
### 연속 캠페인 전환
|
||||
|
||||
- Standard 캠페인에서 Stage 1-7 보스 처치 후 `finishMission`을 호출하지 않고, 같은 엔진 런 안에서 다음 스테이지로 전환하도록 변경했다.
|
||||
- 전환 시 다음 작업을 수행한다.
|
||||
- `currentStage` 증가
|
||||
- `campaignStageIndex` 저장
|
||||
- `StageDirectorSystem.advanceToStage()`로 새 타임라인 로드
|
||||
- 활성 총알, 적, 파티클 풀 정리
|
||||
- 스포너 큐 초기화
|
||||
- 보스, 탄막, hazard, airdrop, exp gem, vortex 정리
|
||||
- `INTRO` 페이즈로 재시작
|
||||
- 체력 25% 회복과 120프레임 무적 부여
|
||||
- Stage 안내 텍스트와 HQ comms 출력
|
||||
- Stage 8 보스 처치 시에는 `GAME_COMPLETE`로 결과 화면에 진입한다.
|
||||
- Blitz 모드는 기존처럼 단일 전투 클리어로 유지한다.
|
||||
|
||||
### 8스테이지 보스 커브
|
||||
|
||||
- 보스 HP를 선형 폭증에서 완만한 곡선형 성장으로 변경했다.
|
||||
- Stage 1은 낮게 시작하고, Stage 8은 누적 성장과 보스 패턴 난이도를 고려해 높은 난이도를 갖도록 설계했다.
|
||||
- 보스 파츠 HP도 같은 stage curve를 사용해 코어, 날개, 포탑이 함께 성장한다.
|
||||
- 각 스테이지에 실제 `TURRET_CATALOG`에 존재하는 turretId loadout을 지정했다.
|
||||
|
||||
### 보스 패턴 실행 보강
|
||||
|
||||
- 다음 액션들이 실제 탄막/기믹으로 실행되도록 매핑했다.
|
||||
- `FAN_PART`, `DASH_PART`: 부채꼴 조준 사격
|
||||
- `SIDE_WAVE`: 좌우 측면 웨이브
|
||||
- `ZONE_BOMB`: 안전 구역 압박과 링 탄막
|
||||
- `WALL_WAVE`: 틈이 있는 벽 형태 탄막
|
||||
- `MISSILE_BARRAGE`, `HOMING_CHASE`: 유도성 탄막
|
||||
- `CROSS_CHASE`: 네 방향 교차 추격 탄
|
||||
- `SPIRAL_WEB`, `REVOLVING_FLAME`: 나선 탄막
|
||||
- `BURST_SPLITTER`: 분열형 부채 탄
|
||||
- `GEAR_STORM`: 고밀도 나선과 링 조합
|
||||
- `PRECISION_LOCK`, `SNIPE_GRID`, `LASER_AIM`, `LASER_SWEEP`: 크로스헤어 기반 고속 압박
|
||||
- `TELEPORT_STRIKE`: 보스 위치 변경 후 기습 사격
|
||||
- `GIMMICK_PULSE`, `CC_REVERSE`, `ZONE_COLLAPSE`: 중력장/페이즈존 기믹과 링 탄막
|
||||
- `ULTIMATE_SYMPHONY`: 기존 고난도 복합 패턴 유지
|
||||
|
||||
## 수정 파일
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/StageDirectorSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/BossSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/EntityManager.ts`
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- Vite 경고: `/sprites/player.png referenced in /sprites/player.png didn't resolve at build time`
|
||||
- 위 경고는 기존 런타임 경로 관련 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
|
||||
|
||||
## 후속 플레이테스트 포인트
|
||||
|
||||
- Stage 1 보스 처치 후 결과 화면 없이 Stage 2 INTRO로 자연스럽게 이어지는지 확인한다.
|
||||
- Stage 8 보스 처치 후 `GAME_COMPLETE` 결과로 진입하는지 확인한다.
|
||||
- 장착 무기 파츠가 기체와 과하게 분리되어 보이지 않는지 확인한다.
|
||||
- Stage 3 이후 `ZONE_BOMB`, `WALL_WAVE`, `HOMING_CHASE`, `PRECISION_LOCK` 계열이 회피 목적을 명확히 만드는지 확인한다.
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# Skybound Skill Concept and Hangar Layout Overlap Fix
|
||||
|
||||
작성일: 2026-04-25 10:09 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- 스킬 업그레이드 후 화면에 긴 라이트 기둥만 보이는 문제가 있어 스킬 개념과 연출을 수정한다.
|
||||
- HUD/UI 관점에서 왼쪽에 여러 UI가 겹쳐 나오는 문제가 있어 필요하면 전체적으로 재설계한다.
|
||||
|
||||
## 확인한 문제
|
||||
|
||||
### Hyper-Sonic Vulcan 컨셉 불일치
|
||||
|
||||
- `Hyper-Sonic Vulcan`은 이름상 고속 벌컨/캐논 계열인데 실제 구현은 영구 지속되는 긴 레이저 빔이었다.
|
||||
- `GameRenderer`가 플레이어 기준으로 화면 끝까지 이어지는 두꺼운 시안 빔을 그려서, 스킬이 무기라기보다 긴 조명처럼 보였다.
|
||||
- `ModularWeaponSystem.updateHyperLaser()`도 라인 판정으로 지속 데미지를 넣고 있어 플레이어가 발사/탄막을 체감하기 어려웠다.
|
||||
|
||||
### Hangar UI 겹침
|
||||
|
||||
- `HangarOverlay.tsx`에서 `UPGRADE`와 `PASS` 탭 콘텐츠가 오른쪽 `craft-area` 패널 밖에 렌더링되고 있었다.
|
||||
- 그 결과 CSS Grid의 세 번째 아이템처럼 배치되어 왼쪽 패널/재료 영역과 겹쳐 보였다.
|
||||
- 특히 `UPGRADE` 탭 선택 시 `PERMANENT UPGRADES` 콘텐츠가 왼쪽 재료 패널 위로 올라오는 문제가 발생했다.
|
||||
|
||||
### 전투 보상 텍스트 겹침
|
||||
|
||||
- 적 처치 보상 텍스트가 화면 가장자리에서 생성될 경우 `TechMats`, `+TAC` 같은 텍스트가 잘리거나 서로 겹쳐 보일 수 있었다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### Twin Arc Vulcan으로 스킬 컨셉 변경
|
||||
|
||||
- `HYPER_SONIC_VULCAN` 메타데이터 이름을 `Twin Arc Vulcan`으로 변경했다.
|
||||
- 설명도 `Twin magitech cannons fire rapid piercing arc rounds.`로 바꿔 실제 플레이 감각과 맞췄다.
|
||||
- 기존의 영구 레이저 빔 컨셉을 제거하고, 전방 관통 아크 탄환을 빠르게 발사하는 무기로 재설계했다.
|
||||
- 플레이어 좌우 포드에서 3갈래 관통탄을 빠르게 발사해 “벌컨 업그레이드” 느낌을 강화했다.
|
||||
- 스킬이 화면을 덮는 긴 빛이 아니라, 방향성과 탄막 밀도가 있는 공격으로 보이게 했다.
|
||||
|
||||
### 긴 라이트 렌더링 제거
|
||||
|
||||
- `GameRenderer`의 full-screen beam `fillRect()` 렌더링을 제거했다.
|
||||
- 대신 기체 앞쪽 포드에 짧은 muzzle bloom과 짧은 시안 streak만 표시하도록 변경했다.
|
||||
- 화면 전체를 가리는 시각 노이즈를 줄이고, 실제 공격은 projectile 렌더링이 담당하게 했다.
|
||||
|
||||
### Hangar 탭 레이아웃 수정
|
||||
|
||||
- `UPGRADE`와 `PASS` 탭 콘텐츠를 오른쪽 `craft-area` 내부로 이동했다.
|
||||
- 이제 탭 콘텐츠가 왼쪽 `Airframe Telemetry`/`Materials` 패널과 겹치지 않는다.
|
||||
- 기존 스타일을 유지하면서 구조적 렌더링 오류를 먼저 제거했다.
|
||||
|
||||
### Floating Text 안전 영역 처리
|
||||
|
||||
- `ctx.spawnText()`에서 텍스트 생성 위치를 화면 안전 영역 안으로 clamp한다.
|
||||
- 왼쪽 끝/오른쪽 끝에서 적이 죽어도 보상 텍스트가 화면 밖으로 잘리거나 HUD 영역에 과하게 겹치는 현상을 줄였다.
|
||||
|
||||
## 수정 파일
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/evolutions.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/weaponBehaviors.ts`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/HangarOverlay.tsx`
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- Vite 경고: `/sprites/player.png referenced in /sprites/player.png didn't resolve at build time`
|
||||
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
|
||||
|
||||
## 후속 플레이테스트 포인트
|
||||
|
||||
- Gatling 진화 후 더 이상 긴 레이저 기둥이 보이지 않는지 확인한다.
|
||||
- `Twin Arc Vulcan`이 빠른 관통 탄막 무기로 체감되는지 확인한다.
|
||||
- Hangar에서 `UPGRADES`, `EVENT PASS` 탭 선택 시 왼쪽 패널과 콘텐츠가 겹치지 않는지 확인한다.
|
||||
- 전투 보상 텍스트가 화면 가장자리에서 잘리지 않는지 확인한다.
|
||||
Reference in New Issue
Block a user