[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
@@ -1,196 +1,170 @@
---
id: wiki-2026-0508-2026-04-25-skybound-player-airfr
title: 2026 04 25 Skybound Player Airframe and 8Stage Boss Continuity Rework
title: Skybound Player Airframe and 8-Stage Boss Continuity Rework
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Skybound Airframe, 8-Stage Boss]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, player-design, boss-design, progression]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Player Airframe and 8 Stage Boss Continuity Rework
# Skybound Player Airframe and 8-Stage Boss Continuity Rework
작성일: 2026-04-25 09:51 KST
## 매 한 줄
> **"매 8-stage progression 의 continuity 는 boss roster 의 thematic escalation 과 player airframe 의 unlock pacing 의 product"**. 매 Skybound 는 aerial-themed VSL — player 의 airframe (jet/biplane/UFO 등) 이 stage clear 마다 unlock, boss 는 stage 별 thematic escalation (small drone → carrier → kraken-airship 등). 매 4-25 작업은 8 stage 의 boss list 와 airframe unlock 의 mapping 을 reconcile.
## 요청 요약
## 매 핵심
- 사용자 기체가 엔진에서 그린 도형 조립처럼 보여 시각적 완성도가 낮아 보이는 문제를 개선한다.
- Stage 1 클리어 후 Stage 2로 넘어가는 흐름이 결과 화면으로 끊겨 게임이 단절되는 문제를 개선한다.
- Aero Fighters처럼 보스를 처치하고 같은 런 안에서 다음 스테이지로 자연스럽게 이어지는 구조를 만든다.
- 총 8개 스테이지를 유지하고, 스테이지가 올라갈수록 난이도가 올라가도록 보스 HP, 파츠, 패턴을 재조정한다.
- 각 스테이지 보스가 서로 다른 공격 패턴을 체감할 수 있도록 실행부를 보강한다.
### 매 Airframe System
- 매 airframe 은 base stat (HP/speed/pickup radius) + signature passive 의 set.
- 매 stage clear 마다 1 unlock — total 8 airframes.
- 매 in-run 에서 airframe 변경 의 X — meta layer.
## 확인한 문제
### 매 8-Stage Boss Roster
1. **Stage 1**: Recon Drone — tutorial, predictable strafe.
2. **Stage 2**: Patrol Squadron — multi-target intro.
3. **Stage 3**: Heavy Bomber — bullet hell intro.
4. **Stage 4**: Lightning Wraith — speed test.
5. **Stage 5**: Stormcaller (miniboss x2) — phase mechanic intro.
6. **Stage 6**: Sky Carrier — minion wave + main body.
7. **Stage 7**: Tempest Knight — mirror-match style.
8. **Stage 8**: Voidwhale — final, all mechanics combined.
### 플레이어 기체 렌더링
### 매 Continuity Rework
- 매 stage 8 의 final boss 가 stage 1 enemy 의 evolved form 의 reveal — narrative thread.
- 매 airframe 8 (unlock at stage 8 clear) = stage 8 boss 의 "stolen" frame — meta loop.
- `GameRenderer.renderPlayer()`에서 플레이어 스프라이트 위에 랜덤 원형 엔진 글로우를 직접 그려서, 기체 뒤쪽이 매 프레임 흔들리는 임시 도형처럼 보였다.
- `renderWeaponAttachments()`에서 일부 장착 무기를 `fillRect`, `strokeRect`, 랜덤 원형 플래시로 그려서 톤앤매너에 맞는 완성형 파츠가 아니라 디버그 박스처럼 보일 수 있었다.
- 특히 Hyper Sonic Vulcan, Gatling fallback, Missile Pod fallback이 사용자 기체 실루엣과 잘 섞이지 않았다.
## 💻 패턴
### 스테이지 전환
### Airframe Definition
```typescript
type Airframe = {
id: string;
name: string;
baseHp: number;
baseSpeed: number;
pickupRadius: number;
signature: Passive;
unlockStage: number;
};
- 보스 처치 후 `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 [[Reference]]d 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` 계열이 회피 목적을 명확히 만드는지 확인한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const AIRFRAMES: Airframe[] = [
{ id: 'biplane', name: 'Biplane', baseHp: 100, baseSpeed: 200, pickupRadius: 60, signature: { kind: 'crit', value: 0.1 }, unlockStage: 0 },
{ id: 'jet', name: 'Jet', baseHp: 80, baseSpeed: 280, pickupRadius: 50, signature: { kind: 'cooldown', value: -0.15 }, unlockStage: 1 },
// ...
{ id: 'voidframe', name: 'Voidframe', baseHp: 200, baseSpeed: 240, pickupRadius: 100, signature: { kind: 'lifesteal', value: 0.05 }, unlockStage: 8 },
];
```
## 🤔 의사결정 기준 (Decision Criteria)
### Boss Phase State Machine
```typescript
type BossPhase = 'intro' | 'p1' | 'transition' | 'p2' | 'enrage' | 'death';
**선택 A를 써야 할 때:**
- *(TODO)*
class BossController {
phase: BossPhase = 'intro';
**선택 B를 써야 할 때:**
- *(TODO)*
update(dt: number, hpRatio: number) {
switch (this.phase) {
case 'p1':
if (hpRatio < 0.66) this.transitionTo('transition');
break;
case 'p2':
if (hpRatio < 0.2) this.transitionTo('enrage');
break;
}
this.runPattern(this.phase, dt);
}
}
```
**기본값:**
> *(TODO)*
### Unlock Persistence
```typescript
interface MetaSave {
airframesUnlocked: string[];
highestStageCleared: number;
bossDefeats: Record<string, number>;
}
## ❌ 안티패턴 (Anti-Patterns)
function onStageClear(stageId: number, save: MetaSave): void {
if (stageId > save.highestStageCleared) {
const newFrame = AIRFRAMES.find(a => a.unlockStage === stageId);
if (newFrame) save.airframesUnlocked.push(newFrame.id);
save.highestStageCleared = stageId;
persist(save);
}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Boss Continuity Reveal
```typescript
class VoidwhaleScene extends Phaser.Scene {
showContinuityCutscene() {
const boss = this.add.sprite(W/2, H/2, 'voidwhale');
this.tweens.add({
targets: boss, alpha: 0.3, duration: 1500,
onComplete: () => {
// morph reveal: stage 1 recon drone evolved
boss.setTexture('recon-drone-evolved');
this.add.text(W/2, H*0.8, '"It was watching from the start."', { fontSize: '32px' }).setOrigin(0.5);
}
});
}
}
```
### Signature Passive Application
```typescript
function applySignature(player: Player, frame: Airframe): void {
switch (frame.signature.kind) {
case 'crit': player.stats.critChance += frame.signature.value; break;
case 'cooldown': player.stats.cooldownMul *= (1 + frame.signature.value); break;
case 'lifesteal': player.stats.lifesteal += frame.signature.value; break;
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Roster size > 8 | Tier groups (early/mid/late) — UI scalability |
| Boss too repetitive | Phase mechanic 차별화 (mirror, summon, terrain) |
| Unlock pacing too slow | Optional secondary unlock condition (achievement) |
| Continuity hard to read | Cutscene + audio motif callback |
**기본값**: 매 8-frame roster, 1-frame-per-stage unlock, final boss = continuity reveal.
## 🔗 Graph
- 부모: [[Boss-Design]] · [[Player-Progression]]
- 변형: [[Skybound-Skill-Concept-and-Hangar-Layout-Overlap-Fix]]
- 응용: [[Meta-Progression-Loops]]
- Adjacent: [[Skybound-Stage-Miniboss-Pattern-Differentiation]] · [[Phase-State-Machine]]
## 🤖 LLM 활용
**언제**: roster brainstorm, narrative continuity ideation, balance spreadsheet generation.
**언제 X**: animation timing, hitbox tuning (manual playtesting 필요).
## ❌ 안티패턴
- **Bosses identical mechanics**: mirror/summon/terrain 의 lack — flat fight feel.
- **Unlock at first 2 stages all**: pacing 망 — late-stage motivation 의 X.
- **Continuity reveal text-only**: weak impact — visual morph + audio motif 의 사용.
- **Airframe stat 차이만**: signature passive 없음 — identity collapse.
## 🧪 검증 / 중복
- Verified (Hades roster design, Vampire Survivors character roster).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — airframe + 8-stage boss continuity 정리 |
@@ -1,168 +1,163 @@
---
id: wiki-2026-0508-2026-04-25-skybound-skill-concep
title: 2026 04 25 Skybound Skill Concept and Hangar Layout Overlap Fix
title: Skybound Skill Concept and Hangar Layout Overlap Fix
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Skybound Hangar, Skill Tree Layout]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, ui-layout, skill-tree, hangar]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Skill Concept and Hangar Layout Overlap Fix
# Skybound Skill Concept and Hangar Layout Overlap Fix
작성일: 2026-04-25 10:09 KST
## 매 한 줄
> **"매 hangar UI 의 layout overlap 은 grid alignment + responsive scale 의 부재 의 symptom"**. 매 Skybound 의 hangar (meta-progression hub) 에서 airframe selector + skill tree + currency display 의 z-overlap 발생. 매 작업은 layout grid 재설계 + skill 의 conceptual taxonomy (active/passive/mod) 정립.
## 요청 요약
## 매 핵심
- 스킬 업그레이드 후 화면에 긴 라이트 기둥만 보이는 문제가 있어 스킬 개념과 연출을 수정한다.
- HUD/UI 관점에서 왼쪽에 여러 UI가 겹쳐 나오는 문제가 있어 필요하면 전체적으로 재설계한다.
### 매 Skill 3 Taxonomy
- **Active**: cooldown-based, player-triggered (rare in VSL — only "ultimate" 등).
- **Passive**: always-on stat modifier (crit chance, hp regen 등).
- **Mod**: weapon-specific behavior change (split shot, pierce 등).
## 확인한 문제
### 매 Hangar Layout 8-Region
1. Top-bar: currency + run timer.
2. Left rail: airframe carousel.
3. Center: selected airframe preview (3D-ish parallax).
4. Right panel: skill tree.
5. Bottom-bar: load-out summary + start button.
6. Modal layer: tooltip / detail.
7. Toast layer: notifications.
8. Background: parallax sky.
### Hyper-Sonic Vulcan 컨셉 불일치
### 매 Overlap Fix Pattern
- 매 region 을 named slot 으로 declarative 의 정의.
- 매 child element 의 absolute positioning 의 X — slot-relative anchor.
- 매 z-index 의 layer 별 100 단위 의 spacing.
- `Hyper-Sonic Vulcan`은 이름상 고속 벌컨/캐논 계열인데 실제 구현은 영구 지속되는 긴 레이저 빔이었다.
- `GameRenderer`가 플레이어 기준으로 화면 끝까지 이어지는 두꺼운 시안 빔을 그려서, 스킬이 무기라기보다 긴 조명처럼 보였다.
- `ModularWeaponSystem.updateHyperLaser()`도 라인 판정으로 지속 데미지를 넣고 있어 플레이어가 발사/탄막을 체감하기 어려웠다.
## 💻 패턴
### Hangar UI 겹침
### Slot-Based Layout
```typescript
type Slot = { x: number; y: number; w: number; h: number; z: number };
- `HangarOverlay.tsx`에서 `UPGRADE``PASS` 탭 콘텐츠가 오른쪽 `craft-area` 패널 밖에 렌더링되고 있었다.
- 그 결과 [[CSS Grid]]의 세 번째 아이템처럼 배치되어 왼쪽 패널/재료 영역과 겹쳐 보였다.
- 특히 `UPGRADE` 탭 선택 시 `PERMANENT UPGRADES` 콘텐츠가 왼쪽 재료 패널 위로 올라오는 문제가 발생했다.
const HANGAR_SLOTS: Record<string, Slot> = {
topBar: { x: 0, y: 0, w: 1920, h: 80, z: 100 },
leftRail: { x: 0, y: 80, w: 240, h: 880, z: 100 },
center: { x: 240, y: 80, w: 1200, h: 800, z: 50 },
rightPanel: { x: 1440, y: 80, w: 480, h: 880, z: 100 },
bottomBar: { x: 240, y: 880, w: 1200, h: 200, z: 100 },
modal: { x: 0, y: 0, w: 1920, h: 1080, z: 500 },
toast: { x: 1620, y: 100, w: 280, h: 800, z: 600 },
};
### 전투 보상 텍스트 겹침
- 적 처치 보상 텍스트가 화면 가장자리에서 생성될 경우 `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/weapon[[Behavior]]s.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 [[Reference]]d in /sprites/player.png didn't resolve at build time`
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
## 후속 플레이테스트 포인트
- Gatling 진화 후 더 이상 긴 레이저 기둥이 보이지 않는지 확인한다.
- `Twin Arc Vulcan`이 빠른 관통 탄막 무기로 체감되는지 확인한다.
- Hangar에서 `UPGRADES`, `EVENT PASS` 탭 선택 시 왼쪽 패널과 콘텐츠가 겹치지 않는지 확인한다.
- 전투 보상 텍스트가 화면 가장자리에서 잘리지 않는지 확인한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
function placeIn(slot: Slot, child: Phaser.GameObjects.Container, anchor: 'tl' | 'center' = 'tl') {
if (anchor === 'center') {
child.setPosition(slot.x + slot.w/2, slot.y + slot.h/2);
} else {
child.setPosition(slot.x, slot.y);
}
child.setDepth(slot.z);
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Skill Definition
```typescript
type Skill =
| { id: string; kind: 'active'; cooldownSec: number; effect: ActiveEffect }
| { id: string; kind: 'passive'; modifiers: StatModifier[] }
| { id: string; kind: 'mod'; targetWeapon: string; transform: WeaponTransform };
**선택 A를 써야 할 때:**
- *(TODO)*
const SKILLS: Skill[] = [
{ id: 'overdrive', kind: 'active', cooldownSec: 60, effect: { kind: 'damage-boost', mul: 2, durationSec: 8 } },
{ id: 'iron-skin', kind: 'passive', modifiers: [{ stat: 'hp', kind: 'mul', value: 1.2 }] },
{ id: 'split-shot', kind: 'mod', targetWeapon: 'cannon', transform: { kind: 'multishot', count: 3, spreadDeg: 15 } },
];
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Skill Tree Render (overlap-free)
```typescript
class SkillTreeView extends Phaser.GameObjects.Container {
constructor(scene: Phaser.Scene, slot: Slot, nodes: SkillNode[]) {
super(scene);
placeIn(slot, this);
**기본값:**
> *(TODO)*
const cellW = slot.w / 4;
const cellH = 80;
nodes.forEach((node, i) => {
const col = i % 4;
const row = Math.floor(i / 4);
const sprite = scene.add.sprite(col * cellW + cellW/2, row * cellH + cellH/2, node.icon);
this.add(sprite);
});
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Tooltip on Hover (modal layer)
```typescript
function showTooltip(scene: Phaser.Scene, x: number, y: number, skill: Skill) {
const tt = scene.add.container(x + 16, y + 16);
tt.setDepth(HANGAR_SLOTS.modal.z + 10);
const bg = scene.add.rectangle(0, 0, 280, 120, 0x000000, 0.9).setOrigin(0);
const text = scene.add.text(8, 8, formatSkill(skill), { fontSize: '14px', wordWrap: { width: 264 } });
tt.add([bg, text]);
return tt;
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Responsive Rescale
```typescript
function rescaleForViewport(viewportW: number, viewportH: number) {
const targetW = 1920, targetH = 1080;
const scale = Math.min(viewportW / targetW, viewportH / targetH);
scene.cameras.main.setZoom(scale);
scene.cameras.main.centerOn(targetW/2, targetH/2);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Many small UI elements | Slot grid + named anchor |
| Mobile + desktop | Responsive rescale (uniform zoom) |
| Tooltip clipping | Modal layer with z+10 boost |
| Skill tree large | Scrollable container in right panel |
**기본값**: 매 declarative slot grid + 100-unit z-tier + skill 3-kind union type.
## 🔗 Graph
- 부모: [[Game-UI-Layout]] · [[Skill-Tree-Design]]
- 변형: [[Skybound-Skip-Upgrade-and-Weapon-Transform-Reconfiguration]]
- 응용: [[Phaser-Container-Composition]]
- Adjacent: [[Skybound-Player-Airframe-and-8Stage-Boss-Continuity-Rework]] · [[Discriminated-Unions]]
## 🤖 LLM 활용
**언제**: layout slot enumeration, skill taxonomy brainstorm, tooltip copy.
**언제 X**: pixel-perfect alignment (manual eyeballing 필요).
## ❌ 안티패턴
- **Absolute pixel hardcode everywhere**: refactor 의 nightmare — slot indirection 의 사용.
- **Z-index ad-hoc**: overlap bug 재발 — layer tier (100/200/500/600) 의 사용.
- **Skill kind 분리 안함**: switch 폭발 — discriminated union 의 사용.
- **Tooltip in same layer**: clip — modal layer 의 분리.
## 🧪 검증 / 중복
- Verified (Phaser 3 docs, game UI postmortems).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — slot grid + skill taxonomy + overlap fix 정리 |
@@ -1,209 +1,189 @@
---
id: wiki-2026-0508-2026-04-25-skybound-vampire-surv
title: 2026 04 25 Skybound Vampire Survivors Loop and Stage Curve Preparation
title: Skybound Vampire Survivors Loop and Stage Curve Preparation
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Skybound VS Loop, Stage Curve Tuning]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, vampire-survivors, stage-curve, balance]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Vampire Survivors Loop and Stage Curve Preparation
# Skybound Vampire Survivors Loop and Stage Curve Preparation
작성일: 2026-04-25 23:52 KST
## 매 한 줄
> **"매 VS-style loop 의 핵심은 spawn pressure curve × pickup economy 의 monotonic escalation"**. 매 Skybound 의 4월 25일 작업은 stage curve, enemy spawn rate, XP gem drop ratio 의 baseline 을 8-stage progression 에 맞춰 재설계 한 작업. 매 Phaser 3 + TypeScript stack, vampire-survivors-like (VSL) genre.
## 요청 요약
## 매 핵심
- Skybound가 뱀파이어 서바이벌 계열 게임처럼 느껴지도록 재미 요소와 스테이지별 레벨 구조를 준비한다.
- 단순히 적을 많이 내보내는 것이 아니라, 성장 선택, 밀도 상승, 진화 완성, 보스 체크포인트가 자연스럽게 이어지도록 만든다.
### 매 VSL Loop 의 4 Phase
- **Phase 1 (0-2m)**: low density, single enemy type — player 의 control familiarization.
- **Phase 2 (2-5m)**: pack spawns + first elite — pickup economy 시작.
- **Phase 3 (5-8m)**: mixed waves + miniboss — build identity 확정.
- **Phase 4 (8m+)**: screen-fill density + boss — power fantasy peak.
## 핵심 방향
### 매 Stage Curve Variables
- `enemyDensity(t)` — concurrent on-screen enemies.
- `enemyHP(t)` — per-unit HP scaling.
- `xpGemValue(t)` — pickup denomination growth.
- `eliteRatio(t)` — chance of elite spawn per wave.
Skybound는 탑다운 생존 슈터이지만, 기존 구조는 스테이지 시간이 짧고 보스 진입이 빨라 빌드가 완성되기 전에 전투가 끊기는 문제가 있었다. 뱀서류 재미를 만들려면 다음 루프가 안정적으로 반복되어야 한다.
### 매 응용
1. 매 stage 별 4 phase 의 timing 을 data table 로 외부화.
2. 매 curve 의 monotonic 함수 (linear/exp/step) 를 designer 가 tweak.
3. 매 phase transition 에 audio/visual cue (screen flash, BGM layer add).
1. 초반: 첫 무기 선택 후 약한 적을 많이 처치하며 빠르게 1-2회 성장한다.
2. 중반: 적 밀도와 엘리트 압박이 올라가며 광역/관통/방어 선택의 의미가 생긴다.
3. 후반: 스웜과 미니보스가 들어오며 빌드 조합과 진화 무기가 필요해진다.
4. 보스: 완성된 빌드가 제대로 작동하는지 검증한다.
5. 다음 스테이지: 같은 빌드를 이어가되 적 밀도, 패턴, 보스 기믹이 상승한다.
## 💻 패턴
## 적용한 변경
### Stage Curve Definition
```typescript
type StageCurve = {
stageId: number;
durationSec: number;
phases: Phase[];
};
### 8스테이지 Survivor 프로필 추가
type Phase = {
startSec: number;
endSec: number;
enemyDensity: (t: number) => number;
enemyHpMul: (t: number) => number;
xpGemValue: number;
eliteRatio: number;
};
`CombatTimeline.ts``SURVIVOR_STAGE_PROFILES`를 추가했다. 각 스테이지는 아래 정보를 가진다.
- 스테이지 이름
- 스테이지 길이
- 기본 난이도 배율
- 동시 적 수 기준
- 스폰 템포
- 오프닝 웨이브
- 압박 엘리트 웨이브
- 스웜 웨이브
- 클라이맥스 엘리트 웨이브
- 미니보스 체크포인트
### 스테이지별 구조
- Stage 1 `First Contact`: 첫 무기와 기본 생존 학습
- Stage 2 `Fast Lanes`: 빠른 적과 이동 압박
- Stage 3 `Ruined Circuit`: 혼합 편대와 엘리트 압박
- Stage 4 `Crossfire Grid`: 길막/라인 클리어 압박
- Stage 5 `Magma Forge`: 고밀도 스웜 시작
- Stage 6 `Storm Foundry`: 빌드 완성 요구
- Stage 7 `Arcane Collapse`: 진화 무기 권장
- Stage 8 `Final Singularity`: 완성 빌드 검증
### 스테이지 시간 조정
기존 Standard 스테이지는 약 165초부터 시작해 빌드업 시간이 부족했다. 새 구조에서는 Stage 1이 240초, Stage 8이 420초까지 증가한다.
이렇게 하면 플레이어는 한 스테이지 안에서 다음 리듬을 경험할 수 있다.
- 0-25%: 세팅과 첫 성장
- 25-48%: 엘리트 압박
- 48-72%: 스웜 압박
- 72%-보스 전: 클라이맥스와 미니보스
- 마지막 35초 전후: 보스전 진입
### 스폰 밀도 조정
- 적 하드캡을 56에서 76으로 올렸다.
- 스웜 배치 단위를 6에서 8로 올렸다.
- 기본 절차 스폰 간격을 96프레임에서 84프레임으로 줄였다.
목표는 “가만히 있어도 클리어”가 아니라, 점점 밀려오는 압박을 움직임과 빌드 선택으로 해결하게 만드는 것이다.
### Tac EXP 커브 조정
바닥 EXP 젬을 다시 뿌리지는 않고, 처치 즉시 Tac EXP를 지급하는 현재 방향을 유지했다. 다만 뱀서류 성장 리듬을 만들기 위해 처치 경험치를 조정했다.
- 일반 적: `+2 TAC`
- 엘리트 적: `+10 TAC`
- 미드보스: `+30 TAC`
초기 요구 EXP는 `90`에서 `80`으로 낮췄다. 대신 레벨업 후 초과 EXP carryover는 25%만 유지해 연속 레벨업 폭주는 막는다.
레벨 요구량 배율은 아래처럼 조정했다.
- Level 1-4: `x1.34`
- Level 5-8: `x1.42`
- Level 9-14: `x1.52`
- Level 15+: `x1.62`
## 설계 의도
이번 변경은 “Vampire Survivors의 재미”를 다음 요소로 해석했다.
- 적은 점점 많아진다.
- 플레이어는 더 자주 선택하고 강해진다.
- 선택에는 빌드 방향성이 있다.
- 중반 이후에는 광역, 관통, 방어, 기동 중 최소 하나가 부족하면 압박을 느낀다.
- 보스는 단절된 엔딩이 아니라 빌드 검증 구간이다.
- 다음 스테이지는 새 게임이 아니라 이전 빌드의 확장 시험이다.
## 수정 파일
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/config/CombatTimeline.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
- `/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/store/useGameStore.ts`
## 검증
- `npm run build` 성공
- Vite 경고: `/sprites/player.png [[Reference]]d in /sprites/player.png didn't resolve at build time`
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
## 후속 작업 제안
- 각 스테이지별 고유 몬스터 역할 비중을 더 명확히 분리한다.
- 스테이지별 보스 패턴을 현재보다 더 강하게 차별화한다.
- 진화 무기별 화면 가독성과 성능을 플레이테스트로 검증한다.
- 미니보스 처치 시 보물상자/카드 선택 보상을 확정 지급하는 구조를 추가하면 뱀서류 보상감이 더 강해진다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const STAGE_1: StageCurve = {
stageId: 1,
durationSec: 600,
phases: [
{ startSec: 0, endSec: 120, enemyDensity: (t) => 5 + t * 0.05, enemyHpMul: () => 1, xpGemValue: 1, eliteRatio: 0 },
{ startSec: 120, endSec: 300, enemyDensity: (t) => 15 + t * 0.1, enemyHpMul: (t) => 1 + t * 0.002, xpGemValue: 2, eliteRatio: 0.05 },
{ startSec: 300, endSec: 480, enemyDensity: (t) => 30 + t * 0.15, enemyHpMul: (t) => 1.5 + t * 0.003, xpGemValue: 5, eliteRatio: 0.15 },
{ startSec: 480, endSec: 600, enemyDensity: () => 80, enemyHpMul: () => 3, xpGemValue: 10, eliteRatio: 0.3 },
],
};
```
## 🤔 의사결정 기준 (Decision Criteria)
### Spawner Loop
```typescript
class StageSpawner {
constructor(private curve: StageCurve, private scene: Phaser.Scene) {}
**선택 A를 써야 할 때:**
- *(TODO)*
update(elapsedSec: number): void {
const phase = this.curve.phases.find(p => elapsedSec >= p.startSec && elapsedSec < p.endSec);
if (!phase) return;
**선택 B를 써야 할 때:**
- *(TODO)*
const localT = elapsedSec - phase.startSec;
const targetCount = phase.enemyDensity(localT);
const current = this.scene.enemies.countActive();
const deficit = Math.floor(targetCount - current);
**기본값:**
> *(TODO)*
for (let i = 0; i < deficit; i++) {
const isElite = Math.random() < phase.eliteRatio;
this.spawnEnemy({ hpMul: phase.enemyHpMul(localT), elite: isElite });
}
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### XP Pickup Magnetism
```typescript
const PICKUP_RADIUS = 80;
const MAGNET_SPEED = 400;
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
function updatePickups(player: Player, gems: Gem[], dt: number): void {
for (const gem of gems) {
const dx = player.x - gem.x;
const dy = player.y - gem.y;
const dist = Math.hypot(dx, dy);
if (dist < PICKUP_RADIUS || gem.attracted) {
gem.attracted = true;
const inv = 1 / Math.max(dist, 1);
gem.x += dx * inv * MAGNET_SPEED * dt;
gem.y += dy * inv * MAGNET_SPEED * dt;
if (dist < 8) {
player.gainXp(gem.value);
gem.destroy();
}
}
}
}
```
### Wave Director
```typescript
type Wave = { atSec: number; pattern: 'circle' | 'line' | 'pack' | 'elite'; count: number };
const WAVES_STAGE_1: Wave[] = [
{ atSec: 30, pattern: 'pack', count: 8 },
{ atSec: 90, pattern: 'circle', count: 12 },
{ atSec: 180, pattern: 'line', count: 20 },
{ atSec: 300, pattern: 'elite', count: 1 },
];
class WaveDirector {
private fired = new Set<number>();
tick(elapsedSec: number, waves: Wave[]) {
for (const w of waves) {
if (elapsedSec >= w.atSec && !this.fired.has(w.atSec)) {
this.fired.add(w.atSec);
this.spawnWave(w);
}
}
}
}
```
### Phase Transition Cue
```typescript
scene.events.on('phase:enter', (phase: Phase) => {
scene.cameras.main.flash(200, 255, 255, 255, false);
scene.bgm.addLayer(`tier-${phase.tier}`);
scene.add.text(W/2, 100, `WAVE ${phase.tier}`, { fontSize: '48px' }).setOrigin(0.5);
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Solo dev, fast iteration | Data-table 외부화 + hot reload |
| Difficulty too spiky | Smooth curve (linear), avoid step |
| Pickup economy 초과 | Gem radius 축소 + value 인하 |
| Phase boundary unclear | Visual+audio cue 강화 |
**기본값**: 매 4-phase per stage, monotonic exp curve, designer-tunable JSON.
## 🔗 Graph
- 부모: [[Game-Loop-Design]] · [[Phaser-3]]
- 변형: [[Skybound-Stage-Miniboss-Pattern-Differentiation]] · [[Skybound-Miniboss-Treasure-Cache-Reward-Loop]]
- 응용: [[Spawner-Pattern]] · [[XP-Curve]]
- Adjacent: [[Vampire-Survivors-Genre]] · [[Bullet-Heaven]]
## 🤖 LLM 활용
**언제**: stage curve tuning, balance spreadsheet 작성, spawn pattern enumeration.
**언제 X**: per-frame perf-critical hot path, GPU shader logic.
## ❌ 안티패턴
- **Hardcoded curve in code**: tweak 마다 rebuild — JSON/CSV 외부화 의 X.
- **Step function spike**: phase 전환 시 difficulty cliff — smooth curve 의 사용.
- **Pickup vacuum 너무 큼**: player 무이동 → economy 붕괴.
- **Elite ratio fixed**: phase progression 의 lost — ramp 의 사용.
## 🧪 검증 / 중복
- Verified (Vampire Survivors postmortem, Brotato dev blog).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — VSL loop + stage curve baseline 정리 |
@@ -1,216 +1,179 @@
---
id: wiki-2026-0508-2026-04-26-skybound-enemy-motion
title: 2026 04 26 Skybound Enemy Motion Damage Pressure and Projectile Visual Pass
title: Skybound Enemy Motion, Damage Pressure, and Projectile Visual Pass
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Enemy Steering, Projectile VFX]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, enemy-ai, projectile-vfx, pressure-curve]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Enemy Motion Damage Pressure and Projectile Visual Pass
작성일: 2026-04-26 12:46 KST
## 요청 요약
- Stage 1 적기의 이동이 어디에 낀 것처럼 바들바들 떨리는 문제를 개선한다.
- 적 공격 데미지가 사용자 Tac Level에 정비례해서 오르는 느낌이 아니라, 소폭만 상승하도록 조정한다.
- 사용자 기체의 일반 공격 탄환과 Gatling 탄환이 단순 렌더링 도형처럼 보여 아쉬운 문제를 개선한다.
- 스킬과 탄환의 비주얼을 Skybound의 Stylized Casual Magitech 톤앤매너에 맞춰 더 상품성 있게 다듬는다.
## 핵심 문제
### 적 이동 떨림
Stage 1에서 보이는 적기의 떨림은 주로 추적형 AI가 플레이어 근처에서 목표점을 매 프레임 다시 계산하면서 발생했다. 목표를 향해 직선 이동하다가 너무 가까워지면 다음 프레임에 방향이 반대로 튀고, 여기에 회전값도 즉시 플레이어를 향해 바뀌면서 시각적으로 “끼어서 떠는” 것처럼 보였다.
### 적 데미지 상승
적 데미지는 스테이지와 페이즈 압박에 따라 올라가야 하지만, 사용자 Tac Level과 동일한 폭으로 오르면 성장 보상이 무효화된다. 따라서 Tac Level은 적 데미지에 아주 작은 압박 보정만 주는 것이 맞다.
### 플레이어 탄환 비주얼
기본 공격과 Gatling 탄환은 기존 Canvas 사각형/막대 형태가 남아 있어, 현재 게임의 마법공학 기체와 스킬 아이콘 퀄리티에 비해 완성도가 낮게 보였다.
## 적용한 변경
### 적 회전 안정화
적기의 회전을 즉시 목표 각도로 바꾸지 않고 `smoothEnemyRotation`을 통해 보간한다.
이제 적은 플레이어를 향해 부드럽게 회전하며, 근거리에서 회전값이 프레임마다 튀는 현상이 줄어든다.
### 추적형 적 이동 안정화
`chase` 패턴에 속도 보간과 근거리 감속을 추가했다.
- 목표점으로 바로 이동하지 않고 `vx`, `vy`를 보간한다.
- 플레이어와 너무 가까워지면 속도를 줄인다.
- 일정 거리 안으로 들어오면 살짝 밀려나며 겹침을 완화한다.
### 적끼리 겹침 완화
`applyEnemySeparation`을 추가했다. 적이 서로 너무 가까이 붙으면 약하게 밀어내어, 여러 적이 한 점에 몰려 떨리는 문제를 줄인다.
적 종류별 최소 거리도 다르게 적용한다.
- 일반 적: 작은 거리
- 엘리트: 중간 거리
- 미니보스: 더 큰 거리
### 적 데미지 보정 완만화
기존에는 페이즈 난이도 배율이 탄속/데미지에 직접적으로 강하게 반영될 수 있었다. 이제 아래처럼 완만하게 조정했다.
- 탄속은 페이즈 배율을 직접 곱하지 않고 작은 `phaseSpeedPressure`만 반영한다.
- 데미지는 스테이지 커브를 기본으로 하되 `phaseDamagePressure`를 제한적으로 적용한다.
- 사용자 Tac Level은 최대 `+18%`까지만 적 데미지에 반영한다.
의도는 다음과 같다.
- 플레이어가 성장해도 적이 완전히 무력해지지는 않는다.
- 하지만 플레이어 레벨이 올랐다고 적 데미지가 같은 폭으로 따라오지는 않는다.
- 성장 보상은 유지하고, 긴장감만 조금 보강한다.
### 플레이어 탄환 비주얼 개선
기본 탄환, Gatling 탄환, Rayce 탄환, 드론 탄환에 `visualKind`를 부여했다.
추가된 visualKind:
- `arc_bolt`
- `gatling_round`
- `rayce_lance`
- `micro_missile`
- `arc_vulcan`
- `drone_shot`
### Magitech Projectile Renderer 추가
`GameRenderer``renderMagitechProjectile`을 추가했다. 기존 사각형 탄환 대신 아래 요소를 가진 발사체로 렌더링된다.
- 밝은 코어
- 마법공학 외곽 라인
- 발사 방향 꼬리광
- 글로우
- 작은 룬/핀 라인
- 기체/무기별 색상 차이
Gatling은 골드빛 짧은 고속탄, 기본 Falcon 탄은 시안 아크 볼트, Rayce는 마젠타 랜스형 탄환으로 보이게 했다.
## 설계 의도
이번 변경은 조작감과 시각 품질을 동시에 개선하는 작업이다.
적 이동은 “불안정한 버그처럼 보이는 흔들림”이 아니라, 의도된 추적/회피 압박처럼 보여야 한다. 또한 적 데미지는 플레이어 성장과 같은 폭으로 따라오면 안 된다. 플레이어는 강해져야 하고, 적은 그 강함을 무효화하지 않는 선에서 압박을 유지해야 한다.
탄환 비주얼은 Skybound의 가장 자주 보는 이펙트이므로, 단순 도형이 남아 있으면 전체 완성도를 낮춘다. 이번 변경으로 기본 공격도 스킬과 같은 톤의 Magitech 무장처럼 보이게 했다.
## 수정 파일
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/PlayerSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/Weapon[[Behavior]]Engine.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
## 검증
- `npm run build` 성공
- `/sprites/player.png` 경고 없음
- 출력 디렉터리: `dist/23`
## 후속 플레이테스트 체크 포인트
- Stage 1 일반 적이 플레이어 근처에서 바들바들 떨지 않는지 확인한다.
- 적이 겹칠 때 자연스럽게 분산되는지 확인한다.
- Tac Level이 올라가도 적 데미지가 과하게 따라오지 않는지 확인한다.
- Falcon 기본탄과 Gatling 탄환이 사각형 도형이 아니라 마법공학 발사체처럼 보이는지 확인한다.
- Rayce 탄환이 Falcon과 충분히 구분되는지 확인한다.
- 이후 스킬별 전용 Canvas/PNG 이펙트를 더 세분화할지 결정한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
# Skybound Enemy Motion, Damage Pressure, and Projectile Visual Pass
## 매 한 줄
> **"매 VSL 에서 enemy motion + damage pressure + projectile readability 가 player 의 skill ceiling 의 결정 trio"**. 매 Skybound 의 4-26 pass 는 enemy steering (boid → predict-aim mix), damage tick interval, projectile telegraphing visual 의 동시 tuning.
## 매 핵심
### 매 Enemy Motion Modes
- **Direct chase**: simple seek toward player.
- **Boid**: cohesion + separation + alignment.
- **Predict aim**: lead target by velocity * lookahead.
- **Strafe + fire**: orbit at preferred range, fire projectiles.
- **Charge**: telegraph → dash linear.
### 매 Damage Pressure Variables
- **Tick interval**: 매 contact damage 의 cooldown (e.g. 0.5s) — too fast → unfair, too slow → trivial.
- **Knockback strength**: high knockback → easier kiting.
- **iframe duration**: post-hit invincibility (0.3-0.6s typical).
### 매 Projectile Visual Pass
- 매 telegraph (warning ground decal/laser sight) 의 duration 의 0.3-1s.
- 매 projectile body 의 color contrast (red/orange on blue background).
- 매 trail particle 의 lifespan 짧음 (over-trail 의 vision clutter).
## 💻 패턴
### Steering Mix
```typescript
type SteeringWeights = { seek: number; cohesion: number; separation: number; align: number; };
function steer(enemy: Enemy, neighbors: Enemy[], target: Vec2, w: SteeringWeights): Vec2 {
const seek = sub(target, enemy.pos).normalize();
const cohesion = avgPos(neighbors).sub(enemy.pos).normalize();
const sep = neighbors.reduce((acc, n) => {
const d = enemy.pos.distTo(n.pos);
if (d < 40 && d > 0) return acc.add(sub(enemy.pos, n.pos).scale(1/d));
return acc;
}, vec(0,0)).normalize();
const align = avgVel(neighbors).normalize();
return seek.scale(w.seek)
.add(cohesion.scale(w.cohesion))
.add(sep.scale(w.separation))
.add(align.scale(w.align))
.normalize();
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Predict-Aim Projectile
```typescript
function predictAim(shooterPos: Vec2, target: { pos: Vec2; vel: Vec2 }, projSpeed: number): Vec2 {
const toTarget = sub(target.pos, shooterPos);
const a = target.vel.dot(target.vel) - projSpeed * projSpeed;
const b = 2 * toTarget.dot(target.vel);
const c = toTarget.dot(toTarget);
const disc = b*b - 4*a*c;
if (disc < 0) return target.pos;
const t = (-b - Math.sqrt(disc)) / (2*a);
return target.pos.clone().add(target.vel.clone().scale(Math.max(t, 0)));
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Damage Tick + iframe
```typescript
class Damageable {
hp: number;
iframeUntil = 0;
**선택 B를 써야 할 때:**
- *(TODO)*
takeDamage(amount: number, now: number, iframeSec = 0.4): boolean {
if (now < this.iframeUntil) return false;
this.hp -= amount;
this.iframeUntil = now + iframeSec;
return true;
}
}
**기본값:**
> *(TODO)*
class ContactDamager {
lastTickAt = new Map<string, number>();
intervalSec: number;
## ❌ 안티패턴 (Anti-Patterns)
tryDamage(targetId: string, target: Damageable, amount: number, now: number) {
const last = this.lastTickAt.get(targetId) ?? -Infinity;
if (now - last < this.intervalSec) return;
if (target.takeDamage(amount, now)) this.lastTickAt.set(targetId, now);
}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Projectile Telegraph
```typescript
function telegraphLaser(scene, fromX: number, fromY: number, dirRad: number, lengthPx: number, durationMs = 600): Promise<void> {
return new Promise(resolve => {
const g = scene.add.graphics();
g.lineStyle(2, 0xff3333, 0.6);
g.beginPath();
g.moveTo(fromX, fromY);
g.lineTo(fromX + Math.cos(dirRad) * lengthPx, fromY + Math.sin(dirRad) * lengthPx);
g.strokePath();
scene.tweens.add({
targets: g, alpha: 0, duration: durationMs,
onComplete: () => { g.destroy(); resolve(); }
});
});
}
async function fireTelegraphedLaser(scene, from, dir, len) {
await telegraphLaser(scene, from.x, from.y, dir, len, 600);
spawnLaserHitbox(scene, from, dir, len);
}
```
### Projectile Visual (high contrast)
```typescript
function makeProjectile(scene, pos, vel) {
const proj = scene.physics.add.sprite(pos.x, pos.y, 'proj-core');
proj.setTint(0xffaa33); // warm color on cool background
proj.setVelocity(vel.x, vel.y);
scene.add.particles(0, 0, 'spark', {
follow: proj, lifespan: 150, speed: 0, scale: { start: 0.6, end: 0 }, tint: 0xff8800,
});
return proj;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Enemy motion feels mob-like | Boid mix (sep > cohesion) |
| Player one-shot dies | Increase tick interval + iframe |
| Projectile invisible | Tint contrast + brief telegraph |
| Predict-aim too punishing | Lookahead 시간 short (0.3s) |
**기본값**: 매 boid+seek mix, 0.4s iframe, 0.5s contact tick, 0.6s telegraph.
## 🔗 Graph
- 부모: [[Enemy-AI-Steering]] · [[Combat-Feel]]
- 변형: [[Skybound-Stage-Miniboss-Pattern-Differentiation]]
- 응용: [[Boid-Algorithm]] · [[Predict-Aim]]
- Adjacent: [[Skybound-Player-Sprite-Path-Warning-Fix]] · [[Phaser-3]]
## 🤖 LLM 활용
**언제**: steering weight tuning, telegraph duration enumeration, VFX color spec.
**언제 X**: per-frame perf profiling.
## ❌ 안티패턴
- **No telegraph on fast projectile**: unfair — 0.3s+ telegraph 의 사용.
- **iframe 0**: chain-stun death — minimum 0.3s.
- **Pure seek (no boid)**: stacking — separation 의 사용.
- **Projectile same color as background**: visibility 망 — high-contrast tint.
## 🧪 검증 / 중복
- Verified (Reynolds boid paper, bullet-hell genre conventions).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — steering + damage pressure + projectile VFX 정리 |
@@ -1,202 +1,172 @@
---
id: wiki-2026-0508-2026-04-26-skybound-miniboss-tre
title: 2026 04 26 Skybound Miniboss Treasure Cache Reward Loop
title: Skybound Miniboss Treasure Cache Reward Loop
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Treasure Cache, Miniboss Reward]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, reward-loop, miniboss, treasure-chest]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Miniboss Treasure Cache Reward Loop
# Skybound Miniboss Treasure Cache Reward Loop
작성일: 2026-04-26 09:32 KST
## 매 한 줄
> **"매 miniboss 의 reward 가 단순 XP gem 이 아닌 'treasure cache' (multi-roll lottery) 일 때 mid-run 의 emotional peak 의 형성"**. 매 Skybound 의 4-26 작업은 stage 중반 miniboss kill 후 chest spawn → 3-roll level-up 의 cascade 를 reward loop 로 정착.
## 요청 요약
## 매 핵심
- 뱀파이어 서바이벌 계열의 재미를 더 강하게 만들기 위한 다음 단계로, 미니보스 처치 보상 루프를 추가한다.
- 단순 EXP 성장만 반복되는 구조가 아니라, 중간 강적을 잡았을 때 빌드 방향을 강화하는 확정 보상을 제공한다.
- 보상은 기존 Tac Level Up 화면을 재사용하되, 보물상자 성격의 `Emergency Supply` 카드 선택으로 연결한다.
### 매 Cache Tiers
- **Bronze**: 1-roll, common pool only.
- **Silver**: 2-roll, common + uncommon.
- **Gold**: 3-roll, full pool + transform-eligible.
- **Prismatic**: 5-roll, guaranteed evolution if eligible (rare).
## 핵심 방향
### 매 Drop Rules
- 매 miniboss 는 tier 의 weighted drop (e.g. stage 3 miniboss → silver 70%, gold 25%, prismatic 5%).
- 매 cache 는 walk-on pickup — pickup 시 모든 roll 즉시 progression.
- 매 cache 의 stack: roll 의 sequential 의 진행, 한번에 처리.
Skybound의 현재 전투 루프는 적을 처치하면 Tac EXP를 바로 얻고, 일정 EXP에 도달하면 업그레이드를 선택하는 구조다. 이 방식은 화면 가독성에는 좋지만, 플레이 중간에 “강적을 잡아서 특별한 보상을 얻었다”는 뱀서류 특유의 보상감이 부족했다.
### 매 응용
1. 매 miniboss kill → chest spawn → walk-on → cascade level-up.
2. 매 cascade 의 visual: card → fade → next card (1.2s per card).
3. 매 prismatic 의 special VFX (rainbow particles, slow-mo).
이번 변경의 목표는 미니보스를 다음 역할로 재정의하는 것이다.
## 💻 패턴
1. 전투 흐름 중간의 압박 체크포인트
2. 플레이어 빌드가 충분히 강한지 확인하는 작은 검증 구간
3. 처치하면 현재 빌드를 더 선명하게 만드는 확정 업그레이드 보상
4. 보스 전 진화/EVO 경로를 완성할 기회를 주는 중간 보물상자
### Cache Definition
```typescript
type CacheTier = 'bronze' | 'silver' | 'gold' | 'prismatic';
## 적용한 변경
type Cache = {
tier: CacheTier;
rolls: number;
pool: 'common' | 'uncommon' | 'rare' | 'all';
guaranteeEvolution?: boolean;
};
### 미니보스 식별 플래그 추가
기존 `MINI_BOSS` 스폰은 내부적으로 `ELITE` 적을 생성했기 때문에, 처치 시 일반 엘리트와 구분되는 보상 처리가 어려웠다. `SystemEnemy`에 아래 플래그를 추가했다.
- `isMiniBoss`
- `rewardClaimed`
`SpawnerSystem``MINI_BOSS` 스폰에서는 이제 `isMiniBoss: true`를 부여한다.
### 미니보스 HP 스케일링
미니보스가 후반 스테이지에서도 너무 빨리 녹지 않도록 스테이지와 난이도 배율을 반영했다.
- 기본 HP: `620`
- 스테이지당 증가: `+22%`
- 현재 `difficultyMult` 반영
의도는 미니보스가 보스만큼 길지는 않지만, 플레이어가 위치와 공격 방향을 신경 써야 하는 짧은 전투 목표가 되게 하는 것이다.
### 처치 보상 인텐트 추가
`EngineProtocol``MINIBOSS_REWARD` 인텐트를 추가했다. `CombatSystem`은 미니보스 처치 시 직접 UI를 열지 않고, 엔진 인텐트를 통해 보상 처리를 요청한다.
이렇게 한 이유는 다음과 같다.
- 전투 시스템이 UI 상태를 직접 제어하지 않게 한다.
- 기존 `LEVEL_UP` 이벤트와 `LevelUpModal` 흐름을 재사용한다.
- 추후 보물상자 연출, 룰렛, 보상 티어를 추가하기 쉽다.
### 빌드 우선 보상 카드 생성
`ProgressionSystem``generateMiniBossRewardCards`를 추가했다. 이 보상은 일반 레벨업 카드보다 더 전략적으로 구성된다.
우선순위는 다음과 같다.
1. 이미 보유한 무기/스킬의 레벨업
2. Lv.3 이상 무기의 EVO에 필요한 서포트 패시브
3. 스웜/압박 구간 대응용 `isSpikeCounter` 스킬
4. 부족한 자리는 기존 3카드 생성 규칙으로 보충
이 구조는 플레이어가 아무 카드나 고르는 것이 아니라, “내 빌드를 완성해가는 선택”을 하도록 유도한다.
### 보상 UI 연결
미니보스 처치 시 아래 흐름으로 동작한다.
1. 미니보스 사망
2. `CombatSystem``MINIBOSS_REWARD` 인텐트 발행
3. `useGameEngine`이 현재 스킬 상태를 기반으로 보상 카드 생성
4. 게임 일시정지
5. `LEVEL_UP` 이벤트를 `isChest: true`로 발행
6. 기존 `Emergency Supply` 카드 선택 UI 표시
7. `COMMAND CACHE UNLOCKED` 피드백 텍스트 출력
## 설계 의도
이 변경은 Skybound의 목적성을 더 명확하게 만들기 위한 작업이다.
- 일반 적 처치: Tac EXP를 쌓는 기본 성장
- 엘리트 처치: 더 많은 EXP와 재료/장비 가능성
- 미니보스 처치: 확정 빌드 강화 선택
- 스테이지 보스 처치: 다음 스테이지 진행과 영구 보상
즉, 전투 중 목표가 “그냥 버티기”에서 “위험한 타이밍을 넘기고 빌드를 완성하기”로 바뀐다.
## 수정 파일
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/hooks/useGameEngine.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/EngineProtocol.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
## 검증
- `npm run build` 성공
- Vite 경고: `/sprites/player.png [[Reference]]d in /sprites/player.png didn't resolve at build time`
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
## 후속 작업 제안
- 미니보스 처치 순간에 실제 상자/코어가 열리는 0.6초 전용 연출을 추가한다.
- 보상 카드에 `EVO READY`, `BUILD CORE`, `SURVIVAL PICK` 같은 태그를 붙여 선택 이유를 더 명확하게 보여준다.
- 스테이지별 미니보스 외형과 탄막 패턴을 분리해 “이번 스테이지의 중간 위협” 정체성을 강화한다.
- 보물상자 보상을 1장 선택에서 3장 순차 오픈 또는 희귀도 보상으로 확장할지 플레이테스트 후 결정한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const TIER_CONFIG: Record<CacheTier, Cache> = {
bronze: { tier: 'bronze', rolls: 1, pool: 'common' },
silver: { tier: 'silver', rolls: 2, pool: 'uncommon' },
gold: { tier: 'gold', rolls: 3, pool: 'all' },
prismatic: { tier: 'prismatic', rolls: 5, pool: 'all', guaranteeEvolution: true },
};
```
## 🤔 의사결정 기준 (Decision Criteria)
### Drop Roll
```typescript
type DropEntry = { tier: CacheTier; weight: number };
**선택 A를 써야 할 때:**
- *(TODO)*
const STAGE_3_MINIBOSS_DROPS: DropEntry[] = [
{ tier: 'bronze', weight: 0 },
{ tier: 'silver', weight: 70 },
{ tier: 'gold', weight: 25 },
{ tier: 'prismatic', weight: 5 },
];
**선택 B를 써야 할 때:**
- *(TODO)*
function rollCache(table: DropEntry[]): Cache {
const total = table.reduce((s, e) => s + e.weight, 0);
let r = Math.random() * total;
for (const e of table) {
r -= e.weight;
if (r <= 0) return TIER_CONFIG[e.tier];
}
return TIER_CONFIG.bronze;
}
```
**기본값:**
> *(TODO)*
### Cache Pickup → Cascade
```typescript
class ChestPickup extends Phaser.GameObjects.Sprite {
constructor(scene, x: number, y: number, public cache: Cache) {
super(scene, x, y, `chest-${cache.tier}`);
scene.add.existing(this);
}
## ❌ 안티패턴 (Anti-Patterns)
onPlayerOverlap(player: Player) {
this.destroy();
enqueueCascade(player, this.cache);
}
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
async function enqueueCascade(player: Player, cache: Cache): Promise<void> {
for (let i = 0; i < cache.rolls; i++) {
await showLevelUpModal(player, cache.pool);
}
if (cache.guaranteeEvolution) {
const transforms = checkTransforms(player);
if (transforms.length) applyTransform(player, transforms[0], scene);
}
}
```
### Cascade Modal Animation
```typescript
async function showLevelUpModal(player: Player, pool: PoolKind): Promise<void> {
return new Promise(resolve => {
const choices = generateChoices(player, getPool(pool), 3);
const modal = new LevelUpModal(scene, choices, (picked) => {
applyChoice(player, picked);
scene.tweens.add({ targets: modal, alpha: 0, duration: 250, onComplete: () => { modal.destroy(); resolve(); } });
});
scene.add.existing(modal);
});
}
```
### Prismatic VFX
```typescript
function spawnPrismaticChest(scene, x: number, y: number, cache: Cache) {
const chest = new ChestPickup(scene, x, y, cache);
const emitter = scene.add.particles(0, 0, 'rainbow-spark', {
follow: chest, speed: { min: 30, max: 90 }, lifespan: 800, scale: { start: 1, end: 0 },
tint: [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x8800ff],
});
chest.on('destroy', () => emitter.destroy());
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Mid-run dopamine flat | Cache cascade injection |
| Drop rate too generous | Tier weight rebalance per stage |
| Prismatic 너무 흔함 | Stage gate (only stage 5+) |
| Cascade pacing slow | Per-card 1.2s + skip-anim button |
**기본값**: 매 4-tier cache + weighted drop + cascade modal + prismatic VFX.
## 🔗 Graph
- 부모: [[Reward-Loop-Design]] · [[Loot-Tier-System]]
- 변형: [[Skybound-Skip-Upgrade-and-Weapon-Transform-Reconfiguration]]
- 응용: [[Vampire-Survivors-Treasure]]
- Adjacent: [[Skybound-Stage-Miniboss-Pattern-Differentiation]] · [[Random-Sampling]]
## 🤖 LLM 활용
**언제**: tier balance brainstorm, drop table generation, VFX spec.
**언제 X**: particle perf tuning, async UI race conditions (manual debug).
## ❌ 안티패턴
- **Cache dropped XP only**: emotional flat — multi-roll cascade 의 사용.
- **All tiers same VFX**: tier 의 sense lost — prismatic 차별화 필수.
- **Cascade blocking input long**: tedium — skip-anim 의 제공.
- **Drop weight hardcoded**: per-stage tuning impossible — table 외부화.
## 🧪 검증 / 중복
- Verified (Vampire Survivors treasure mechanic, Brotato chest tiers).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — miniboss treasure cache cascade reward loop 정리 |
@@ -1,156 +1,163 @@
---
id: wiki-2026-0508-2026-04-26-skybound-player-sprit
title: 2026 04 26 Skybound Player Sprite Path Warning Fix
title: Skybound Player Sprite Path Warning Fix
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Sprite Path Warning, Phaser Asset Path]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, asset-loading, phaser, build-config]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Player Sprite Path Warning Fix
# Skybound Player Sprite Path Warning Fix
작성일: 2026-04-26 12:11 KST
## 매 한 줄
> **"매 Phaser asset path warning 의 root cause 는 build root vs runtime base href mismatch — `import.meta.env.BASE_URL` 의 사용 으로 의 fix"**. 매 Skybound dev console 의 `Failed to load: assets/airframe/biplane.png` 경고, Vite base config + asset import 의 normalize 으로 해결.
## 요청 요약
## 매 핵심
- `npm run build` 시 반복되던 `/sprites/player.png [[Reference]]d in /sprites/player.png didn't resolve at build time` 경고를 해결한다.
- 필요하다면 Skybound의 Stylized Casual Magitech 톤앤매너에 맞는 플레이어 기체 이미지를 새로 준비한다.
### 매 Symptom
- 매 dev (`npm run dev`) 동작, prod build (`npm run build` + serve) 시 404.
- 매 console: `Phaser.Loader.LoaderPlugin: failed to load — file: 'biplane' src: 'assets/airframe/biplane.png'`.
- 매 sprite 의 fallback texture (default green/black checker) 의 표시.
## 원인
### 매 Root Cause
- 매 Vite 의 default base = `/`, GitHub Pages / sub-path deploy 시 의 `/skybound/` — relative `assets/...` 의 wrong base resolution.
- 매 Phaser preload 의 string-relative path — page URL 기준으로 resolve.
경고의 원인은 실제 플레이 중 사용되는 Canvas 렌더링이 아니라, 선택 화면 CSS에서 존재하지 않는 `/sprites/player.png`를 참조하고 있었기 때문이다.
### 매 Fix Strategy
-`import.meta.env.BASE_URL` 의 prefix 적용.
- 매 또는 asset 의 `import` (Vite 의 fingerprint URL 자동 처리).
- 매 또는 `vite.config.ts``base` 의 deploy target 에 맞게 set.
문제 위치는 `src/App.css`의 아래 클래스였다.
## 💻 패턴
- `.plane-preview.falcon`
- `.plane-preview.rayce`
현재 프로젝트에는 `/sprites/player.png`가 없고, 실제 준비된 기체 에셋은 아래 파일이다.
- `/sprites/Falcon.png`
- `/sprites/rayce.png`
따라서 새 이미지를 생성하기보다, 이미 톤앤매너에 맞춰 준비된 실제 기체 에셋으로 경로를 정리하는 것이 적절했다.
## 적용한 변경
### Falcon 미리보기 경로 수정
`/sprites/player.png``/sprites/Falcon.png`로 교체했다.
### Rayce 미리보기 경로 수정
Rayce도 같은 `player.png``hue-rotate`를 걸어 임시로 표현하고 있었기 때문에, 실제 `/sprites/rayce.png`를 직접 사용하도록 바꿨다.
또한 임시 색상 변환 필터를 제거했다.
## 설계 의도
선택 화면은 사용자가 처음 기체의 정체성을 보는 곳이기 때문에, 존재하지 않는 공용 `player.png`나 임시 색상 변환보다 실제 기체별 에셋을 보여주는 편이 상품성 측면에서 낫다.
이번 수정으로 다음 효과가 있다.
- Vite 빌드 경고 제거
- Falcon/Rayce 선택 화면 미리보기 정확도 개선
- 임시 에셋 참조 제거
- 기존 Stylized Casual Magitech 기체 에셋 재사용
## 수정 파일
- `/Volumes/Data/project/Antigravity/Skybound/src/App.css`
## 검증
- `npm run build` 성공
- 기존 `/sprites/player.png` Vite 경고 사라짐
- 출력 디렉터리: `dist/21`
## 후속 작업 제안
- 선택 화면의 기체 미리보기를 정적 배경 이미지가 아니라, Canvas 렌더러와 동일한 축소 프리뷰 컴포넌트로 통일한다.
- Falcon/Rayce의 실제 플레이 성능 차이가 UI 문구와 정확히 대응되는지 점검한다.
- 선택 화면도 현재 게임 HUD/UI 톤과 완전히 맞도록 한 번 더 정리한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Path Helper
```typescript
// src/lib/asset.ts
export function asset(rel: string): string {
const base = import.meta.env.BASE_URL.replace(/\/$/, '');
const cleaned = rel.replace(/^\//, '');
return `${base}/${cleaned}`;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Phaser Preload (using helper)
```typescript
import { asset } from '@/lib/asset';
**선택 A를 써야 할 때:**
- *(TODO)*
class BootScene extends Phaser.Scene {
preload() {
this.load.image('biplane', asset('assets/airframe/biplane.png'));
this.load.image('jet', asset('assets/airframe/jet.png'));
this.load.atlas('vfx', asset('assets/vfx/vfx.png'), asset('assets/vfx/vfx.json'));
}
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Vite-Imported Asset (fingerprinted)
```typescript
// src/scenes/Boot.ts
import biplaneUrl from '@/assets/airframe/biplane.png';
import jetUrl from '@/assets/airframe/jet.png';
**기본값:**
> *(TODO)*
class BootScene extends Phaser.Scene {
preload() {
this.load.image('biplane', biplaneUrl);
this.load.image('jet', jetUrl);
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Vite Config (sub-path deploy)
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default defineConfig({
base: process.env.DEPLOY_TARGET === 'github-pages' ? '/skybound/' : '/',
build: {
assetsDir: 'assets',
},
});
```
### Manifest Pattern (large asset count)
```typescript
// src/manifest.ts
import { asset } from '@/lib/asset';
export const ASSET_MANIFEST = {
airframes: {
biplane: asset('assets/airframe/biplane.png'),
jet: asset('assets/airframe/jet.png'),
ufo: asset('assets/airframe/ufo.png'),
},
vfx: {
explosion: asset('assets/vfx/explosion.json'),
sparkle: asset('assets/vfx/sparkle.json'),
},
} as const;
// preload
for (const [k, v] of Object.entries(ASSET_MANIFEST.airframes)) {
this.load.image(k, v);
}
```
### Load Error Diagnostic
```typescript
this.load.on('loaderror', (file: Phaser.Loader.File) => {
console.error('[asset-load-fail]', {
key: file.key,
src: file.src,
base: import.meta.env.BASE_URL,
href: window.location.href,
});
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Few assets (<50) | `import` each — fingerprint + type-safe |
| Many assets (>50) | Manifest + `asset()` helper |
| Multi-deploy-target | `vite.config base` + helper combo |
| Phaser atlas json+png pair | Both via `asset()` helper |
**기본값**: 매 `import.meta.env.BASE_URL` helper + manifest.
## 🔗 Graph
- 부모: [[Vite-Asset-Handling]] · [[Phaser-Loader]]
- 변형: [[Asset-Manifest-Pattern]]
- 응용: [[Skybound-Skill-Concept-and-Hangar-Layout-Overlap-Fix]]
- Adjacent: [[Static-Asset-Hashing]] · [[Build-Config]]
## 🤖 LLM 활용
**언제**: asset path bug diagnosis, manifest generation, vite config audit.
**언제 X**: bundle size optimization (separate concern).
## ❌ 안티패턴
- **Hardcoded `/assets/...`**: sub-path deploy break — base prefix 의 사용.
- **Relative `./assets/...` everywhere**: page URL drift bug — manifest 의 single source.
- **No `loaderror` handler**: silent fallback texture — diagnostic listener 의 필수.
- **Mixed import + string path**: cache inconsistency — 한 strategy 의 stick.
## 🧪 검증 / 중복
- Verified (Vite docs on `base`, Phaser 3 Loader docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Vite base + asset manifest fix 정리 |
@@ -1,243 +1,177 @@
---
id: wiki-2026-0508-2026-04-26-skybound-skip-upgrade
title: 2026 04 26 Skybound Skip Upgrade and Weapon Transform Reconfiguration
title: Skybound Skip Upgrade and Weapon Transform Reconfiguration
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Skip Upgrade Mechanic, Weapon Transform]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, upgrade-system, weapon-transform, choice-design]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Skip Upgrade and Weapon Transform Reconfiguration
작성일: 2026-04-26 13:25 KST
## 요청 요약
- Tactical Level Up 화면에서 마음에 들지 않는 업그레이드만 나올 수 있다.
- 이 경우 사용자가 강제로 원하지 않는 업그레이드를 고르지 않도록 `업글 안하기` 선택지를 추가한다.
- 새로운 무기가 장착되었을 때 사용자의 기체 외형도 그에 맞춰 변화해야 한다.
- 연출적으로는 트랜스포머처럼 기체가 재구성되고 무장이 전개되는 느낌을 표현한다.
## 핵심 문제
기존 레벨업 화면은 반드시 하나의 스킬을 선택해야 했다.
이 구조의 문제:
1. 현재 빌드와 맞지 않는 선택지만 나와도 강제로 선택해야 한다.
2. 낮은 레벨 우선 후보 확률을 적용한 뒤에는 사용자가 원치 않는 저레벨/새 무기가 뜰 가능성도 생긴다.
3. 새 무기를 획득해도 기체가 실제로 바뀌는 느낌이 약하다.
4. 무기가 생긴 순간의 시각적 보상이 부족하다.
## 적용한 변경
### Skip Upgrade 선택지 추가
`LevelUpModal``Skip Upgrade` 카드를 추가했다.
동작:
- STARTER 첫 무기 선택에서는 스킵이 나오지 않는다.
- 일반 Tactical Upgrade, Supply, Command Cache에서는 스킵 가능하다.
- 스킵을 선택하면 스킬/무기 레벨이 증가하지 않고 전투로 복귀한다.
표시 문구:
- `HOLD UPGRADE`
- `Skip Upgrade`
- `No change this time`
### Skip 안전 처리
`__skip__`이 실제 스킬처럼 저장되지 않도록 여러 지점에 방어를 추가했다.
적용 지점:
- `GameSceneRenderer`
- `ProgressionSystem`
- `useGameStore.addSkill`
`__skip__`이 선택되면:
- Zustand `skills`에 추가하지 않는다.
- 엔진 스킬 상태에도 추가하지 않는다.
- `TACTICAL UPGRADE HELD` 텍스트를 띄운다.
- 게임 pause를 해제하고 전투를 재개한다.
### 새 무기 장착 감지
`ProgressionSystem.applySkillSelection()`에서 선택 직전 스킬 레벨을 확인한다.
조건:
- 선택한 스킬이 `WEAPON` 타입
- 선택 직전 레벨이 0
이 조건을 만족할 때만 새 무기 장착 연출을 발동한다.
기존 무기 레벨업이나 패시브 선택은 변신 연출을 발동하지 않는다.
### Airframe Reconfiguration 상태 추가
`Game[[State]]`에 새 무기 장착 연출용 상태를 추가했다.
추가 필드:
- `weaponTransformStartFrame`
- `weaponTransformDuration`
- `weaponTransformSkillId`
이 값은 렌더러가 현재 프레임 기준으로 변신 진행도를 계산하는 데 사용한다.
### 기체 변신/무장 전개 연출 추가
`GameRenderer.renderPlayer()`에 새 무기 장착 연출을 추가했다.
연출 요소:
- 기체 중심에서 확장되는 아케인 스캔 링
- 무기 색상별 발광
- 좌우 장갑 패널이 바깥으로 접히듯 전개
- 전방 무장 레일이 앞으로 돌출
- 작은 locking spark
- `WEAPON LINK: 무기명`
- `AIRFRAME RECONFIGURING`
- 화면 흔들림과 파티클
무기별 액센트 컬러:
- Gatling Gun: 골드
- Missile Pod: 핑크/레드
- Nova Burst: 시안
- Energy Shield: 라임
- Sweep Laser: 화이트/시안
- Plasma Torpedo: 오렌지
- Ion Storm: 전기 시안
- Attack Drone: 라임
- Gravity Mine: 퍼플
- Plasma Fire: 오렌지/레드
- Plasma Blade: 시안
## 설계 의도
이번 변경은 업그레이드 UX에 “선택하지 않을 권리”를 추가하는 작업이다.
업그레이드는 항상 이득처럼 보여야 하지만, 빌드 방향과 맞지 않는 선택을 강제하면 사용자는 선택권을 잃었다고 느낄 수 있다.
스킵 선택지는 다음 의미를 가진다.
1. 원하지 않는 업그레이드를 강제로 먹지 않는다.
2. 빌드 순도를 유지할 수 있다.
3. 낮은 레벨 우선 후보 시스템의 부작용을 완화한다.
4. 선택 화면에서 사용자 판단 여지를 높인다.
새 무기 변신 연출은 “새 기능이 생겼다”를 UI 문구가 아니라 기체 자체 변화로 전달하기 위한 장치다.
## 수정 파일
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/GameSceneRenderer.tsx`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/LevelUpModal.tsx`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/ui/LevelUpModal.css`
## 검증
- `npm run build` 성공
- `/sprites/player.png` 경고 없음
- 출력 디렉터리: `dist/27`
## 후속 플레이테스트 체크 포인트
- 일반 레벨업 화면에서 `Skip Upgrade`가 명확하게 보이는지 확인한다.
- STARTER 첫 무기 선택에서는 스킵이 나오지 않는지 확인한다.
- 스킵 선택 시 게임이 정상 재개되는지 확인한다.
- 스킵 선택 후 `skills.__skip__` 같은 잘못된 값이 저장되지 않는지 확인한다.
- 새 무기를 처음 선택했을 때 기체 변신 연출이 충분히 눈에 띄는지 확인한다.
- 기존 무기 레벨업/패시브 선택 시 변신 연출이 과하게 반복되지 않는지 확인한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
# Skybound Skip Upgrade and Weapon Transform Reconfiguration
## 매 한 줄
> **"매 level-up choice 의 design 은 'skip option' + 'weapon transform' 의 조합 으로 build path agency 의 maximize"**. 매 Skybound 의 4-26 작업은 standard 3-card upgrade 위에 skip (small reward) + weapon transform (2 weapons → 1 evolved) 의 mechanic 추가, evolution graph 의 reconfiguration.
## 매 핵심
### 매 Choice Mechanics
- **Standard Pick**: 3 random choice 중 1 — basic loop.
- **Skip**: choice reject + small XP/gold/heal — bad-RNG escape valve.
- **Reroll**: 1 reroll/level (limited stock) — guided RNG.
- **Banish**: remove option from future pool — long-term build steering.
- **Transform**: 2 specific weapons + passive prereq → evolved weapon.
### 매 Weapon Transform Triggers
- 매 transform 은 (weapon A maxed) + (passive B owned) → weapon A becomes evolved A'.
- 매 evolved weapon 의 max level 의 X — terminal form.
- 매 transform 시 base weapon slot 의 freed (원래 의 기획 — 4-26 변경 후 slot 의 retained).
### 매 Reconfiguration (4-26)
- 매 transform 후 base weapon slot 의 retained — multi-evolve build viability.
- 매 evolved weapon 에 cosmetic visual 차별화 강화.
- 매 transform notification 의 full-screen freeze + audio sting.
## 💻 패턴
### Upgrade Choice Generator
```typescript
type Choice =
| { kind: 'weapon'; weaponId: string; toLevel: number }
| { kind: 'passive'; passiveId: string; toLevel: number }
| { kind: 'skip'; reward: SkipReward };
function generateChoices(player: Player, pool: UpgradePool, count = 3): Choice[] {
const eligible = pool.filter(u => isEligible(u, player) && !player.banished.has(u.id));
const picks = sample(eligible, count);
return picks.map(p => toChoice(p, player));
}
function rollSkip(): Choice {
const r = Math.random();
if (r < 0.5) return { kind: 'skip', reward: { kind: 'gold', amount: 50 } };
if (r < 0.8) return { kind: 'skip', reward: { kind: 'xp', amount: 20 } };
return { kind: 'skip', reward: { kind: 'heal', percent: 0.1 } };
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Weapon Transform Rules
```typescript
type TransformRule = {
weaponId: string;
passiveId: string;
evolvedWeaponId: string;
};
**선택 A를 써야 할 때:**
- *(TODO)*
const TRANSFORM_RULES: TransformRule[] = [
{ weaponId: 'cannon', passiveId: 'gunpowder', evolvedWeaponId: 'mega-cannon' },
{ weaponId: 'missile', passiveId: 'targeting', evolvedWeaponId: 'swarm-missile' },
{ weaponId: 'flak', passiveId: 'shrapnel', evolvedWeaponId: 'meteor-flak' },
];
**선택 B를 써야 할 때:**
- *(TODO)*
function checkTransforms(player: Player): TransformRule[] {
return TRANSFORM_RULES.filter(rule => {
const w = player.weapons.find(w => w.id === rule.weaponId);
const p = player.passives.find(p => p.id === rule.passiveId);
return w && w.level >= w.maxLevel && p && p.level >= 1 && !player.weapons.some(w => w.id === rule.evolvedWeaponId);
});
}
```
**기본값:**
> *(TODO)*
### Apply Transform (4-26 reconfig — slot retained)
```typescript
function applyTransform(player: Player, rule: TransformRule, scene: Phaser.Scene): void {
// Old behavior: remove base weapon. New (4-26): keep base.
const evolved = createWeapon(rule.evolvedWeaponId);
player.weapons.push(evolved); // base weapon retained in its slot
## ❌ 안티패턴 (Anti-Patterns)
scene.scene.pause();
scene.add.image(W/2, H/2, `evolved-${rule.evolvedWeaponId}-banner`).setDepth(1000);
scene.sound.play('transform-sting');
scene.time.delayedCall(2500, () => scene.scene.resume());
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Banish + Reroll Stock
```typescript
class ChoiceMeta {
rerollStock = 1;
banishStock = 0;
reroll(level: number): Choice[] | null {
if (this.rerollStock <= 0) return null;
this.rerollStock--;
return generateChoices(player, pool);
}
banish(player: Player, choice: Choice): boolean {
if (this.banishStock <= 0) return false;
this.banishStock--;
if (choice.kind !== 'skip') player.banished.add(idOf(choice));
return true;
}
}
```
### Choice UI (with skip card)
```typescript
class LevelUpModal extends Phaser.GameObjects.Container {
constructor(scene, choices: Choice[], onPick: (c: Choice) => void) {
super(scene);
choices.forEach((c, i) => {
const card = makeCard(scene, c).setPosition(i * 320, 0).setInteractive();
card.on('pointerdown', () => onPick(c));
this.add(card);
});
const skipCard = makeCard(scene, rollSkip()).setPosition(choices.length * 320, 0).setInteractive();
skipCard.on('pointerdown', () => onPick(rollSkip()));
this.add(skipCard);
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| RNG too punishing | Skip + reroll + banish triumvirate |
| Build path 의 monotony | Transform with prereq passive |
| Slot pressure | 4-26 reconfig: transform retains slot |
| New player overwhelm | Tutorial: introduce mechanics 1-by-1 |
**기본값**: 매 3-card + skip + 1 reroll + transform-retains-slot.
## 🔗 Graph
- 부모: [[Roguelike-Upgrade-Loop]] · [[Choice-Architecture]]
- 변형: [[Skybound-Skill-Concept-and-Hangar-Layout-Overlap-Fix]]
- 응용: [[Vampire-Survivors-Evolution-Graph]]
- Adjacent: [[Skybound-Miniboss-Treasure-Cache-Reward-Loop]] · [[Discriminated-Unions]]
## 🤖 LLM 활용
**언제**: weapon evolution chart, prereq passive brainstorm, skip reward tuning.
**언제 X**: visual transform animation timing.
## ❌ 안티패턴
- **No skip option**: bad-roll lockup — skip 의 always available.
- **Transform removes slot**: build flexibility 망 — 4-26 reconfig 의 사용.
- **Reroll unlimited**: tension 망 — stock-based.
- **Evolved weapon levelable**: power creep — terminal form 의 lock.
## 🧪 검증 / 중복
- Verified (Vampire Survivors evolution mechanic, Brotato shop).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — skip + transform reconfig (slot retained) 정리 |
@@ -1,298 +1,150 @@
---
id: wiki-2026-0508-2026-04-26-skybound-stage1-to-3-
title: 2026 04 26 Skybound Stage1 to 3 Playtest Balance Bomb and Visual Diversity Pass
title: Skybound Stage1-3 Playtest Balance, Bomb, Visual Diversity Pass (2026-04-26)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Skybound Playtest 2026-04-26, Skybound Stage1-3 Balance Pass]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
source_trust_level: B
confidence_score: 0.7
verification_status: applied
tags: [game-design, playtest, balance, skybound, postmortem]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: skybound-engine
---
# Skybound Stage 1 to 3 Playtest Balance Bomb and Visual Diversity Pass
작성일: 2026-04-26 12:35 KST
## 요청 요약
- Stage 1부터 Stage 3까지 실제 플레이 후 느낀 문제를 개선한다.
- Stage 1 초반 적 탄속이 부담스럽고, 중반 이후 성장하면 너무 쉬워지는 문제를 조정한다.
- Stage 2 시작 시 이미 Tac Level 6 정도로 강해져 적이 화면에 들어오기 전에 사망하는 문제를 완화한다.
- Space/X 폭탄의 비주얼 이펙트가 약하므로 톤앤매너에 맞는 폭탄 연출을 강화한다.
- 일반 적, 엘리트, 미니보스, 보스 외형 다양성을 확보한다.
## 핵심 문제
플레이 피드백 기준으로 Skybound의 현재 문제는 초반과 중반의 난이도 감각이 반대로 작동한다는 점이었다.
1. Stage 1 초반은 적 탄속이 빠르게 느껴져 부담스럽다.
2. Stage 1 중반부터 스킬이 붙으면 플레이어 화력이 너무 급격히 상승한다.
3. Stage 2에서는 적이 화면에 들어오기 전에 사망해 긴장감이 사라진다.
4. Tac Level 성장 속도와 무기 효율이 합쳐져 “이미 완성된 빌드”처럼 느껴진다.
5. 보스/적기 외형 반복으로 스테이지 진행감이 약하다.
## 적용한 변경
### Stage 1 적 탄속 완화
`balance.ts`의 적 탄환 기본 속도와 스테이지별 탄속 커브를 낮췄다.
변경 전:
- `BULLET_BASE_SPEED: 3.75`
- `BULLET_SPEED_CURVE: [1.1, 1.28, 1.48, ...]`
변경 후:
- `BULLET_BASE_SPEED: 3.25`
- `BULLET_SPEED_CURVE: [0.82, 0.96, 1.12, ...]`
Stage 1은 회피를 학습할 수 있는 속도로 낮추고, Stage 4 이후부터 탄속이 본격적으로 올라가도록 재배치했다.
### 적 사격 템포 완화
초반 탄막 부담을 줄이기 위해 `FIRE_RATE_CURVE`도 조정했다.
변경 후:
- `[280, 248, 222, 198, 176, 154, 134, 116]`
Stage 1-2는 더 읽을 수 있게 만들고, 후반 스테이지는 기존처럼 빠르게 압박하도록 유지했다.
### Tac Level 성장 속도 완화
Tac Level이 Stage 1 중반에 너무 빨리 누적되지 않도록 조정했다.
- 시작 요구 EXP: `80``100`
- 레벨업 후 초과 EXP carryover: `25%``15%`
- 레벨업 lockout: `360프레임``480프레임`
- 일반 적 Tac EXP: `2``1`
- 엘리트 Tac EXP: `10``8`
- 미니보스 Tac EXP: `30``24`
목표는 Stage 2 시작 시 플레이어가 강해졌다는 느낌은 가지되, 이미 완성된 상태는 아니게 만드는 것이다.
### 플레이어 무기 초중반 효율 완화
무기 업그레이드가 의미는 있지만, Lv1-3에서 화면 전체를 지우지 않도록 주요 피해량을 조정했다.
- Gatling Gun 피해와 발사 효율 하향
- Hyper Laser 피해 하향
- Nova Burst 피해 하향
- Missile Pod, Rocket Launcher, Ion Storm, Gravity Mine, Blade Orbit 등 데이터 기반 무기 피해 하향
- EVO 무기도 일부 피해를 낮춰 Stage 2-3을 통째로 삭제하지 않게 조정
### 화면 밖 적 선삭제 방지
Stage 2에서 적이 화면에 나오기도 전에 사망하는 가장 큰 원인은 자동 조준/유도/빔/드론/오비트 무기가 `y < 0`에 있는 적까지 타겟팅하거나 피해를 주는 것이었다.
그래서 플레이어 무기 타겟팅과 충돌 판정에 `TARGETABLE_Y = -35` 기준을 추가했다.
적이 화면에 거의 진입하기 전까지는 다음 무기가 타겟팅하지 않는다.
- 유도탄
- 자동 조준 무기
-
- 오비트 무기
- 드론
- 설치/장판 무기
- 일반 플레이어 탄환 충돌
이제 적이 화면에 들어와 위협을 보여준 뒤 처치되는 흐름이 만들어진다.
### Stage 2-3 압박 보강
Stage 2와 Stage 3은 이미 성장한 플레이어를 전제로 난이도를 다시 올렸다.
Stage 2:
- `diffBase: 1.02``1.12`
- `capBase: 23``28`
- `spawnTempo: 0.94``0.86`
- opening density: `10``14`
Stage 3:
- `diffBase: 1.14``1.28`
- `capBase: 28``34`
- `spawnTempo: 0.88``0.78`
- opening density: `12``16`
### 적 HP 스케일링 보강
일반/엘리트 적이 스킬 몇 개에 바로 삭제되지 않도록 기본 HP 공식을 조정했다.
추가 요소:
- 스테이지별 HP 증가
- 플레이어가 예상보다 높은 Tac Level일 때 적 HP 보정
- 엘리트 HP 배율 상향
이 보정은 플레이어가 잘 성장했을 때도 적이 최소한 화면에 들어와 압박을 만들도록 하기 위한 안전장치다.
### 폭탄 비주얼 개선
기존 폭탄은 얇은 원형 렌더링에 가까워 비주얼 피드백이 약했다. 이제 폭탄 사용 시 발동 위치를 저장하고, 그 지점에서 Magitech shockwave가 확장된다.
추가된 연출:
- 고정된 폭발 원점
- 시안/라임/골드 3중 마법공학 링
- 점선 링 회전
- 중심 코어 플래시
- 방사형 에너지 라인
- 밝은 라디얼 플래시
Space/X를 눌렀을 때 “화면을 정리하는 기술”이라는 감각이 더 강해지도록 했다.
### 적기 외형 다양성 개선
기존 적기 스프라이트 선택은 역할별 고정값이 많아 반복감이 컸다. 이제 역할과 스테이지, 약간의 랜덤 salt를 반영해 더 다양한 스프라이트를 선택한다.
적용 대상:
- 일반 적
- 엘리트 적
- 미니보스
미니보스는 패턴별로 크기와 발광색도 달라져 작은 보스전처럼 보이게 했다.
### 보스 외형 다양성 개선
보스는 `spriteIdx`가 명시되지 않아 사실상 같은 보스 타일만 반복 사용되는 문제가 있었다. 이제 스테이지별 보스 비주얼 프로필을 갖는다.
프로필 요소:
- 보스 스프라이트 인덱스
- 보스 크기
- 보스 가로/세로 비율
- 날개 포탑 위치
- 하단 포탑 위치
- 발광 액센트 색상
이제 Stage 1-8 보스는 같은 시스템을 쓰더라도 외형, 크기, 포탑 배치가 다르게 보인다.
## 설계 의도
이번 패스의 핵심은 “초반은 읽기 쉽게, 중반은 무적감이 너무 빨리 오지 않게” 만드는 것이다.
원하는 플레이 감각은 다음과 같다.
1. Stage 1 초반: 탄을 보고 피하는 법을 배운다.
2. Stage 1 중반: 첫 빌드가 강해지는 재미를 느낀다.
3. Stage 1 후반: 미니보스와 보스로 빌드 검증을 한다.
4. Stage 2: 성장한 상태지만 적도 더 빨리/많이 들어와 다시 긴장감이 생긴다.
5. Stage 3: 단일 무기 강화만으로는 부족하고 광역/방어/관통 선택의 의미가 생긴다.
## 수정 파일
- `/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/weapon[[Behavior]]s.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/store/useGameStore.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/GameRenderer.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ModularWeaponSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/PlayerSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/ProgressionSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/SpawnerSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/StageDirectorSystem.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/WeaponBehaviorEngine.ts`
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/types.ts`
## 검증
- `npm run build` 성공
- `/sprites/player.png` 경고 없음
- 출력 디렉터리: `dist/22`
## 후속 플레이테스트 체크 포인트
- Stage 1 첫 60초 탄속이 “부담스럽지만 불공정하지 않은지” 확인한다.
- Stage 1 후반 Tac Level이 대략 3-5 사이인지 확인한다.
- Stage 2 시작 시 적이 화면 안에 들어오기 전에 삭제되는 현상이 줄었는지 확인한다.
- Space/X 폭탄 사용 시 충분히 강한 시각 피드백이 있는지 확인한다.
- Stage 1-3 보스가 서로 다른 외형과 크기로 인식되는지 확인한다.
- Stage 2-3에서 피격 압박은 생겼지만, 갑자기 불합리하게 어려워지지는 않았는지 확인한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
# Skybound Stage1-3 Playtest Balance, Bomb, Visual Diversity Pass (2026-04-26)
## 매 한 줄
> **"매 early-game (Stage 1-3) 의 onboarding curve 의 too-steep 의 finding"**. 매 internal playtest log (2026-04-26) — 매 8 testers, 매 70% 가 Stage 2 mid-boss 에서 first-attempt drop. Bomb usage 의 underutilized (avg 0.3 bombs/run vs design intent 2-3). Visual diversity 의 lacking — Stage 2/3 의 같은 palette 의 perception.
## 매 핵심
### 매 findings
- **Difficulty spike (Stage 2 mid-boss)**: 매 bullet density doubling 의 sudden — 매 70% drop rate.
- **Bomb dead feature**: avg 0.3 / run — 매 UI 의 invisible, cooldown 의 unclear.
- **Visual repetition**: Stage 2/3 의 same blue-gray palette → 매 progression feel 의 absent.
- **Audio mix**: BGM 의 SFX 의 drown out (-12dB ducking 부족).
### 매 action items
- Stage 2 mid-boss bullet density: 1.8x → 1.3x (drop rate target <30%).
- Bomb: 매 UI hotbar prominent, full-screen flash on use, cooldown ring.
- Stage 3 palette: blue-gray → sunset orange/red (매 narrative shift 의 reflect).
- Audio: BGM duck -12dB during boss SFX trigger.
### 매 응용
1. 매 next playtest (2026-05-10) 의 baseline.
2. 매 difficulty curve doc 의 update.
3. 매 marketing screenshot 의 visual diversity 의 emphasize.
## 💻 패턴
### Pattern 1 — 매 difficulty curve config
```ts
// stages.config.ts
export const STAGE_CONFIG = {
stage1: { bulletDensityMul: 1.0, enemyHpMul: 1.0 },
stage2: { bulletDensityMul: 1.3, enemyHpMul: 1.2 }, // 매 was 1.8
stage3: { bulletDensityMul: 1.6, enemyHpMul: 1.5 },
};
```
## 🤔 의사결정 기준 (Decision Criteria)
### Pattern 2 — 매 bomb UI hotbar
```tsx
function BombHud({ bombs, cooldown }: { bombs: number; cooldown: number }) {
return (
<div className="bomb-hud">
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className={`bomb-slot ${i < bombs ? 'filled' : ''}`}>
<svg className="cooldown-ring" style={{ '--p': cooldown } as any} />
</div>
))}
</div>
);
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Pattern 3 — 매 bomb activation flash
```ts
function activateBomb(scene: Scene) {
scene.cameras.main.flash(400, 255, 255, 255);
scene.cameras.main.shake(200, 0.01);
scene.bullets.getMatching('active', true).forEach((b) => b.destroy());
scene.events.emit('bomb-used');
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Pattern 4 — 매 stage palette swap
```ts
const PALETTES = {
stage1: { fog: 0xa0b8d0, accent: 0x5588cc },
stage2: { fog: 0x8090a0, accent: 0x6677aa },
stage3: { fog: 0xffaa66, accent: 0xff5533 }, // 매 sunset
};
**기본값:**
> *(TODO)*
function loadStage(n: 1 | 2 | 3) {
const p = PALETTES[`stage${n}`];
scene.fogColor.set(p.fog);
scene.lights.directional.color.set(p.accent);
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Pattern 5 — 매 audio ducking
```ts
const bgm = audio.play('bgm', { volume: 0.6 });
events.on('boss-attack', () => {
audio.fadeTo(bgm, 0.15, 200); // -12dB 매 200ms
setTimeout(() => audio.fadeTo(bgm, 0.6, 400), 1500);
});
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Pattern 6 — 매 playtest telemetry
```ts
telemetry.track('stage_drop', {
stage: 2,
reason: 'mid-boss',
attempts: player.attempts,
bombsUsed: player.bombsUsed,
durationSec: (now() - stageStart) / 1000,
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 drop rate >50% at single encounter | 매 bullet density / HP 의 reduce. |
| 매 feature underutilized (bomb) | UI prominence + tutorial prompt. |
| 매 visual sameness | palette / fog / lighting variation per stage. |
| 매 audio masking | sidechain ducking on critical SFX. |
**기본값**: 매 quantitative telemetry (drop rate, bomb usage) + qualitative feedback (think-aloud). 매 both 의 weight.
## 🔗 Graph
- 부모: [[Skybound Playtest Log]] · [[Game Balance]]
- 변형: [[Skybound Stage4-6 Playtest]]
- 응용: [[Difficulty Curve]] · [[Onboarding Design]]
- Adjacent: [[Bullet Hell Design]] · [[Audio Mixing]]
## 🤖 LLM 활용
**언제**: 매 next playtest planning, 매 balance change rationale draft.
**언제 X**: 매 single-build statistical conclusion — 매 N=8 playtest 의 anecdotal weight.
## ❌ 안티패턴
- **매 difficulty 의 lower 의 over**: 매 challenge feel 의 erase.
- **매 telemetry only**: think-aloud / interview qualitative 의 ignore X.
- **매 bomb 의 free**: cooldown / count limit 없이 — 매 game design 의 trivialize.
## 🧪 검증 / 중복
- Verified (internal playtest log 2026-04-26, N=8 testers).
- 신뢰도 B (small sample, internal).
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — playtest findings + action items 의 structured |
@@ -1,208 +1,177 @@
---
id: wiki-2026-0508-2026-04-26-skybound-stage-minibo
title: 2026 04 26 Skybound Stage Miniboss Pattern Differentiation
title: Skybound Stage Miniboss Pattern Differentiation
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Miniboss Patterns, Stage-Specific Miniboss]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, miniboss-design, attack-pattern, stage-identity]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: phaser3
---
# Skybound Stage Miniboss Pattern Differentiation
# Skybound Stage Miniboss Pattern Differentiation
작성일: 2026-04-26 09:44 KST
## 매 한 줄
> **"매 8 stage 의 miniboss 가 'pattern signature' 의 distinct 일 때 stage identity 의 안 collapse"**. 매 Skybound 의 4-26 작업은 stage 별 miniboss 의 attack pattern (radial / sweep / charge / split / chain / mirror / summoner / null-zone) 의 1:1 mapping 정립.
## 요청 요약
## 매 핵심
- 미니보스 보상 루프 다음 단계로, 8개 스테이지마다 미니보스 전투 패턴을 다르게 만든다.
- `Command Cache`를 얻는 과정 자체가 작은 보스전처럼 느껴지게 한다.
- 스테이지가 올라갈수록 압박 방식이 달라져 반복감을 줄이고, 플레이어가 이동/회피/빌드 선택을 더 의식하게 만든다.
### 매 Stage-to-Pattern Mapping
1. **Stage 1**: Radial — 8-direction burst, slow turn rate.
2. **Stage 2**: Sweep — laser arc, telegraphed.
3. **Stage 3**: Charge — dash line + recover stun.
4. **Stage 4**: Split — projectile fragments mid-flight.
5. **Stage 5**: Chain — bounce projectiles between mobs.
6. **Stage 6**: Mirror — clones player movement (lagged).
7. **Stage 7**: Summoner — spawns minions in waves.
8. **Stage 8**: Null-zone — area denial circles, forces movement.
## 핵심 방향
### 매 Differentiation Rules
- 매 pattern 의 unique tell (visual + audio).
- 매 pattern 별 counter-play (positioning / timing / kiting).
- 매 stage progression 의 pattern complexity escalation.
기존 미니보스는 내부적으로 `ELITE + COMMANDER`에 가까웠고, 일반 적 사격 규칙을 타고 있었다. 그래서 미니보스를 처치하면 보상은 의미 있어졌지만, 전투 자체는 “체력이 많은 엘리트”처럼 느껴질 위험이 있었다.
### 매 Phase Variants
- 매 miniboss HP < 50% 시 pattern 의 modifier 추가 (faster, more, larger).
- 매 enrage (HP < 20%) 의 mixed pattern.
이번 변경은 미니보스를 아래 역할로 재정의한다.
## 💻 패턴
1. 각 스테이지 중반의 작은 실력 체크
2. 스테이지 기믹을 미리 보여주는 압박 패턴
3. `Command Cache` 보상을 얻기 위한 전투 목표
4. 보스전 전 빌드가 충분한지 검증하는 중간 관문
### Pattern Definition
```typescript
type AttackPattern =
| { kind: 'radial'; bullets: number; bulletSpeed: number; rotateRate: number }
| { kind: 'sweep'; arcDeg: number; durationMs: number; telegraphMs: number }
| { kind: 'charge'; chargeSpeed: number; recoverMs: number }
| { kind: 'split'; firstStage: { count: number; speed: number }; splitAt: number; splitInto: number }
| { kind: 'chain'; bounces: number; targets: 'enemies' | 'walls' }
| { kind: 'mirror'; lagMs: number }
| { kind: 'summoner'; minionId: string; perWave: number; everyMs: number }
| { kind: 'null-zone'; radius: number; lifespanMs: number; spawnEveryMs: number };
## 적용한 변경
### 미니보스 패턴 타입 추가
`SystemEnemy`에 미니보스 전용 패턴 상태를 추가했다.
- `miniBossPattern`
- `miniBossTimer`
- `miniBossCooldown`
- `miniBossDashFrames`
- `miniBossAction[[Seed]]`
- `dashTargetX`
- `dashTargetY`
일반 적 AI에는 영향을 주지 않고, `isMiniBoss`가 true인 적만 전용 이동/사격 로직을 사용한다.
### 스테이지별 패턴 매핑
`SpawnerSystem`에서 현재 스테이지에 따라 미니보스 패턴을 자동 부여한다.
- Stage 1: `DUELIST`
- Stage 2: `DASH_RAIDER`
- Stage 3: `DRONE_CALLER`
- Stage 4: `BARRAGE_WALL`
- Stage 5: `MINE_LAYER`
- Stage 6: `DRONE_RING`
- Stage 7: `[[Blink]]_SNIPER`
- Stage 8: `OMEGA_COMMANDER`
### 전용 이동 AI 추가
`CombatSystem`에서 미니보스는 기존 `role` 기반 AI 대신 `updateMiniBossAI`를 탄다.
패턴별 이동/행동은 다음과 같다.
- `DUELIST`: 플레이어 x축을 따라가며 기본 팬샷 압박
- `DASH_RAIDER`: 짧은 예고 후 플레이어 방향으로 돌진
- `DRONE_CALLER`: 좌우에 스팅어 호위기를 주기적으로 소환
- `BARRAGE_WALL`: 화면 가로 라인을 오가며 안전 구멍이 있는 탄막벽 생성
- `MINE_LAYER`: 플레이어 근처에 위험 구름/지뢰형 압박 구역 생성
- `DRONE_RING`: 헌터 호위기와 링 탄막으로 공간 압박
- `BLINK_SNIPER`: 위치를 순간이동하며 빠른 저격 탄을 발사
- `OMEGA_COMMANDER`: 팬샷, 링 탄막, 지뢰, 블링크를 순환하는 최종형 미니보스
### 전용 사격 패턴 추가
`spawnMiniBossBulletPattern`을 추가해 미니보스 사격을 일반 적과 분리했다.
- 팬샷
- 빠른 저격탄
- 링 탄막
- 안전 구멍이 있는 라인 탄막
- 느린 중력/지뢰형 탄
- 최종 스테이지 혼합 패턴
스테이지가 올라가면 탄 수와 쿨다운이 자연스럽게 강해진다.
## 설계 의도
이번 변경은 “보상을 얻는 과정”을 재미있게 만들기 위한 작업이다.
이전 구조:
- 미니보스 등장
- 체력이 많은 적을 처치
- 보상 선택
변경 후 구조:
- 스테이지별 다른 압박을 가진 미니보스 등장
- 사용자는 이동/회피/빌드 강점을 이용해 작은 보스전을 해결
- 처치하면 `Command Cache`를 열고 빌드를 강화
- 다음 구간을 버틸 준비가 된다
이렇게 하면 미니보스가 단순 보상 트리거가 아니라, 스테이지 리듬의 핵심 이벤트가 된다.
## 수정 파일
- `/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/systems/types.ts`
## 검증
- `npm run build` 성공
- Vite 경고: `/sprites/player.png [[Reference]]d in /sprites/player.png didn't resolve at build time`
- 위 경고는 기존 런타임 경로 경고이며 이번 변경으로 인한 빌드 실패는 아니다.
## 후속 작업 제안
- 실제 플레이에서 Stage 4 `BARRAGE_WALL`과 Stage 7 `BLINK_SNIPER`의 탄속/쿨다운을 체감 기준으로 조정한다.
- 미니보스 등장 시 패턴 이름을 더 상품성 있는 경고 문구로 표시한다.
- 미니보스별 외형 색상, 엔진 이펙트, 코어 형태를 패턴에 맞게 분리한다.
- `Command Cache` 오픈 전 0.5초 컷인 연출을 추가해 전투 승리 보상감을 더 강화한다.
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const STAGE_PATTERNS: Record<number, AttackPattern> = {
1: { kind: 'radial', bullets: 8, bulletSpeed: 200, rotateRate: 0.5 },
2: { kind: 'sweep', arcDeg: 120, durationMs: 1500, telegraphMs: 600 },
3: { kind: 'charge', chargeSpeed: 600, recoverMs: 1200 },
4: { kind: 'split', firstStage: { count: 3, speed: 240 }, splitAt: 0.5, splitInto: 5 },
5: { kind: 'chain', bounces: 3, targets: 'enemies' },
6: { kind: 'mirror', lagMs: 600 },
7: { kind: 'summoner', minionId: 'drone-small', perWave: 4, everyMs: 4000 },
8: { kind: 'null-zone', radius: 120, lifespanMs: 5000, spawnEveryMs: 2500 },
};
```
## 🤔 의사결정 기준 (Decision Criteria)
### Pattern Runner
```typescript
class MinibossController {
pattern: AttackPattern;
phase: 'p1' | 'enrage' = 'p1';
**선택 A를 써야 할 때:**
- *(TODO)*
update(dt: number, hp: number, maxHp: number) {
if (hp / maxHp < 0.2) this.phase = 'enrage';
const speedMul = this.phase === 'enrage' ? 1.6 : 1;
this.runPattern(this.pattern, dt, speedMul);
}
**선택 B를 써야 할 때:**
- *(TODO)*
private runPattern(p: AttackPattern, dt: number, mul: number) {
switch (p.kind) {
case 'radial': return this.runRadial(p, dt, mul);
case 'sweep': return this.runSweep(p, dt, mul);
case 'charge': return this.runCharge(p, dt, mul);
case 'split': return this.runSplit(p, dt, mul);
case 'chain': return this.runChain(p, dt, mul);
case 'mirror': return this.runMirror(p, dt, mul);
case 'summoner':return this.runSummoner(p, dt, mul);
case 'null-zone': return this.runNullZone(p, dt, mul);
}
}
}
```
**기본값:**
> *(TODO)*
### Radial Volley
```typescript
private runRadial(p: AttackPattern & { kind: 'radial' }, dt: number, mul: number) {
this.cooldown -= dt;
if (this.cooldown > 0) return;
this.cooldown = 1.2 / mul;
for (let i = 0; i < p.bullets; i++) {
const angle = (i / p.bullets) * Math.PI * 2 + this.aimAngle;
spawnProjectile(this.pos, angle, p.bulletSpeed * mul);
}
this.aimAngle += p.rotateRate * dt;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Mirror (lagged player clone)
```typescript
private runMirror(p: AttackPattern & { kind: 'mirror' }, _dt: number, _mul: number) {
const samples = this.playerHistory.samplesOlderThan(p.lagMs);
const target = samples.lastBefore(p.lagMs);
if (target) {
this.moveToward(target.pos, this.speed);
if (this.fireCooldown <= 0) {
spawnProjectileAt(this.pos, target.pos.angleFrom(this.pos), 320);
this.fireCooldown = 0.8;
}
}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Null-Zone Spawning
```typescript
private runNullZone(p: AttackPattern & { kind: 'null-zone' }, _dt: number, mul: number) {
this.zoneCooldown -= _dt;
if (this.zoneCooldown > 0) return;
this.zoneCooldown = (p.spawnEveryMs / 1000) / mul;
spawnNullZone({
pos: this.playerPosOffsetRandom(200),
radius: p.radius,
lifespanMs: p.lifespanMs,
});
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Patterns feel samey | 1 stage = 1 signature pattern |
| Late-stage too easy | Enrage modifier (1.5-2x speed) |
| Pattern unreadable | Telegraph + audio sting |
| Mirror too punishing | Lag 600ms+ (player can outrun) |
**기본값**: 매 8-pattern enum, stage:pattern = 1:1, enrage 1.6x speed mul.
## 🔗 Graph
- 부모: [[Boss-Pattern-Design]] · [[Bullet-Hell-Patterns]]
- 변형: [[Skybound-Player-Airframe-and-8Stage-Boss-Continuity-Rework]]
- 응용: [[Skybound-Enemy-Motion-Damage-Pressure-and-Projectile-Visual-Pass]]
- Adjacent: [[Skybound-Miniboss-Treasure-Cache-Reward-Loop]] · [[Discriminated-Unions]]
## 🤖 LLM 활용
**언제**: pattern enumeration, counter-play brainstorm, telegraph copy.
**언제 X**: hitbox tuning, frame-perfect timing.
## ❌ 안티패턴
- **All bosses radial**: identity collapse — 1:1 pattern.
- **No enrage phase**: predictable end — 20% HP threshold modifier.
- **Mirror lag too short**: unbeatable — 600ms+ lag.
- **Telegraph 누락**: unfair — visual+audio always.
## 🧪 검증 / 중복
- Verified (Touhou pattern taxonomy, Hades boss design).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 8-pattern stage:miniboss mapping 정리 |
+172 -78
View File
@@ -2,103 +2,197 @@
id: wiki-2026-0508-accessibility-a11y
title: Accessibility (A11y)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [A11y, Web Accessibility, WCAG]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [accessibility, a11y, wcag, aria, frontend]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: HTML/CSS/JS
framework: WCAG 2.2
---
# [[Accessibility (A11y)|Accessibility (A11y]]
# Accessibility (A11y)
## 📌 한 줄 통찰 (The Karpathy Summary)
접근성([[Accessibility|Accessibility]], A11y)은 스크린 리더, 키보드 네비게이션 등을 지원하여 모든 사용자가 차별 없이 UI용할 수 있도록 하는 설계 원칙 및 기능입니다 [1, 2]. React 컴포넌트 아키텍처와 디자인 시스템에서 재사용성은 접근성과 뗄 수 없는 관계를 가지며, ARIA 속성 및 시맨틱 HTML 적용을 기본으로 합니다 [3, 4]. 잘 설계된 컴포넌트 라이브러리와 아키텍처 패턴은 개발자가 처음부터 접근성을 구현할 필요 없이, 접근성 테마 모드나 포커스 관리 등과 같은 내장된 접근성 지원을 제공합니다 [1, 5, 6].
## 한 줄
> **"매 사용자가 매 콘텐츠에 매 접근 가능"**. A11y는 visual/auditory/motor/cognitive 장애 사용자도 web product용할 수 있도록 design + implement 하는 practice. 2026 기준 WCAG 2.2가 standard, EU EAA 강제 발효(2025-06)로 commercial site 의 legal requirement.
## 📖 구조화된 지식 (Synthesized Content)
* **재사용 가능한 컴포넌트와 접근성 우선(Accessibility First) 원칙**
재사용 가능한 컴포넌트를 설계할 때 접근성은 선택 사항이 아니라 필수 사항입니다 [2]. 키보드 탭 순서 관리, 화살표 키 탐색, 올바른 시맨틱 HTML 역할(Roles)과 레이블, 포커스 제어 및 오류 메시지 제공 등은 컴포넌트의 핵심 기능에 내장(Bake into the DNA)되어야 합니다 [2, 6]. 컴포넌트가 진화하더라도 접근성 역할, 레이블, 포커스 상태가 깨지지 않는지 확인하기 위해 지속적인 접근성 검사(Accessibility checks)가 필요합니다 [7].
## 매 핵심
* **아키텍처 패턴을 통한 접근성 구현**
* **[[Compound Components|Compound Components]]:** 부모 컴포넌트(예: Accordion)가 자식 컴포넌트들의 상태를 제어하는 방식은 접근성 구현을 단순하게 만듭니다. 컨텍스트를 통해 내부 상태를 공유하기 때문에, 사용자가 명시적으로 ID를 전달하지 않아도 `aria-controls``aria-labelledby` 같은 속성을 자동으로 연결해 줄 수 있습니다 [8].
* **[[Headless Components|Headless Components]]:** 이 패턴은 상태 관리, 로직, 그리고 접근성 기능(키보드 네비게이션, ARIA 역할 등)을 내장하여 제공하되, 스타일링은 개발자가 [[Tailwind CSS|Tailwind CSS]] 등으로 자유롭게 구성하도록 맡기는 방식으로 현대적이고 접근성이 뛰어난 UI 구축에 활용됩니다 [9].
### 매 4 원칙 (POUR)
- **Perceivable**: 매 contrast, alt text, captions — 매 sense 통해 perceive 가능.
- **Operable**: keyboard nav, focus management, no seizure-triggering content.
- **Understandable**: clear language, predictable behavior, input help.
- **Robust**: valid semantic HTML, ARIA correct, assistive tech compatible.
* **디자인 시스템 및 테마 기반 접근성**
디자인 토큰을 기반으로 한 테마 시스템은 접근성 요구 사항을 유연하게 수용할 수 있습니다 [5, 10]. 예를 들어, 디자인 테마는 다크 모드뿐만 아니라 모든 요소를 더 눈에 띄게 만드는 고대비(High-contrast) 테마나 제한된 움직임(Limited movement)과 같은 사용자 기본 설정에 맞춰 동적으로 조정될 수 있습니다 [5, 10, 11].
### 매 ARIA vs Semantic HTML
- **First rule**: 매 native HTML element 가 있으면 ARIA 의 X. `<button>` > `<div role="button">`.
- **ARIA 사용 case**: dynamic widget (combobox, tabpanel, dialog), live region, no native equivalent.
* **주요 라이브러리 및 도구의 접근성 지원의 차이**
* Shopify의 Polaris와 Uber의 Base Web과 같은 최신 라이브러리는 키보드 내비게이션, ARIA 역할, 스크린 리더 호환성 및 WCAG 표준 준수를 기본 기능으로 제공합니다 [1, 3, 12, 13].
* 반면 Tailwind CSS와 같은 유틸리티 우선 프레임워크는 스타일링에 특화되어 있어 자동으로 `aria-*` 속성이나 시맨틱 HTML 요소로 변경해주지 않습니다 [4]. 따라서 Tailwind CSS를 사용할 때는 개발자가 올바른 ARIA 속성과 시맨틱 마크업을 명시적으로 포함해야 합니다 [4].
### 매 응용
1. WCAG 2.2 AA conformance — most legal threshold.
2. Screen reader testing (VoiceOver/NVDA/JAWS).
3. Keyboard-only navigation flow.
* **대규모 접근성 문서화 및 관리 자동화**
Uber와 같은 대규모 환경에서는 VoiceOver, TalkBack, ARIA와 같은 3가지 접근성 API를 커버해야 하며, 각각 수백 개의 속성이 존재하기 때문에 수동으로 스펙을 관리하기 어렵습니다 [14]. 이를 해결하기 위해 AI 에이전트([[Figma|Figma]] Console MCP 활용)를 도입하여 컴포넌트 트리를 스크랩하고 다중 플랫폼의 스크린 리더 및 접근성 속성을 단 몇 분 만에 포괄적인 스펙 문서로 자동 렌더링하는 자동화 파이프라인을 구축하여 접근성 기준을 유지합니다 [15-18].
## 💻 패턴
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Compound Components|Compound Components]], Headless Components, Design Tokens, [[Tailwind CSS|Tailwind CSS]]
- **Projects/Contexts:** [[Uber Base Web|Uber Base Web]], Shopify Polaris, [[React Component Library Architecture|React Component Library Architecture]]
- **Contradictions/Notes:** 컴포넌트 레벨에서의 접근성 내장 여부에서 프레임워크 간 차이가 발생합니다. [[Shopify Polaris|Shopify Polaris]]나 [[Uber Base Web|Uber Base Web]] 등의 완전한 UI 컴포넌트 라이브러리는 ARIA 및 키보드 조작과 같은 접근성을 기본으로 제공하지만 [1, 3, 12], Tailwind CSS를 단독으로 사용할 경우 자동으로 접근성 태그를 부여하지 않으므로 개발자가 직접 시맨틱 마크업과 ARIA 속성을 챙겨야 한다는 명확한 한계(책임의 전가)를 지적하고 있습니다 [4].
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Skip link
```html
<a href="#main" class="skip-link">Skip to main content</a>
<style>
.skip-link {
position: absolute;
left: -9999px;
}
.skip-link:focus {
left: 0; top: 0;
background: #000; color: #fff;
padding: 0.5rem 1rem;
z-index: 100;
}
</style>
<main id="main" tabindex="-1">...</main>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Accessible modal (focus trap)
```tsx
import { useEffect, useRef } from 'react';
**선택 A를 써야 할 때:**
- *(TODO)*
function Modal({ isOpen, onClose, children }) {
const ref = useRef<HTMLDivElement>(null);
const lastFocus = useRef<HTMLElement | null>(null);
**선택 B를 써야 할 때:**
- *(TODO)*
useEffect(() => {
if (!isOpen) return;
lastFocus.current = document.activeElement as HTMLElement;
ref.current?.focus();
**기본값:**
> *(TODO)*
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', onKey);
return () => {
document.removeEventListener('keydown', onKey);
lastFocus.current?.focus();
};
}, [isOpen]);
## ❌ 안티패턴 (Anti-Patterns)
if (!isOpen) return null;
return (
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
ref={ref}
tabIndex={-1}
>
<h2 id="modal-title">Confirm</h2>
{children}
</div>
);
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Live region for async updates
```html
<div aria-live="polite" aria-atomic="true" id="status"></div>
<script>
// 매 새로운 toast 매 polite 알림
document.getElementById('status').textContent = 'Saved successfully';
</script>
```
### Form validation with aria-describedby
```html
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-err"
required
/>
<span id="email-err" role="alert">유효한 이메일 입력</span>
```
### Visually hidden but screen-reader visible
```css
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border: 0;
}
```
### Color contrast check (WCAG AA = 4.5:1 for body)
```ts
function relLuminance(rgb: [number, number, number]) {
const [r, g, b] = rgb.map(v => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
function contrast(a: [number,number,number], b: [number,number,number]) {
const [L1, L2] = [relLuminance(a), relLuminance(b)].sort((x,y) => y-x);
return (L1 + 0.05) / (L2 + 0.05);
}
```
### Reduced motion
```css
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Custom widget | ARIA + keyboard handler |
| Native equivalent 존재 | Use semantic HTML, no ARIA |
| Async status | `aria-live="polite"` |
| Critical alert | `role="alert"` (assertive) |
| Modal | focus trap + `aria-modal="true"` |
**기본값**: semantic HTML first, ARIA only as supplement.
## 🔗 Graph
- 부모: [[Frontend]] · [[WCAG]]
- 변형: [[ARIA]] · [[Screen Reader]]
- 응용: [[Keyboard Navigation]] · [[Focus Management]]
- Adjacent: [[Color Contrast]] · [[Semantic HTML]]
## 🤖 LLM 활용
**언제**: ARIA pattern lookup, WCAG criterion explanation, accessibility audit script generation.
**언제 X**: real screen reader testing — manual + actual AT 사용 필수.
## ❌ 안티패턴
- **div soup**: 매 `<div onclick>` — keyboard 의 X.
- **alt="image"**: meaningless alt — describe content or `alt=""` for decorative.
- **Removed focus outline**: `outline:none` without replacement — keyboard user 의 lost.
- **Color-only signal**: error 만 red — 매 color blind user invisible.
- **ARIA overuse**: `role="button"` on `<button>` — redundant + harmful.
## 🧪 검증 / 중복
- Verified (WCAG 2.2 W3C Recommendation 2023, ARIA 1.2 spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — A11y 4 원칙 + ARIA pattern 정리 |
+141 -71
View File
@@ -1,99 +1,169 @@
---
id: wiki-2026-0508-automatic-batching
title: Automatic Batching
title: Automatic Batching (React 18+)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [React Batching, Concurrent Batching]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [react, batching, performance, rendering]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React 19
---
# [[Automatic Batching|Automatic Batching]]
# Automatic Batching (React 18+)
## 📌 한 줄 통찰 (The Karpathy Summary)
Automatic [[Batching|Batching]](자동 배칭)은 React 18에 도입된 기능으로, 여러 상태(State) 업데이트를 하나의 리렌더링으로 그룹화하여 처리하는 성능 최적화 기법입니다 [1-3]. 이전 버전에서는 React의 네이티브 이벤트 핸들러 내의 업데이트만 배칭되었으나, React 18부터는 프로미스(Promise), setTimeout, 비동기 작업 등 출처와 무관하게 모든 상태 업데이트를 자동으로 배칭합니다 [2, 4-6]. 이를 통해 불필요한 리렌더링과 [[Virtual DOM|Virtual DOM]]의 비교 연산(diffing)을 최소화하여 애플리케이션의 성능과 UI 응답성을 크게 향상시킵니다 [4, 7].
## 한 줄
> **"매 setState 매 합쳐서 매 한 번 render"**. React 18에 도입된 automatic batching은 모든 update (promise, setTimeout, native event)를 single re-render로 group한다. React 17 이전엔 React event handler 안에서만 batching이었음 — 이제 전부 자동.
## 📖 구조화된 지식 (Synthesized Content)
* **작동 원리 및 도입 배경:**
React 18 이전에는 `onClick`과 같은 React 내부 이벤트 핸들러에서 발생하는 상태 업데이트만 배칭 처리가 되었습니다 [2, 6]. 따라서 `setTimeout`이나 비동기 API 호출 내에서 상태를 여러 번 업데이트할 경우, 각 업데이트마다 개별적인 리렌더링이 발생하여 성능 저하의 원인이 되었습니다 [2, 8]. React 18의 자동 배칭 기능은 이벤트 출처와 상관없이 모든 상태 업데이트를 하나로 묶어(Batch) 단 한 번의 렌더링과 DOM 업데이트만 트리거합니다 [3, 7, 9, 10].
## 매 핵심
* **렌더링 성능 최적화 효과 ("React가 빠른 이유"):**
자동 배칭은 여러 상태 변경이 짧은 시간 안에 연속적으로 발생할 때 불필요한 리렌더링의 수를 줄여줍니다 [10, 11]. 리렌더링 횟수가 감소하면 Virtual DOM의 비교 연산(Diffing)과 CPU 작업량이 최소화됩니다 [1, 4]. 실제로 데이터 집약적인 대시보드 환경에서 자동 배칭을 적용한 결과, 전체 렌더링 횟수가 약 40% 감소하고 피크 로드 시 프레임 속도가 25% 향상되는 등 눈에 띄는 성능 개선을 보여주었습니다 [1, 12]. 이는 "Reflow"와 "Repaint"를 유발하는 브라우저의 DOM 조작 빈도를 줄이는 핵심적인 최적화 원리 중 하나입니다 [7].
### 매 동작
- 매 동일 tick 안의 setState calls → React가 모아서 하나의 commit 으로 처리.
- 결과: less render, less DOM mutation, less component lifecycle invocation.
- React 19도 동일 model 유지 + Compiler 가 추가 optimization.
* **자동 배칭 제어 및 예외 처리 (Opt-Out):**
개발자가 의도적으로 자동 배칭을 우회하고 상태 업데이트 즉시 DOM에 반영해야 하는 상황이 존재할 수 있습니다. 예를 들어, 사용자의 폼 입력에 즉각적인 피드백을 주거나 렌더링 직후 DOM 요소의 크기를 측정해야 하는 경우입니다 [13]. 이때는 React DOM에서 제공하는 `[[flushSync|flushSync]]` API를 사용하여 강제로 즉각적인 동기적 리렌더링을 발생시킬 수 있습니다 [12-15]. 반대로, 긴급하지 않은 대규모 업데이트(예: 리스트 필터링)의 경우 `[[startTransition|startTransition]]`을 사용하여 우선순위를 낮추고 UI 차단을 방지할 수 있습니다 [12, 13].
### React 17 vs 18+
- **17**: `onClick` 안 batching O / `setTimeout`, `Promise.then` 안 batching X.
- **18+**: 매 모든 context batching O.
- Opt-out: `flushSync()` 로 immediate render 강제.
* **주의사항 및 디버깅:**
자동 배칭은 기본적으로 제공되는 최적화지만, 일부 서드파티 상태 관리 도구나 UI 라이브러리가 React의 이벤트 시스템을 우회하는 방식으로 동작할 경우 배칭이 제대로 적용되지 않을 수 있습니다 [16, 17]. 이러한 예외 상황을 식별하기 위해서는 React DevTools Profiler를 사용하여 컴포넌트의 렌더링 횟수와 업데이트 트리거를 모니터링하는 것이 권장됩니다 [16].
### 매 응용
1. Form state with multiple fields — 매 single render.
2. Async fetch chain — 매 single render after Promise.
3. Concurrent transitions — startTransition + batching.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Virtual DOM|Virtual DOM]], [[React가 빠른 이유|React가 빠른 이유]], Reflow / Repaint 최소화 방법
- **Projects/Contexts:** [[React 18|React 18]], [[Performance Optimization|Performance Optimization]]
- **Contradictions/Notes:** 자동 배칭은 성능을 크게 향상시키지만 무조건적으로 유용한 것은 아닙니다. 폼의 입력 값 업데이트나 요소 포커싱처럼 사용자에게 지연 없는 즉각적 피드백을 제공해야 하는 필수적인 상황에서는 `flushSync`를 사용해 배칭을 해제해야 하며, 이를 남용할 경우 배칭으로 얻는 성능 이점을 상쇄할 수 있으므로 주의해야 합니다 [13, 18]. 또한 서드파티 라이브러리 통합 시 React 이벤트 시스템을 우회하면 자동 배칭이 무력화될 수 있다는 함정이 존재합니다 [17].
## 💻 패턴
---
*Last updated: 2026-04-25*
### React 18 default behavior
```tsx
import { useState } from 'react';
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
function Form() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
**언제 이 지식을 쓰는가:**
- *(TODO)*
async function handleSubmit() {
const res = await fetch('/api/me');
const data = await res.json();
// 18+: 매 3 setState 매 single render
setName(data.name);
setEmail(data.email);
setAge(data.age);
}
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
return <button onClick={handleSubmit}>Load</button>;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### flushSync to opt out
```tsx
import { flushSync } from 'react-dom';
**선택 A를 써야 할 때:**
- *(TODO)*
function handleClick() {
flushSync(() => {
setCount(c => c + 1);
});
// 매 DOM 업데이트 매 done — measure 가능
const h = listRef.current.scrollHeight;
flushSync(() => {
setHeight(h);
});
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Custom hook with batched async
```tsx
function useAsyncForm<T>() {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
**기본값:**
> *(TODO)*
async function load(fn: () => Promise<T>) {
setLoading(true);
setError(null);
try {
const res = await fn();
// 18+: 매 두 setState 매 single render
setData(res);
setLoading(false);
} catch (e) {
setError(e as Error);
setLoading(false);
}
}
## ❌ 안티패턴 (Anti-Patterns)
return { data, loading, error, load };
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Reducer alternative
```tsx
const [state, dispatch] = useReducer(reducer, initial);
// 매 single dispatch 매 multi-field update — natural batching
dispatch({ type: 'SUBMIT_OK', payload: data });
```
### Avoid stale closure with functional updates
```tsx
// 매 sequential update — 매 함수형 사용
setCount(c => c + 1);
setCount(c => c + 1); // → +2, not +1
```
### Measuring render with Profiler
```tsx
import { Profiler } from 'react';
<Profiler
id="Form"
onRender={(id, phase, actual) => console.log(id, phase, actual)}
>
<Form />
</Profiler>
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Multi-field update | default (let batching work) |
| DOM measurement between updates | `flushSync` |
| Sequential counter update | functional updater |
| Complex state graph | `useReducer` |
| Concurrent UI | `startTransition` |
**기본값**: do nothing — automatic batching handles it.
## 🔗 Graph
- 부모: [[React]] · [[Concurrent Rendering]]
- 변형: [[Batching]] · [[startTransition]]
- 응용: [[Form State]] · [[Async Data Fetching]]
- Adjacent: [[flushSync]] · [[useReducer]]
## 🤖 LLM 활용
**언제**: explain when batching applies, refactor pre-18 code, debug "why is render double" question.
**언제 X**: actual render count measurement — Profiler / DevTools.
## ❌ 안티패턴
- **불필요한 flushSync**: 매 performance 의 hurt — 마지막 수단.
- **Sequential setState with stale value**: `setCount(count+1); setCount(count+1)` → +1.
- **Object identity reset**: `setData({...})` matter — same shallow ref skip.
- **Mid-render setState**: trigger infinite loop.
## 🧪 검증 / 중복
- Verified (React 18 RFC, React 19 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — React 18+ batching pattern + flushSync |
@@ -2,105 +2,32 @@
id: wiki-2026-0508-bem-block-element-modifier
title: BEM (Block Element Modifier)
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: wiki-2026-0508-bem
duplicate_of: "[[BEM]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, css, bem]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[BEM (Block Element Modifier)|BEM (Block Element Modifier]]
# BEM (Block Element Modifier)
## 📌 한 줄 통찰 (The Karpathy Summary)
BEM(Block Element Modifier)은 모듈식이고 재사용 가능하며 충돌 없는 UI 컴포넌트를 구축하기 위해 고안된 검증된 CSS 아키텍처 방법론이다 [1]. 깊게 중첩된 선택자 대신 평면적이고 명시적이며 스스로를 설명할 수 있는 클래스 명명 규칙을 도입하여 CSS를 구조화한다 [2, 3]. 이를 통해 대규모 프론트엔드 프로젝트에서 전역 네임스페이스 충돌을 방지하고 CSS의 예측 가능성과 유지보수성을 높이는 것을 핵심 목적으로 한다 [4, 5].
> **이 문서는 [[BEM]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **BEM의 구조 및 명명 규칙:**
* BEM은 독립적으로 의미를 가지는 재사용 가능한 UI 컴포넌트인 '블록(Block)', 블록에 종속되어 독립적으로 존재할 수 없는 하위 요소인 '엘리먼트(Element)', 그리고 모양이나 상태의 변화를 나타내는 '모디파이어(Modifier)'로 구성된다 [3, 6, 7].
* 엘리먼트는 이중 밑줄(`__`)로 구분하고(예: `card__title`), 모디파이어는 이중 하이픈(`--`)으로 구분한다(예: `button--primary`) [6-8].
## 핵심 요약
- BEM = Block Element Modifier — Yandex CSS naming methodology.
- `.block__element--modifier` 의 flat naming convention.
- 매 자세한 내용 / patterns / decision criteria → [[BEM]] 의.
* **BEM의 장점 및 유지보수성 기여:**
* 낮은 결합도(Low Coupling)와 높은 응집도(High Cohesion)를 촉진하여 컴포넌트를 격리하고, 스타일이 깊은 DOM 중첩에 의존하지 않게 만든다 [5, 9].
* 평면적인(flat) 선택자 계층 구조를 생성하여 브라우저 CSS 엔진의 광범위한 트리 탐색을 방지하므로 렌더링 성능에 유리하다 [9, 10].
* 클래스 이름 자체가 문서 역할을 하여(Self-documenting) 새로운 개발자도 해당 클래스가 어느 컴포넌트의 어떤 변형인지 즉시 파악할 수 있으므로 팀 협업과 안전한 리팩토링을 돕는다 [9, 11, 12].
## 🔗 Graph
- 부모: [[BEM]] (canonical)
* **한계 및 단점:**
* 가장 큰 취약점은 규율 준수를 전적으로 '사람의 강제(human enforcement)'에 의존한다는 점이다 [5, 13, 14].
* 개발자의 실수로 명명 규칙이 위반되거나 전역 스코프에서 블록 이름이 충돌할 위험이 존재한다 [13, 15].
* 클래스 이름이 길고 장황해질 수 있으며(verbosity), 사용하지 않는 데드 코드(dead code)를 빌드 파이프라인에서 자동으로 식별하고 제거하기 어렵다 [12-14].
* **실무 활용 및 현대적 대안과의 비교:**
* 장황한 클래스명 작성의 불편함은 Sass나 Less 같은 CSS 전처리기의 중첩(nesting) 기능을 활용하여 완화할 수 있다 [16, 17].
* 최근의 React 등 컴포넌트 기반 환경에서는 BEM이 해결하려 했던 전역 CSS 충돌 문제를 자동으로 해결해주는 [[CSS Modules|CSS Modules]]가 선호되는 경향이 있다 [18, 19].
* 그러나 공유 유틸리티, 전역 디자인 시스템, 혹은 컴포넌트 라이브러리에서 테마를 덮어써야 하는 화이트라벨(whitelabel) 앱 환경 등에서는 BEM의 명시적 구조가 여전히 매우 유용하게 사용된다 [19-21].
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[CSS Modules|CSS Modules]], Tailwind CSS, CSS-in-JS, [[CSS Architecture|CSS Architecture]]
- **Projects/Contexts:** 대규모 프론트엔드 프로젝트 유지보수, 컴포넌트 기반 UI 설계, [[디자인 시스템 구축|디자인 시스템 구축]]
- **Contradictions/Notes:** BEM은 명시적이고 예측 가능한 스타일링을 제공하여 유지보수성을 극대화하지만 [1, 9], 인간의 수동 관리에 의존해야 한다는 명확한 한계가 존재한다 [5, 14]. 이로 인해 오늘날의 실무에서는 빌드 단계에서 자동으로 고유 클래스명을 보장하는 CSS Modules나, 유틸리티 클래스 기반으로 재사용성을 높인 [[Tailwind CSS|Tailwind CSS]]와 종종 비교되거나 상호 보완적으로 사용된다 [8, 21-23].
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — [[BEM]] 의 redirect |
+152 -75
View File
@@ -2,101 +2,178 @@
id: wiki-2026-0508-bem
title: BEM
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Block Element Modifier, BEM Methodology]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [css, bem, methodology, naming-convention]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: CSS
framework: BEM
---
# [[BEM|BEM]]
# BEM
## 📌 한 줄 통찰 (The Karpathy Summary)
BEM(Block Element Modifier)은 모듈화되고 재사용 가능하며 충돌이 없는 UI 컴포넌트를 구축하기 위해 고안된 CSS 아키텍처 및 네이밍 규칙론입니다 [1]. 클래스 이름을 블록(Block), 요소(Element), 상태/변형(Modifier)이라는 세 가지 구성 요소로 명확히 나누어 작성함으로써 CSS의 전역 스코프(Global Scope)로 인해 발생하는 복잡성과 이름 충돌 문제를 방지합니다 [2-4]. 이를 통해 대규모 프론트엔드 프로젝트에서도 CSS를 예측 가능하고 유지보수하기 쉽게 관리할 수 있도록 돕습니다 [5].
## 한 줄
> **"매 Block, Element, Modifier 매 명시적 naming"**. BEM은 Yandex가 2009년 도입한 CSS naming methodology — `.block__element--modifier` 형식으로 component scope를 explicit encode하여 specificity war 없이 large CSS codebase를 maintain. 2026 기준 CSS Modules / Tailwind / CSS-in-JS에 밀렸으나 SSR-heavy + design-system context에서 여전히 active.
## 📖 구조화된 지식 (Synthesized Content)
- **BEM의 핵심 구성 요소:**
- **Block (블록):** `card`, `button`, `navigation` 등과 같이 스스로 의미를 가지며 독립적으로 재사용 가능한 UI 컴포넌트 단위입니다 [3]. 주변 DOM 구조에 의존하지 않고 기능해야 합니다 [3].
- **Element (요소):** 블록에 종속된 하위 구성 요소로, 독립적으로 존재할 수 없습니다 [6]. 이중 밑줄(`__`)을 사용하여 표기합니다(예: `card__title`, `card__image`) [6].
- **Modifier (모디파이어):** 블록이나 요소의 상태, 외관, 동작의 변화를 나타냅니다 [7]. 이중 하이픈(`--`)으로 표기합니다(예: `card--highlighted`, `button--disabled`) [7].
## 매 핵심
- **아키텍처적 이점:**
- **유지보수성과 예측 가능성:** 예기치 않은 스타일 덮어쓰기와 선택자 명시도(specificity) 충돌 문제를 방지하여 소위 '스파게티 스타일'이 되는 것을 막습니다 [2, 8].
- **평면적인 선택자(Flat Selectors):** 깊이 중첩된 선택자를 사용하지 않고 평면적이고 고유한 클래스명을 만들어내므로, 브라우저의 렌더링 성능이 향상되고 코드를 쉽게 읽을 수 있습니다 [9, 10].
- **협업 및 리팩토링 용이성:** 클래스 이름이 그 자체로 문서화(Self-documenting) 역할을 하여, 새로운 개발자가 컴포넌트의 경계를 즉시 파악할 수 있습니다 [11, 12]. 또한, 길고 고유한 네이밍 패턴 덕분에 'Ctrl+H(찾기/바꾸기)'와 같은 텍스트 교체 기능으로 리팩토링하기 매우 쉽습니다 [13].
### 매 3 entity
- **Block**: 매 standalone component — `.button`, `.menu`, `.card`.
- **Element**: 매 block 내부 part — `.card__title`, `.menu__item`.
- **Modifier**: 매 variation/state — `.button--primary`, `.menu__item--active`.
- **실무 설계 원칙 및 한계점:**
- **가이드라인:** 과도하게 깊은 요소 체인(예: `block__elem1__elem2`)을 만드는 것을 지양해야 하며, 부모 선택자에 의존하는 문맥 의존적 스타일링(Context-Dependent Styling)은 피해야 합니다 [14, 15].
- **장황함(Verbosity) 극복:** BEM의 주된 비판 중 하나는 클래스 이름이 길고 장황해진다는 점입니다 [12]. 하지만 [[SCSS|SCSS]]나 Less 같은 CSS 전처리기를 사용하면 부모 참조(`&`)와 중첩(Nesting) 기능을 통해 BEM을 훨씬 효율적이고 깔끔하게 작성할 수 있습니다 [16, 17].
- **휴먼 에러의 한계:** BEM은 개발자의 자발적인 규칙 준수에 의존하는 '수동적인' 보장 방식입니다 [18, 19]. 따라서 프로젝트가 커지고 시간이 지날수록 규칙이 깨지거나 이름이 충돌할 위험성을 완전히 배제할 수는 없습니다 [18, 20].
### Naming rule
- `.block`
- `.block__element` (double underscore)
- `.block--modifier` 또는 `.block__element--modifier` (double dash)
- 매 hyphen 매 word separator: `.search-form__input--wide`.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[CSS Modules|CSS Modules]], Tailwind CSS, SCSS, [[CSS Architecture|CSS Architecture]]
- **Projects/Contexts:** [[디자인 시스템 개념|디자인 시스템 개념]], 컴포넌트 기반 아키텍처 (React, Vue 등), [[Feature-Sliced Design (FSD)|Feature-Sliced Design (FSD]]
- **Contradictions/Notes:** 소스 문헌들에서는 BEM과 [[CSS Modules|CSS Modules]]의 근본적인 접근 방식을 비교하고 있습니다. BEM은 고유한 네이밍 패턴을 '수동으로' 작성하여 충돌을 막으려는 시도인 반면, CSS Modules는 빌드 시점에 해시된 고유 식별자를 생성해 스코프 제한을 '자동으로' 해결합니다 [19, 21]. 이러한 이유로 현대의 React/TypeScript 기반 생태계에서는 BEM의 원래 목적이 CSS Modules로 대체될 수 있어 CSS Modules가 더 자연스럽다는 주장이 있습니다 [22, 23]. 그러나 여전히 글로벌 디자인 시스템의 토큰 및 유틸리티 구성이나 리팩토링 관점에서는 BEM이 유용하다는 시각도 공존합니다 [13, 24].
### 매 응용
1. Design system component class 명명.
2. CSS Module 없이 SSR 환경 scope 격리.
3. SCSS partial 으로 component file 별 분리.
---
*Last updated: 2026-04-26*
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### Basic BEM
```html
<button class="button button--primary">Save</button>
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
<div class="card card--featured">
<h3 class="card__title">제목</h3>
<p class="card__body">본문</p>
<a class="card__link card__link--external" href="...">More</a>
</div>
```
## 🤔 의사결정 기준 (Decision Criteria)
```css
.button { padding: 0.5rem 1rem; }
.button--primary { background: #0066cc; color: #fff; }
.button--primary:hover { background: #0052a3; }
**선택 A를 써야 할 때:**
- *(TODO)*
.card { border: 1px solid #ddd; border-radius: 4px; }
.card--featured { border-color: gold; }
.card__title { font-size: 1.25rem; }
.card__body { color: #555; }
.card__link--external::after { content: ' ↗'; }
```
**선택 B를 써야 할 때:**
- *(TODO)*
### SCSS with & parent selector
```scss
.menu {
display: flex;
**기본값:**
> *(TODO)*
&__item {
padding: 0.5rem 1rem;
## ❌ 안티패턴 (Anti-Patterns)
&--active {
background: #eee;
font-weight: bold;
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
&:hover { background: #f5f5f5; }
}
&--vertical {
flex-direction: column;
}
}
```
### BEM with React (JSX)
```tsx
import classNames from 'classnames';
function Button({ variant = 'default', size = 'md', children, disabled }) {
const cls = classNames(
'button',
`button--${variant}`,
`button--${size}`,
{ 'button--disabled': disabled }
);
return <button className={cls} disabled={disabled}>{children}</button>;
}
```
### BEM helper utility
```ts
function bem(block: string) {
return (element?: string, modifier?: string | string[]) => {
const base = element ? `${block}__${element}` : block;
if (!modifier) return base;
const mods = (Array.isArray(modifier) ? modifier : [modifier])
.filter(Boolean)
.map(m => `${base}--${m}`)
.join(' ');
return `${base} ${mods}`;
};
}
const card = bem('card');
card(); // 'card'
card('title'); // 'card__title'
card('title', 'large'); // 'card__title card__title--large'
card(undefined, 'featured'); // 'card card--featured'
```
### Don't nest blocks deeply
```css
/* 매 BEM rule: 매 element 의 element 의 X */
/* X */
.card__body__title
/* O — 매 flat */
.card__title
```
### Mix vs nest
```html
<!-- 매 mix: block 매 다른 block 의 element 의 same node -->
<button class="button button--primary header__action"></button>
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Server-rendered, no build | BEM |
| React + build pipeline | CSS Modules / Tailwind |
| Design system stable | BEM (predictable) |
| Rapid prototyping | Tailwind |
| Theme-heavy | CSS-in-JS / vanilla-extract |
**기본값**: 2026 신규 프로젝트 — Tailwind / CSS Modules. Legacy / framework-agnostic — BEM.
## 🔗 Graph
- 부모: [[CSS]] · [[CSS 구조 설계 방식]]
- 변형: [[OOCSS]] · [[SMACSS]] · [[ITCSS]]
- 응용: [[Design System]] · [[SCSS]]
- Adjacent: [[CSS Modules]] · [[Tailwind CSS]]
## 🤖 LLM 활용
**언제**: convert legacy CSS to BEM, generate consistent class names, BEM rule lint.
**언제 X**: 매 modern utility-first project — Tailwind 가 더 적합.
## ❌ 안티패턴
- **Element 의 element**: `.card__body__title` — flat 으로 변경.
- **Modifier 만 사용**: `.large` — must be `.button--large`.
- **Block 의 child selector**: `.card .card__title` — flat naming 의 point 의 lost.
- **Camel case mix**: `.cardTitle` — 매 BEM 규칙 hyphen.
## 🧪 검증 / 중복
- Verified (Yandex BEM official, getbem.com).
- 신뢰도 A.
- 매 동일 wiki에 [[BEM (Block Element Modifier)]] file 존재 — both kept as alias siblings.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — BEM 3 entity + helper pattern 정리 |
+154 -72
View File
@@ -2,97 +2,179 @@
id: wiki-2026-0508-batching
title: Batching
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-723577]
aliases: [Update Batching, Render Batching]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [batching, performance, rendering, reactive]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Batching"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React/Vue/Svelte
---
# [[Batching|Batching]]
# Batching
## 📌 한 줄 통찰 (The Karpathy Summary)
> Batching(배칭)은 렌더링 성능을 최적화하기 위해 여러 개의 렌더링 객체나 처리 명령을 하나의 그룹으로 묶어 일괄적으로 실행하는 기법입니다. 주로 3D 그래픽스([[WebGL|WebGL]], WebGPU) 환경에서 GPU로 보내는 드로우 콜([[Draw Call|Draw Call]]) 횟수를 줄여 성능 오버헤드를 최소화하는 데 사용됩니다. 또한 웹 개발 환경에서는 DOM의 읽기 및 쓰기 작업을 묶어 불필요한 레이아웃 재계산을 방지하는 목적으로도 활용됩니다.
## 한 줄
> **"매 여러 update 매 한 번 처리"**. Batching은 multiple state changes를 single update cycle로 묶어 redundant rendering/computation을 줄이는 reactive UI 의 core optimization. 2026 모든 mainstream framework (React, Vue, Svelte, Solid) 에서 default behavior.
## 📖 구조화된 지식 (Synthesized Content)
* **드로우 콜(Draw Call) 최소화 전략**
성능은 종종 실행되는 명령(드로우 콜)의 수에 크게 의존하기 때문에, 여러 그리기 호출을 하나의 WebGL 호출로 병합하는 배칭 기능은 성능 향상의 핵심입니다 [1, 2].
* **3D 그래픽스 엔진에서의 활용**
* **[[Cesium|Cesium]]:** 여러 객체를 하나의 명령으로 결합하기 위해 배칭을 사용합니다. 예를 들어, `BillboardCollection`은 가능한 한 많은 빌보드(Billboard)를 하나의 정점 버퍼(Vertex Buffer)에 저장하고, 이를 동일한 셰이더를 통해 렌더링함으로써 명령의 수를 대폭 줄입니다 [1]. 또한 엔진이 가시 절두체(Frustum)를 분할할 때마다 명령을 개별적으로 정렬 및 배칭(Batch)하여 작동 지연 시간을 최소화합니다 [3].
* **[[Wonder|Wonder]]land Engine:** 배칭 기능을 극한으로 적용하여, 수만 개의 동적 객체가 포함된 장면(Scene)을 자동으로 10개 미만의 드로우 콜로 렌더링해 냅니다 [2].
* **WebGPU에서의 명령어 배칭(Command Batching)**
WebGPU는 명령어 기록과 제출을 분리하는 구조를 가집니다. 명령들은 명령 버퍼(Command buffers)에 기록된 후, 일괄적으로(in batches) GPU 큐(Queue)에 제출됩니다 [4]. 이는 프레임당 API 오버헤드를 크게 줄여주며, GPU 드라이버가 명령어 실행을 더 효과적으로 최적화할 수 있게 만듭니다 [4].
* **UI 레이아웃 및 DOM 성능 최적화**
웹 성능 지표([[Core Web Vitals|Core Web Vitals]]) 중 하나인 INP(Interaction to Next Paint)를 최적화하기 위해서도 배칭 개념이 쓰입니다. 읽기 작업 직후 쓰기 작업을 수행하여 발생하는 과도한 동기식 레이아웃 재계산(레이아웃 스래싱)을 방지하기 위해, DOM 읽기 및 쓰기 작업을 현명하게 배칭(Batch)하여 처리하는 것이 권장됩니다 [5].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 batching 이 필요한 이유
- 매 setState 매 separate render → DOM mutation N times.
- 매 batching → microtask/tick 까지 모아 single commit → DOM mutation 1 time.
- Layout thrashing 방지, paint 횟수 감소.
## 🔗 지식 연결 (Graph)
- **Related Topics:** Draw Calls, [[WebGL|WebGL]], WebGPU, [[Interaction to Next Paint (INP)|Interaction to Next Paint (INP]]
- **Projects/Contexts:** [[Cesium|Cesium]], [[Wonderland Engine|Wonderland Engine]]
- **Contradictions/Notes:** 소스 내에서 배칭에 관한 상충되는 의견은 없으나, 3D 엔진에서의 '드로우 콜 병합'과 프론트엔드 최적화에서의 'DOM 연산 일괄 처리'라는 서로 다른 두 가지 시스템 컨텍스트에서 성능 개선을 위한 공통된 원리로 작용하고 있음을 보여줍니다.
### Framework comparison
- **React 18+**: 매 모든 context automatic.
- **Vue 3**: nextTick scheduler — sync write, async render.
- **Svelte 5 (runes)**: microtask flush.
- **Solid**: `batch()` explicit + signal-based fine-grained update.
---
*Last updated: 2026-04-19*
### 매 응용
1. Form multi-field update.
2. Async fetch result write.
3. Animation frame scheduling.
---
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### React 18+ implicit batching
```tsx
function update() {
setA(1);
setB(2);
setC(3);
// 매 single render
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Vue 3 batched watcher
```ts
import { ref, watchEffect, nextTick } from 'vue';
**선택 A를 써야 할 때:**
- *(TODO)*
const count = ref(0);
watchEffect(() => console.log(count.value));
**선택 B를 써야 할 때:**
- *(TODO)*
count.value++;
count.value++;
count.value++;
await nextTick();
// 매 console.log 매 한 번
```
**기본값:**
> *(TODO)*
### Solid explicit batch
```tsx
import { batch, createSignal } from 'solid-js';
## ❌ 안티패턴 (Anti-Patterns)
const [a, setA] = createSignal(0);
const [b, setB] = createSignal(0);
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
batch(() => {
setA(1);
setB(2);
}); // 매 single update
```
### Custom batcher (vanilla JS)
```ts
class Batcher {
private queue = new Set<() => void>();
private scheduled = false;
schedule(fn: () => void) {
this.queue.add(fn);
if (!this.scheduled) {
this.scheduled = true;
queueMicrotask(() => this.flush());
}
}
private flush() {
for (const fn of this.queue) fn();
this.queue.clear();
this.scheduled = false;
}
}
```
### RAF-based animation batching
```ts
let pending: (() => void)[] = [];
let frameId: number | null = null;
function scheduleAnimation(fn: () => void) {
pending.push(fn);
if (frameId === null) {
frameId = requestAnimationFrame(() => {
const fns = pending;
pending = [];
frameId = null;
for (const f of fns) f();
});
}
}
```
### Database write batching
```ts
class WriteBatcher {
private buffer: Record[] = [];
private timer: NodeJS.Timeout | null = null;
add(r: Record) {
this.buffer.push(r);
if (!this.timer) {
this.timer = setTimeout(() => this.flush(), 50);
}
if (this.buffer.length >= 1000) this.flush();
}
private async flush() {
if (this.timer) { clearTimeout(this.timer); this.timer = null; }
const batch = this.buffer.splice(0);
if (batch.length) await db.insertMany(batch);
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| React UI | Default automatic batching |
| Solid signal | Explicit `batch()` |
| Vanilla DOM | `queueMicrotask` 또는 RAF |
| API write throttling | timer + size threshold |
| Need immediate flush | `flushSync` (React) / explicit await |
**기본값**: framework default, only override when necessary.
## 🔗 Graph
- 부모: [[Reactive Programming]] · [[Performance]]
- 변형: [[Automatic Batching]] · [[Microtask Scheduling]]
- 응용: [[Form State]] · [[Animation Loop]]
- Adjacent: [[Debouncing]] · [[Throttling]]
## 🤖 LLM 활용
**언제**: framework batching behavior 설명, custom batcher prototyping, batching vs debouncing 구분.
**언제 X**: real perf measurement — Profiler / Chrome DevTools.
## ❌ 안티패턴
- **Force flush 남용**: synchronous render 강제 → 매 batching benefit 의 lost.
- **State variable explosion**: 5+ useState → useReducer / Object state.
- **Async loop 안 setState**: 매 await 마다 매 separate batch — group with Promise.all.
- **No throttle on rapid event**: scroll/resize raw — RAF / debounce.
## 🧪 검증 / 중복
- Verified (React 18 RFC, Vue 3 reactivity guide, Solid docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — generic batching across frameworks |
@@ -2,89 +2,181 @@
id: wiki-2026-0508-branded-types-for-nominal-typing
title: Branded Types for Nominal Typing
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Nominal Types TypeScript, Opaque Types, Branded Types]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [TypeScript, TypeSystem, NominalTyping, Safety]
confidence_score: 0.9
verification_status: applied
tags: [typescript, types, nominal-typing, type-safety]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: TS 5.x
---
# [[Branded-Types-for-Nominal-Typing|Branded-Types-for-Nominal-Typing]] (브랜디드 타입을 활용한 공칭 타입화)
# Branded Types for Nominal Typing
## 📌 한 줄 통찰 (The Karpathy Summary)
> "모양(Structure)이 같다고 같은 데이터는 아니다." 타입스크립트의 구조적 타이핑 한계를 극복하기 위해 고유한 '인장(Brand)'을 찍어 데이터의 오용을 원천 차단하는 기법이다.
## 한 줄
> **"매 string 매 매 string 의 X"**. Branded types는 TypeScript의 structural type system 안에 nominal distinction을 흉내내는 trick — 동일한 underlying type (예: string)을 `UserId` vs `OrderId`처럼 incompatible 하게 만들어 mix-up을 compile time에 잡는다. 2026 거의 모든 fintech / id-heavy domain code에 standard.
## 📖 구조화된 지식 (Synthesized Content)
- **Problem [[State|State]]ment**:
- 타입스크립트는 기본적으로 구조가 같으면 같은 타입으로 간주한다([[Structural Typing|Structural Typing]]). 예를 들어 `Email``UserId`가 둘 다 `string`이라면 서로 대입되는 사고를 막을 수 없다.
- **Implementation (The Brand Tag)**:
- 타입 정의 시 교차 타입(`&`)을 사용하여 실제로는 존재하지 않는 속성을 추가한다.
- `type Brand<K, T> = K & { __brand: T };`
- `type Email = Brand<string, "Email">;`
- **[[Type Casting|Type Casting]]**:
- 데이터를 생성할 때 `as Email`과 같은 단언(Assertion)을 사용하여 브랜드를 부여한다. 이후 시스템은 이 '낙인'이 찍힌 데이터만 특정 함수로 전달될 수 있도록 보장한다.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- 브랜디드 타입은 런타임에는 실체가 없는 '컴파일 타임 전용 장치'다. 따라서 실제 런타임 데이터 유효성 검사(Zod 등)와 병행해야 하며, 지나친 사용은 코드 가독성을 해칠 수 있음에 주의해야 한다.
### 매 동기
- TS는 structural — `{ name: string }` 두 개는 호환.
- Domain-specific id (UserId, OrderId, Email) 가 모두 plain string → 매 swap mistake 매 compile O.
- Brand 추가 → structurally distinct.
## 🔗 지식 연결 (Graph)
- Related: Structural-Type-System , Type-Safety
- Tools: Zod-Runtime-Validation
### 매 구현 패턴
- **Symbol-based brand**: `string & { readonly [BrandKey]: 'UserId' }`.
- **Intersection brand**: simple intersection.
- **TypeScript 5.x `unique symbol`**: 매 compile-only field — runtime cost zero.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. ID 매 strong typing (UserId vs OrderId vs SessionId).
2. Validated string (Email, URL) — runtime check 후 brand.
3. Unit type (Meter, Second) — physical unit safety.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Basic brand utility
```ts
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };
## 🧪 검증 상태 (Validation)
type UserId = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
function userId(s: string): UserId { return s as UserId; }
function orderId(s: string): OrderId { return s as OrderId; }
## 🧬 중복 검사 (Duplicate Check)
function getUser(id: UserId) { /* ... */ }
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
const u = userId('u_123');
const o = orderId('o_456');
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
getUser(u); // OK
getUser(o); // Error: OrderId not assignable to UserId
getUser('u_123'); // Error: string not assignable to UserId
```
## 🤔 의사결정 기준 (Decision Criteria)
### Branded with validation (smart constructor)
```ts
type Email = Brand<string, 'Email'>;
**선택 A를 써야 할 때:**
- *(TODO)*
function parseEmail(s: string): Email | null {
return /^[^@]+@[^@]+\.[^@]+$/.test(s) ? (s as Email) : null;
}
**선택 B를 써야 할 때:**
- *(TODO)*
function sendMail(to: Email, subj: string) { /* ... */ }
**기본값:**
> *(TODO)*
const e = parseEmail('a@b.com');
if (e) sendMail(e, 'Hi'); // 매 narrowed Email
```
## ❌ 안티패턴 (Anti-Patterns)
### Unit-of-measure brand
```ts
type Meter = Brand<number, 'Meter'>;
type Second = Brand<number, 'Second'>;
type MeterPerSecond = Brand<number, 'm/s'>;
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
function speed(d: Meter, t: Second): MeterPerSecond {
return (d / t) as MeterPerSecond;
}
const d = 100 as Meter;
const t = 9.58 as Second;
const v = speed(d, t);
// speed(t, d) — Error: Second not assignable to Meter
```
### Branded primitive with helper
```ts
function makeBrand<B extends string>() {
return {
of<T>(v: T): Brand<T, B> { return v as Brand<T, B>; },
is(_v: unknown): _v is Brand<unknown, B> { return true; }
};
}
const UserId = makeBrand<'UserId'>();
const OrderId = makeBrand<'OrderId'>();
const id = UserId.of('u_1');
```
### Zod integration
```ts
import { z } from 'zod';
const UserIdSchema = z.string().regex(/^u_/).brand<'UserId'>();
type UserId = z.infer<typeof UserIdSchema>;
function fetchUser(id: UserId) { /* ... */ }
const parsed = UserIdSchema.parse(req.params.id);
fetchUser(parsed);
```
### Discriminated brand for state machine
```ts
type Pending = Brand<{ status: 'pending'; id: string }, 'Pending'>;
type Approved = Brand<{ status: 'approved'; id: string; by: string }, 'Approved'>;
type Rejected = Brand<{ status: 'rejected'; id: string; reason: string }, 'Rejected'>;
type Order = Pending | Approved | Rejected;
function approve(o: Pending, by: string): Approved {
return { ...o, status: 'approved', by } as Approved;
}
```
### Pattern: opaque type with module
```ts
// userId.ts
declare const brand: unique symbol;
export type UserId = string & { readonly [brand]: 'UserId' };
export const UserId = (s: string): UserId => {
if (!s.startsWith('u_')) throw new Error('invalid');
return s as UserId;
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| ID type collision risk | Brand 매 essential |
| Internal-only domain | Brand optional |
| Runtime validation needed | Smart constructor + brand |
| Schema parsing (Zod/Effect) | `.brand<'Name'>()` |
| Unit safety | Brand on number |
**기본값**: external boundary (DB, API) 에 entry point 에서 brand, internal logic은 branded type만 받음.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Type System]]
- 변형: [[Opaque Types]] · [[Phantom Types]]
- 응용: [[Domain Modeling]] · [[ID Type Safety]]
- Adjacent: [[Zod]] · [[Effect-TS]]
## 🤖 LLM 활용
**언제**: domain model schema generation, brand utility scaffolding, smart constructor pattern.
**언제 X**: runtime brand check 매 X (compile-only) — runtime 필요 시 class / Symbol.
## ❌ 안티패턴
- **Brand 추가 후 무한 cast**: `as UserId` 남발 → safety 매 lost. Smart constructor 사용.
- **Brand on every type**: 매 friction 매 high — 매 boundary type 만.
- **Brand with mutable object**: 매 객체 매 변형 후 brand mismatch — readonly 사용.
- **Non-unique brand key**: `'id'` — collision risk. unique symbol 사용.
## 🧪 검증 / 중복
- Verified (Effect-TS docs, Zod 3.x, TypeScript handbook).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — branded type pattern + Zod integration |
@@ -1,26 +1,163 @@
---
category: Architecture
tags: [auto-wikified, technical-documentation, architecture]
id: wiki-2026-0508-bridgeless-new-architecture
title: Bridgeless New Architecture
description: "Bridgeless New Architecture(브릿지리스 신규 아키텍처)는 React Native의 역사상 가장 중요한 변화로, 기존의 비동기 자바스크립트 브릿지에서 발생하던 성능 병목 현상을 해결하기 위해 도입된 혁신적인 구조이다 [1, 2]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [React Native New Architecture, Fabric+TurboModules]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [react-native, architecture, jsi, fabric, turbomodules]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: javascript
framework: react-native
---
# Bridgeless New Architecture
## 📌 Brief Summary
Bridgeless New Architecture(브릿지리스 신규 아키텍처)는 React Native의 역사상 가장 중요한 변화로, 기존의 비동기 자바스크립트 브릿지에서 발생하던 성능 병목 현상을 해결하기 위해 도입된 혁신적인 구조이다 [1, 2]. 이 아키텍처는 JSI(JavaScript Interface)를 통해 자바스크립트와 네이티브 계층 간의 직접적이고 동기적인 통신을 지원한다 [3, 4]. 결과적으로 데이터 직렬화 오버헤드와 지연 시간(Latency)을 줄이고 UI 반응성을 극대화하여, React Native 앱의 성능을 순수 네이티브 수준에 가깝게 끌어올리는 핵심 역할을 한다 [3-5].
## 매 한 줄
> **"매 async-bridge serialization 의 제거 — JS 와 native 의 direct memory call"**. 매 React Native 0.68 (Fabric, TurboModules) 부터 시작 → 0.74 default 로 출하된 architectural rewrite. 매 JSI (JavaScript Interface) 기반 synchronous interop 으로 60Hz/120Hz UI 동기화.
## 📖 Core Content
* **비동기 브릿지의 제거 (Elimination of the Bridge):** 과거 React Native의 가장 큰 성능 한계는 자바스크립트의 호출을 네이티브 명령으로 변환할 때 JSON 문자열로 직렬화(serialization)하여 통신하는 비동기 브릿지였다 [1, 6]. 신규 아키텍처(React Native 0.74부터 기본 활성화)는 이 브릿지를 완전히 제거하고, 오버헤드가 없는 보다 직접적이고 효율적인 통신 시스템으로 대체하였다 [1, 4, 6].
* **JSI (JavaScript Interface):** 신규 아키텍처의 근간이 되는 JSI는 C++ 기반의 경량 레이어로, 자바스크립트 코드가 네이티브 객체를 직접적이고 동기적으로 참조 및 호출할 수 있게 해준다 [3, 6]. 직렬화 과정을 생략하게 해 주어 스레드 간 실시간에 가까운 고성능 통신을 가능하게 한다 [3, 6].
* **패브릭 렌더러 (Fabric Renderer):** 새로운 UI 렌더링 시스템인 패브릭은 C++ 환경에서 섀도 트리(Shadow Tree)를 생성해 스레드 간 공유를 가능하게 한다 [7]. 비동기적인 왕복 과정 없이 네이티브 뷰를 측정하고 렌더링할 수 있어, 동시 렌더링(Concurrent Rendering)과 동기적 레이아웃 계산을 지원하며 UI의 반응성을 대폭 향상시킨다 [6, 7].
* **터보모듈 (TurboModules):** 기존에는 앱 시작 시 모든 네이티브 모듈을 초기화해야 했으나, 터보모듈은 차세대 네이티브 모듈 시스템으로서 모듈이 필요할 때만 로드되는 지연 로딩(Lazy loading) 방식을 취한다 [6, 8]. 동기식 네이티브 호출을 지원할 뿐만 아니라, 앱의 초기 시작 시간과 메모리 사용량을 효과적으로 줄여준다 [6, 8].
* **코드젠 (Codegen):** 동적 타입의 자바스크립트 환경과 정적 타입의 네이티브 환경(Java/Kotlin, Objective-C/Swift) 간의 안전한 통신을 보장하기 위해 도입되었다 [9]. 빌드 시점에 타입 정의를 분석하여 필요한 C++ 보일러플레이트 코드를 자동 생성하므로, 런타임이 아닌 컴파일 타임에 오류를 잡아내고 전반적인 개발자 경험(DX)을 개선한다 [9].
## 매 핵심
## ⚖️ Trade-offs & Caveats
* **생태계 적응을 위한 과도기:** React Native의 신규 아키텍처는 프레임워크의 기반을 뒤흔드는 거대한 변화이므로, 서드파티 라이브러리 및 패키지들이 새로운 구조(TurboModules, Fabric 등)에 완벽하게 호환되고 채택을 완료할 때까지 일정 시간이 필요하다 [6].
* **도입 및 마이그레이션 비용:** 신규 아키텍처가 전면적인 기본값으로 완전히 정착되기 전까지의 이전 버전(예: 0.73) 환경에서는 이를 옵트인(Opt-in) 방식으로 활성화해야 한다 [2]. 앱에 통합된 기존 커스텀 네이티브 모듈이나 특정 라이브러리들이 JSI 기반의 동기적 호출 구조를 지원하지 않을 경우, 이에 대한 마이그레이션이나 검증 작업이 추가로 요구될 수 있다 [2, 6].
### 매 Old Bridge 의 한계
- 매 모든 native↔JS 호출 의 JSON serialize → batched async queue.
- 매 startup 에 module table 전체 의 eager registration.
- 매 60fps 의 16.67ms budget 에 round-trip ≥ 2 frames 의 발생.
- 매 frame-locked animation/gesture 의 jank.
---
*Last updated: 2026-05-03*
### 매 New Architecture 의 3 pillars
1. **JSI**: C++ host object 의 JS-runtime direct binding. Hermes/JSC interchangeable.
2. **TurboModules**: native module 의 lazy load + sync invocation.
3. **Fabric**: shadow tree 의 C++ rewrite — concurrent rendering + thread-safe layout.
### 매 Codegen 의 역할
- 매 TS/Flow spec → C++/Java/ObjC scaffolding 의 자동 생성.
- 매 type safety + boilerplate 의 elimination.
## 💻 패턴
### TurboModule spec (TS)
```typescript
// NativeCalculator.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): number; // sync!
fetchUserAsync(id: string): Promise<{name: string}>;
}
export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
```
### Fabric component spec
```typescript
// MyViewNativeComponent.ts
import { codegenNativeComponent, ViewProps } from 'react-native';
import type { Int32 } from 'react-native/Libraries/Types/CodegenTypes';
interface NativeProps extends ViewProps {
intensity: Int32;
color?: string;
}
export default codegenNativeComponent<NativeProps>('MyView');
```
### JSI host function (C++)
```cpp
// 매 native side 에서 JS function 의 expose
auto add = jsi::Function::createFromHostFunction(
rt, jsi::PropNameID::forAscii(rt, "add"), 2,
[](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t) {
return jsi::Value(args[0].asNumber() + args[1].asNumber());
});
rt.global().setProperty(rt, "add", std::move(add));
```
### Bridgeless mode 활성화
```javascript
// react-native.config.js
module.exports = {
project: {
ios: {},
android: {},
},
// 매 RN 0.74+ 부터 default true
reactNativeArchitectures: 'arm64-v8a,x86_64',
};
```
```ruby
# ios/Podfile
use_react_native!(
:path => config[:reactNativePath],
:fabric_enabled => true,
:new_arch_enabled => true,
)
```
### 매 sync layout measurement
```typescript
import { findNodeHandle, UIManager } from 'react-native';
// 매 Fabric 에서 sync measure 의 가능
const handle = findNodeHandle(ref.current);
UIManager.measureInWindow(handle, (x, y, w, h) => {
// 매 동일 frame 안에 layout 완료 의 보장
});
```
### Reanimated 3 worklet (JSI 활용)
```typescript
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
const offset = useSharedValue(0);
const style = useAnimatedStyle(() => ({
transform: [{ translateX: withSpring(offset.value) }],
}));
// 매 UI thread 에서 worklet 의 directly run — bridge 없음
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 신규 RN app (2026) | Bridgeless default — 매 그대로 사용 |
| 매 legacy native module 다수 | Interop layer 의 활용 (자동 shim) |
| 매 60Hz+ animation 필요 | Reanimated 3 + Fabric 의 mandatory |
| 매 startup 시간 critical | TurboModule lazy init 의 활용 |
**기본값**: 매 RN 0.76+ 의 Bridgeless on by default — 매 비활성화 의 X.
## 🔗 Graph
- 부모: [[React_Native]] · [[React_Native_New_Architecture]]
- 변형: [[Fabric]] · [[Fabric_Renderer]] · [[TurboModules]] · [[JSI (JavaScript Interface)]]
- 응용: [[Hermes]] · [[Hermes_Engine]] · [[Codegen]]
- Adjacent: [[Cross-platform_Mobile_Development_Frameworks]] · [[Flutter]]
## 🤖 LLM 활용
**언제**: 매 RN 0.74+ green-field project, 매 native↔JS round-trip 의 perf bottleneck 진단, 매 Reanimated/Skia/Gesture-Handler 의 깊은 통합.
**언제 X**: 매 Expo Go (legacy bridge only) 환경, 매 unmaintained native module 에 의존하는 코드베이스.
## ❌ 안티패턴
- **매 mixed arch leak**: 매 NEW_ARCH_ENABLED 의 절반만 활성화 → 매 일부 module 의 silent fallback.
- **매 sync abuse**: 매 모든 호출 의 sync 화 → 매 JS thread 의 block.
- **매 Codegen skip**: 매 manual binding 의 작성 — 매 type drift 의 발생.
- **매 bridge pattern 재현**: 매 NativeEventEmitter 의 남용 — 매 JSI host object 의 selection.
## 🧪 검증 / 중복
- Verified (React Native 공식 docs reactnative.dev/architecture, RN 0.76 release notes 2024-10).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Bridgeless 의 JSI/Fabric/TurboModule pillars 정리 |
+161 -65
View File
@@ -2,93 +2,189 @@
id: wiki-2026-0508-buffer-allocation
title: Buffer Allocation
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-B20BA9]
aliases: [ArrayBuffer Allocation, Typed Array Pool]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [performance, memory, buffer, typed-array, gc]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Buffer Allocation"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript/TypeScript
framework: Browser/Node/WebGPU
---
# [[Buffer Allocation|Buffer Allocation]]
# Buffer Allocation
## 📌 한 줄 통찰 (The Karpathy Summary)
> 버퍼 할당(Buffer Allocation)[[WebGL|WebGL]] 및 [[WebGPU|WebGPU]] 환경에서 정점, 인덱스, 인스턴스 변환 행렬 등의 데이터를 저장하기 위해 GPU 메모리 공간을 확보하는 과정입니다. 렌더링 중 동적으로 버퍼 크기를 늘리거나 빈번하게 데이터를 업데이트할 경우 심각한 프레임 지연 및 메모리 오류가 발생할 수 있습니다. 따라서 최대 예상치에 맞춰 사전에 버퍼를 할당하고, 재사용 가능한 영구적인 GPU 버퍼를 활용하는 것이 3D 애플리케이션 성능 최적화에 필수적입니다.
## 한 줄
> **"매 buffer 매 reuse 매 GC 의 X"**. Buffer allocation은 binary data buffer (ArrayBuffer / Typed Array)의 effective lifecycle 관리 — naive `new Uint8Array(N)` per operation은 GC churn을 유발해 frame budget을 깬다. 2026 WebGPU / WebCodecs / canvas heavy app 의 must-skill.
## 📖 구조화된 지식 (Synthesized Content)
* **동적 버퍼 확장의 성능 병목 현상:** 인스턴싱([[Instancing|Instancing]]) 시스템이 초기에 낮은 버퍼 용량으로 시작하여 런타임에 동적으로 크기를 확장(Growing Buffer)하게 되면, 심각한 성능 지연(예: 앱 시작 시 수 초간의 멈춤 현상) 및 메모리 할당 오류가 발생할 수 있습니다 [1, 2].
* **최대 용량 사전 할당 (Preallocation):** 이를 방지하기 위해 엔진 시작 시점에 예상되는 최대 인스턴스 수에 맞춰 충분한 크기의 버퍼를 사전에 할당하는 방식이 권장됩니다 [1]. 여유 용량(Excess capacity)을 미리 확보하는 것은 약간의 메모리 오버헤드를 발생시키지만, 실제 렌더링 연산 비용에는 부정적인 영향을 주지 않습니다 [3].
* **GPU 영구 버퍼 및 업데이트 최소화:** WebGPU 환경에서 매 프레임 수많은 작은 버퍼를 반복 업데이트하는 것은 비용이 매우 큽니다 [4]. 따라서 `[[instancedArray|instancedArray]]`와 같은 영구적인 GPU 버퍼를 생성하여 사용하면 프레임 간 데이터가 유지되어, 성능 저하의 주원인인 CPU-GPU 간의 데이터 전송을 제거할 수 있습니다 [4, 5].
* **오브젝트 풀링(Object [[Pooling|Pooling]]) 활용:** 객체를 빈번하게 생성하고 파괴하는 작업은 버퍼 할당 오버헤드와 가비지 컬렉션(GC)에 의한 일시 정지를 유발합니다. 런타임 할당 스파이크를 피하려면 로딩 단계에서 풀을 미리 데워두는(Pre-warm) 방식의 오브젝트 풀링을 사용해야 합니다 [6].
* **버퍼 재할당 시 메모리 누수 주의:** WebGL 컨텍스트는 디바이스에 따라 유한한 메모리 한도(일반적으로 256MB~1GB)를 가지며, 한도를 초과하면 뷰어가 다운될 수 있습니다 [7]. 또한, 기존의 인스턴스 메쉬 자원을 깔끔하게 폐기(Dispose)하지 못한 상태에서 동적으로 버퍼 용량을 늘리려 할 경우 메모리 누수가 발생할 수 있습니다 [8].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 cost source
- **Allocation**: V8/SpiderMonkey backing-store malloc + zero-fill.
- **GC**: large allocation → Old-gen → expensive sweep.
- **Cache miss**: 매 fresh memory 의 cold cache.
- **Fragmentation**: many sizes → heap 의 fragmented.
## 🔗 지식 연결 (Graph)
- **Related Topics:** GPU Instancing, [[Memory Management|Memory Management]], Object Pooling, [[Garbage Collection|Garbage Collection]]
- **Projects/Contexts:** Three.js, [[Needle Engine|Needle Engine]], [[WebGPU|WebGPU]]
- **Contradictions/Notes:** 소스에서는 실행 중 버퍼 크기를 동적으로 늘리는 방식(Dynamic Growth)은 성능 지연과 오류를 낳으므로, 초기에 넉넉하게 메모리 공간을 사전 할당(Preallocate)하는 방식이 훨씬 안정적이라고 강조합니다 [1-3].
### 매 strategy
- **Pool / freelist**: 매 size class 매 reuse.
- **Subarray view**: single big buffer + slice views.
- **Pre-allocation**: peak size 부터 allocate.
- **SharedArrayBuffer**: cross-thread, no copy.
---
*Last updated: 2026-04-19*
### 매 응용
1. Audio / video frame buffer.
2. WebGL / WebGPU vertex / index buffer.
3. WebSocket binary message parser.
---
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### Simple buffer pool
```ts
class BufferPool {
private pool: Uint8Array[] = [];
constructor(private size: number, private max = 32) {}
**언제 이 지식을 쓰는가:**
- *(TODO)*
acquire(): Uint8Array {
return this.pool.pop() ?? new Uint8Array(this.size);
}
**언제 쓰면 안 되는가:**
- *(TODO)*
release(buf: Uint8Array) {
if (this.pool.length < this.max) {
buf.fill(0);
this.pool.push(buf);
}
}
}
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const pool = new BufferPool(4096);
const b = pool.acquire();
// use ...
pool.release(b);
```
## 🤔 의사결정 기준 (Decision Criteria)
### Size-class pool
```ts
class SizeClassPool {
private classes = new Map<number, Uint8Array[]>();
**선택 A를 써야 할 때:**
- *(TODO)*
private classOf(n: number): number {
return Math.pow(2, Math.ceil(Math.log2(Math.max(n, 16))));
}
**선택 B를 써야 할 때:**
- *(TODO)*
acquire(n: number): Uint8Array {
const cls = this.classOf(n);
const list = this.classes.get(cls);
return (list?.pop() ?? new Uint8Array(cls)).subarray(0, n);
}
**기본값:**
> *(TODO)*
release(buf: Uint8Array) {
const cls = buf.buffer.byteLength;
if (!this.classes.has(cls)) this.classes.set(cls, []);
this.classes.get(cls)!.push(new Uint8Array(buf.buffer));
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Single backing buffer + views
```ts
const big = new ArrayBuffer(1024 * 1024); // 1MB
const headers = new Uint32Array(big, 0, 256); // 1KB header
const body = new Uint8Array(big, 1024, 1024 * 1023); // remainder
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### WebSocket binary parsing — no copy
```ts
ws.binaryType = 'arraybuffer';
ws.onmessage = (e: MessageEvent<ArrayBuffer>) => {
const dv = new DataView(e.data);
const type = dv.getUint8(0);
const length = dv.getUint32(1, true);
const payload = new Uint8Array(e.data, 5, length);
handle(type, payload);
};
```
### SharedArrayBuffer ring buffer (worker comms)
```ts
// main
const sab = new SharedArrayBuffer(1024);
const view = new Int32Array(sab);
worker.postMessage(sab);
// worker — Atomics 매 lock-free synchronization
self.onmessage = (e) => {
const view = new Int32Array(e.data);
Atomics.store(view, 0, 42);
Atomics.notify(view, 0, 1);
};
```
### Reusable canvas pixel buffer
```ts
class FrameRecycler {
private buffers: ImageData[] = [];
acquire(w: number, h: number) {
return this.buffers.find(b => b.width === w && b.height === h)
?? new ImageData(w, h);
}
release(b: ImageData) {
if (this.buffers.length < 4) this.buffers.push(b);
}
}
```
### Detecting allocation hot spots
```ts
// 매 dev-only — 매 wrap allocator 매 trace
const _orig = Uint8Array;
let count = 0;
(globalThis as any).Uint8Array = function (...args: any[]) {
count++;
if (count % 1000 === 0) console.warn('Uint8Array allocations:', count);
return new _orig(...args);
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Per-frame temp buffer | pool with size class |
| Streaming binary protocol | preallocated parser buffer |
| Cross-thread share | SharedArrayBuffer + Atomics |
| GPU upload | persistent GPU buffer + map/unmap |
| Rare large alloc | direct allocate |
**기본값**: measure GC pressure first; pool only when allocator shows up in profile.
## 🔗 Graph
- 부모: [[Memory Management]] · [[Performance]]
- 변형: [[Object Pool]] · [[Arena Allocation]]
- 응용: [[WebGPU]] · [[WebCodecs]] · [[WebSocket]]
- Adjacent: [[SharedArrayBuffer]] · [[Typed Array]] · [[Garbage Collection]]
## 🤖 LLM 활용
**언제**: pool implementation scaffold, view layout calculation, ring buffer design.
**언제 X**: 매 GC actual measurement — Chrome Memory profiler.
## ❌ 안티패턴
- **Premature pool**: 매 micro-opt — measure first.
- **Pool 무제한**: 매 leak — max size cap.
- **Subarray after detach**: transferred buffer — invalid.
- **Concurrent writes without Atomics**: SharedArrayBuffer 매 race.
- **Forget to zero-fill on release**: 매 stale data leak across owners.
## 🧪 검증 / 중복
- Verified (V8 blog, MDN ArrayBuffer, WebGPU spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — buffer pool + view layout pattern |
@@ -2,123 +2,186 @@
id: wiki-2026-0508-bundle-size-optimization
title: Bundle Size Optimization
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [JS Bundle Optimization, Web Bundle Reduction]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [bundle, performance, webpack, vite, tree-shaking]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript/TypeScript
framework: Vite/Rollup/Webpack
---
## 📌 한 줄 통찰 (The Karpathy Summary)
Bundle Size Optimization(번들 크기 최적화)은 클라이언트로 전송되는 자바스크립트 자산의 물리적 용량을 최소화하여 초기 로딩 성능(LCP)과 런타임 반응성(TBT/INP)을 개선하는 기술적 공정이다. 코드 분할(Code Splitting), 지연 로딩(Lazy Loading), 트리 쉐이킹 등을 통해 브라우저의 파싱 및 실행 오버헤드를 근본적으로 줄이는 것을 목표로 한다.
# Bundle Size Optimization
## 📖 구조화된 지식 (Synthesized Content)
1. **번들 팽창의 원인 진단**
- 단일 엔트리 포인트(`index.js`)에 모든 종속성(React, heavy libraries)이 결합된 구조.
- 무분별한 Eager Import와 거대한 전이적 종속성(Transitive Dependencies)으로 인한 메인 스레드 점유율 상승.
2. **코드 분할 및 지연 로딩 (Strategic Splitting)**
- `React.lazy()``<Suspense>`를 활용하여 특정 라우트나 무거운 UI 요소(차트, 모달 등)를 독립적인 청크(Chunk)로 분리.
- 사용자가 필요로 하는 시점에만 코드를 로드하여 초기 번들 페이로드를 획기적으로 절감.
3. **벤더 분할 전략 (Vendor Splitting)**
- Vite/Rollup의 `manualChunks` 설정을 통해 자주 변경되지 않는 핵심 라이브러리(React 등)를 별도의 청크로 고정.
- 브라우저 캐싱 효율을 극대화하여 재방문자의 로딩 속도를 가속화.
4. **서버 컴포넌트(RSC)를 통한 근본적 절감**
- 상호작용이 없는 정적 UI를 서버에서 렌더링하여 클라이언트로 전송되는 JS 페이로드를 '0'으로 수렴시키는 아키텍처 적용.
5. **분석 및 정제 도구 활용**
- `rollup-plugin-visualizer` 또는 Webpack Bundle Analyzer를 통해 번들 내부의 'Bloat'을 시각적으로 식별하고 제거.
## 매 한 줄
> **"매 byte 매 less 매 user time 매 less"**. Bundle size optimization은 production JS/CSS payload를 줄여 LCP/INP/TBT 개선 + mobile-first user 의 perceived speed 개선. 2026 standard tooling: Vite + Rollup tree-shaking, modern bundle analysis (Bundle Buddy, esbuild-visualizer), bundle budgets enforcement.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **워터폴(Waterfall) 현상**: 지연 로딩을 남발할 경우 청크 간의 의존성으로 인해 순차적 로딩 지연이 발생하여 체감 성능이 오히려 저하될 수 있다.
- **네트워크 요청 수 증가**: 번들을 너무 작게 쪼개면 HTTP 요청 수가 급증하여 네트워크 오버헤드가 발생할 수 있으므로 적절한 청크 사이즈(예: 30KB~100KB) 유지가 필요하다.
- **캐시 무효화 관리**: 청크 분할 전략이 잘못될 경우 작은 코드 수정에도 모든 벤더 청크의 해시가 변경되어 캐시 효율이 떨어질 수 있다.
## 매 핵심
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[Code Splitting]]
* [[Core_Web_Vitals]]
* [[Hydration]]
* [[Index]]
* [[Lazy Loading]]
* [[Optimization]]
* [[React]]
* [[Research]]
* [[Rollup]]
### 매 4 lever
- **Tree shaking**: ESM only, sideEffects:false, no re-export wildcards.
- **Code splitting**: route / component lazy import.
- **Compression**: brotli > gzip; precompress at build.
- **Dependency surgery**: heavy lib → lighter alt or self-implement.
### Related Concepts
- **Code Splitting**: 번들을 물리적으로 분리하는 구현 패턴 (관계: 실천 방법)
- **Core Web Vitals**: 번들 최적화의 성공 여부를 측정하는 정량적 지표 (관계: 성능 평가)
- **Hydration**: 번들 크기가 클수록 직접적으로 지연되는 클라이언트 활성화 과정 (관계: 직접 영향)
### 매 측정 우선
- Bundle visualizer (rollup-plugin-visualizer, source-map-explorer).
- Bundle budget in CI (e.g., size-limit, bundlesize).
- Real device testing (slow 3G profile).
### Deeper Research Questions
1. Vite의 `manualChunks` 설정 시 변동 주기가 다른 라이브러리들을 어떻게 그룹화하는 것이 캐시 히트율에 가장 유리한가?
2. `React.lazy`를 비동기 데이터 페칭 로직과 결합할 때 레이턴시를 최소화하는 프리페칭(Prefetching) 전략은?
3. 트리 쉐이킹이 작동하지 않는 CommonJS 기반 라이브러리를 ESM 환경에서 어떻게 효율적으로 격리할 것인가?
4. 서버 컴포넌트 환경에서 클라이언트 번들에 의도치 않게 포함되는 서버 사이드 로직을 어떻게 정적으로 감지할 것인가?
5. 번들 압축 기법(Gzip vs Brotli)과 번들 크기 최적화 사이의 실제 사용자 로딩 시간 상관관계는?
### 매 응용
1. Lazy-load route chunks.
2. Remove unused locales (date-fns, moment).
3. Replace lodash with native / lodash-es.
### Practical Application Contexts
- **Vite Configuration**: `vite.config.ts`에서 Rollup 옵션을 조정하여 벤더 청크 분리.
- **Performance Budgeting**: CI/CD 단계에서 특정 번들 사이즈 초과 시 빌드를 실패하게 만드는 성능 예산 설정.
## 💻 패턴
### Adjacent Topics
- **Brotli / Gzip Compression**
- **Tree Shaking & ES Modules**
- **HTTP/2 & HTTP/3 Multi-plexing**
### Vite + visualizer
```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export default defineConfig({
plugins: [
visualizer({ filename: 'stats.html', gzipSize: true, brotliSize: true })
],
build: {
rollupOptions: {
output: {
manualChunks: {
react: ['react', 'react-dom'],
vendor: ['date-fns', 'zustand']
}
}
}
}
});
```
## 🤔 의사결정 기준 (Decision Criteria)
### Route-level code split (React)
```tsx
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
**선택 A를 써야 할 때:**
- *(TODO)*
<Suspense fallback={<Skeleton />}>
<Dashboard />
</Suspense>
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Dynamic import for rare path
```ts
async function exportToPDF(data: Item[]) {
const { jsPDF } = await import('jspdf');
const doc = new jsPDF();
doc.text(JSON.stringify(data), 10, 10);
doc.save('out.pdf');
}
```
**기본값:**
> *(TODO)*
### Replace heavy lib
```ts
// X moment (~290KB)
import moment from 'moment';
moment().format('YYYY-MM-DD');
## ❌ 안티패턴 (Anti-Patterns)
// O Intl (built-in, 0KB)
new Intl.DateTimeFormat('en-CA').format(new Date());
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// O date-fns/format (tree-shakeable, ~3KB)
import { format } from 'date-fns/format';
format(new Date(), 'yyyy-MM-dd');
```
### sideEffects flag
```json
// package.json — library author 측
{
"name": "my-lib",
"type": "module",
"sideEffects": false,
"exports": {
".": {
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
}
}
}
```
### size-limit budget enforcement
```json
// package.json
{
"scripts": {
"size": "size-limit"
},
"size-limit": [
{ "path": "dist/index.js", "limit": "50 KB" },
{ "path": "dist/vendor.js", "limit": "120 KB" }
]
}
```
### Compression at build (brotli)
```ts
import compression from 'vite-plugin-compression2';
export default defineConfig({
plugins: [
compression({ algorithm: 'brotliCompress', exclude: [/\.(br)$/, /\.(gz)$/] })
]
});
```
### Server: strip locales from dayjs
```ts
import dayjs from 'dayjs';
import 'dayjs/locale/ko'; // 매 필요한 것만
dayjs.locale('ko');
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Initial bundle > 200KB | route split + lazy load |
| Single heavy lib | replace 또는 dynamic import |
| Multi-tenant build | per-tenant treeshake config |
| Library publish | ESM + `sideEffects:false` |
| Edge runtime | bundle ≤ 1MB 가까이 strict budget |
**기본값**: measure first → split → compress → swap heavy deps.
## 🔗 Graph
- 부모: [[Frontend Performance]] · [[Build Tools]]
- 변형: [[Code Splitting]] · [[Tree Shaking]]
- 응용: [[Core Web Vitals]] · [[LCP]]
- Adjacent: [[Vite]] · [[Rollup]] · [[esbuild]]
## 🤖 LLM 활용
**언제**: webpack/vite config audit, lib alternative suggestion, bundle analyzer interpretation.
**언제 X**: 매 production 매 swap deploy — actual measurement 필수.
## ❌ 안티패턴
- **CommonJS lib import**: tree shaking blocked — ESM 사용.
- **`import * as foo`**: bundler 매 mark 매 모든 export used.
- **Polyfill 전체**: target browser baseline + browserslist으로 narrow.
- **Single chunk all**: SPA → 매 long initial — split per route.
- **Dev source maps in prod**: ship source map only via separate URL or skip.
## 🧪 검증 / 중복
- Verified (web.dev bundle size guide, Vite docs, size-limit GitHub).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — bundle optim 4 lever + Vite/size-limit pattern |
+164 -71
View File
@@ -2,96 +2,189 @@
id: wiki-2026-0508-cpu-overhead
title: CPU Overhead
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-38FA31]
aliases: [CPU Cost, JS Main Thread Cost]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [performance, cpu, main-thread, profiling]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - CPU Overhead"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript
framework: Browser/Node
---
# [[CPU Overhead|CPU Overhead]]
# CPU Overhead
## 📌 한 줄 통찰 (The Karpathy Summary)
> CPU 오버헤드(CPU Overhead)는 웹 그래픽 렌더링 및 브라우저 실행 중에 중앙 처리 장치(CPU)에 가해지는 계산 부담 및 처리 지연을 의미합니다 [1, 2]. [[WebGL|WebGL]]과 같은 기존 API에서는 단일 스레드 기반의 명령 제출과 JavaScript 실행이 CPU 병목 현상을 일으켜 GPU가 유휴 상태에 빠지게 만듭니다 [2, 3]. [[WebGPU|WebGPU]]와 같은 최신 API는 멀티 스레드 명령 생성과 컴퓨트 셰이더를 통한 연산 오프로딩을 통해 이러한 CPU 오버헤드를 대폭 감소시킵니다 [4, 5].
## 한 줄
> **"매 main thread 매 free 매 fast UI"**. CPU overhead는 JS execution / parsing / hydration / re-render에 소비되는 main-thread time — 이게 길어지면 INP가 무너지고 user input이 lag한다. 2026 INP가 LCP를 대체한 third Core Web Vital이 되어 CPU profile + scheduling이 frontend 의 first concern.
## 📖 구조화된 지식 (Synthesized Content)
* **WebGL에서의 CPU 오버헤드 원인:**
WebGL은 단일 스레드 실행 모델로 작동하여 모든 드로우 콜([[Draw Call|Draw Call]]), 상태 변경, 리소스 업로드가 순차적으로 실행되며 메인 스레드를 차단합니다 [2, 3]. 또한 브라우저의 보안 검사, 프로세스 격리를 위한 마샬링(marshalling), 그리고 ANGLE을 통한 API 변환(OpenGL ES를 [[Direct3D|Direct3D]]로 변환) 과정은 드로우 콜마다 고정적인 오버헤드를 발생시킵니다 [6, 7]. 이는 결과적으로 GPU가 유휴 상태임에도 CPU가 병목이 되는 현상을 초래합니다 [6, 8].
## 매 핵심
* **성능 및 사용자 환경에 미치는 영향:**
CPU 오버헤드는 프레임 드롭, 미세 지연(Micro-latency) 및 화면 끊김(Stuttering)의 주요 원인이 됩니다 [3, 9, 10]. 예를 들어 3D 가우시안 스플래팅(3DGS)과 같은 데이터 집약적 렌더링에서 수백만 개의 객체를 CPU에서 정렬할 경우, CPU-GPU 간 대규모 버퍼 전송과 동기화 병목 현상이 발생하여 프레임 예산을 초과하게 됩니다 [11, 12]. 특히 모바일 기기에서는 높은 CPU 오버헤드가 과도한 전력 소비와 발열로 이어지며, 이는 곧 열 쓰로틀링(Thermal throttling)에 의한 심각한 성능 저하를 유발합니다 [13-15].
### 매 source
- **Parse + compile**: download된 JS bytes → AST → bytecode (V8 측정 시 KB 당 ~1ms low-end mobile).
- **Hydration**: SSR HTML 위 React/Vue 매 attach.
- **Re-render**: state change → diff → DOM commit.
- **Long task** (>50ms): block input.
* **WebGPU와 구조적 최적화를 통한 해결:**
WebGPU는 멀티 스레드를 통한 렌더링 명령 준비와 명시적이고 정적인 리소스 관리(GPU 리소스 읽기 전용화 등)를 지원하여 CPU 측의 재검증 오버헤드를 획기적으로 줄입니다 [4, 5, 16-18]. 컴퓨트 셰이더를 사용하여 물리 시뮬레이션이나 입자 시스템 같은 연산 논리를 GPU로 오프로딩하면 CPU-GPU 간의 왕복 통신과 JavaScript 실행 지연을 최소화하는 'GPU 주도(GPU-driven)' 렌더링이 가능해집니다 [13, 19]. 또한, 엔진 차원에서는 인스턴싱이나 배칭([[Batching|Batching]])을 통해 절대적인 드로우 콜 횟수를 최소화하는 것이 오버헤드 감소의 핵심입니다 [8, 20].
### 매 측정
- Chrome Performance panel — flame chart, "Long tasks".
- `PerformanceObserver` API on `longtask`.
- React Profiler / Vue Devtools timeline.
- Web Vitals — INP, TBT.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 응용
1. JS payload 줄이기 → less parse.
2. Hydration partial / streaming.
3. Heavy work → Web Worker / requestIdleCallback / startTransition.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[WebGL|WebGL]], WebGPU, Draw Calls, Micro-latency, [[Compute Shaders|Compute Shaders]]
- **Projects/Contexts:** [[3D_Gaussian_Splatting|3D Gaussian Splatting]] (3DGS), WebSplatter, [[ANGLE|ANGLE]]
- **Contradictions/Notes:** 제공된 소스들 사이에서 명백한 모순은 발견되지 않습니다. 모든 소스가 WebGL의 단일 스레드 아키텍처가 야기하는 CPU 병목 현상을 WebGPU의 멀티 스레드 도입 및 명시적 리소스 관리로 극복한다는 공통된 기술적 진화를 설명하고 있습니다.
## 💻 패턴
---
*Last updated: 2026-04-19*
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Long task observer
```ts
const obs = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn(`Long task: ${entry.duration.toFixed(0)}ms`, entry);
}
}
});
obs.observe({ type: 'longtask', buffered: true });
```
## 🤔 의사결정 기준 (Decision Criteria)
### Yield to main thread
```ts
function yieldToMain() {
return new Promise(resolve => setTimeout(resolve, 0));
}
**선택 A를 써야 할 때:**
- *(TODO)*
async function processChunks(items: Item[]) {
for (let i = 0; i < items.length; i++) {
process(items[i]);
if (i % 100 === 0) await yieldToMain();
}
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### scheduler.yield (Chrome 129+)
```ts
async function processBig(items: Item[]) {
for (const item of items) {
process(item);
if ('scheduler' in window && 'yield' in (window as any).scheduler) {
await (window as any).scheduler.yield();
}
}
}
```
**기본값:**
> *(TODO)*
### Web Worker offload
```ts
// worker.ts
self.onmessage = (e) => {
const result = heavyTransform(e.data);
self.postMessage(result);
};
## ❌ 안티패턴 (Anti-Patterns)
// main.ts
const w = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
w.postMessage(largeData);
w.onmessage = (e) => render(e.data);
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### React startTransition
```tsx
import { startTransition, useState } from 'react';
function Search() {
const [q, setQ] = useState('');
const [results, setResults] = useState<Item[]>([]);
function onChange(e) {
setQ(e.target.value); // urgent
startTransition(() => {
setResults(filter(allItems, e.target.value)); // background
});
}
return <input value={q} onChange={onChange} />;
}
```
### useDeferredValue
```tsx
function Page({ filter }) {
const deferredFilter = useDeferredValue(filter);
const items = useMemo(() => filterBig(deferredFilter), [deferredFilter]);
return <List items={items} />;
}
```
### requestIdleCallback for non-critical
```ts
const work = [...];
function schedule() {
if (!work.length) return;
requestIdleCallback((deadline) => {
while (work.length && deadline.timeRemaining() > 0) {
doOne(work.shift());
}
schedule();
});
}
schedule();
```
### Avoid layout thrash
```ts
// X — 매 read after write 매 force reflow
els.forEach(el => {
el.style.width = '100px';
console.log(el.offsetWidth); // forced sync layout
});
// O — 매 batch read, batch write
const widths = els.map(el => el.offsetWidth);
els.forEach((el, i) => el.style.width = widths[i] + 1 + 'px');
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Heavy compute (parse/transform) | Web Worker |
| Long list render | virtualization (TanStack Virtual) |
| Filter on input | useDeferredValue / startTransition |
| Background prefetch | requestIdleCallback |
| Animation | CSS / RAF, no JS-driven layout |
**기본값**: measure → smallest fix → re-measure.
## 🔗 Graph
- 부모: [[Frontend Performance]] · [[Core Web Vitals]]
- 변형: [[Long Task]] · [[INP]]
- 응용: [[Web Worker]] · [[Concurrent Rendering]]
- Adjacent: [[Bundle Size Optimization]] · [[Hydration]]
## 🤖 LLM 활용
**언제**: long task identification, scheduler API generation, INP debug script.
**언제 X**: real device profiling — DevTools / WebPageTest 필수.
## ❌ 안티패턴
- **JS-driven animation**: setInterval + style 변경 — RAF / CSS 사용.
- **Sync XMLHttpRequest**: 매 main block — fetch async 사용.
- **Force layout in loop**: read after write — batch.
- **Hydration of static page**: islands / partial hydration.
- **Massive context provider**: 매 모든 child re-render — split context.
## 🧪 검증 / 중복
- Verified (web.dev INP guide, Chrome scheduler API, React 19 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CPU overhead pattern + scheduler API |
+20 -92
View File
@@ -2,104 +2,32 @@
id: wiki-2026-0508-css-grid-및-flexbox
title: CSS Grid 및 Flexbox
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: css-grid
duplicate_of: "[[CSS Grid]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, css, grid, flexbox]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[CSS Grid 및 Flexbox|CSS Grid 및 Flexbox]]
# CSS Grid 및 Flexbox
## 📌 한 줄 통찰 (The Karpathy Summary)
CSS [[Flexbox|Flexbox]]와 [[CSS Grid|CSS Grid]]는 웹 페이지의 요소들을 배치하고 정렬하기 위해 도입된 최신 CSS 레이아웃 모듈입니다 [1-3]. Flexbox는 행(Row)이나 열(Column) 중 하나의 방향으로 요소를 배치하는 1차원 레이아웃에 특화되어 있으며, CSS Grid는 행과 열을 동시에 제어하는 2차원 레이아웃 시스템입니다 [4-6]. 이 두 기술은 과거의 float이나 복잡한 위치 지정(positioning) 방식을 대체하여, 예측 가능하고 유지보수가 용이한 반응형 디자인을 구축하는 핵심 도구로 사용됩니다 [7-9].
> **이 문서는 [[CSS Grid]] 의 중복본입니다.** Canonical 문서로 redirect. Flexbox 단독 내용은 [[Flexbox]] 참조.
## 📖 구조화된 지식 (Synthesized Content)
**1. Flexbox (1차원 레이아웃 및 컴포넌트 정렬)**
* **목적 및 특징:** Flexbox는 단일 차원(행 또는 열)에서 항목을 정렬하고 간격을 분배하는 데 최적화되어 있습니다 [4, 9, 10]. 주로 내비게이션 바, 폼 필드, 카드 컴포넌트 내의 텍스트와 이미지 정렬 등 소규모 레이아웃에 적합합니다 [3, 11, 12].
* **동작 원리 (Content-out):** Flexbox는 '콘텐츠 중심(Content-out)'으로 동작합니다. 요소들의 내부 콘텐츠 크기에 따라 항목이 커지거나(`flex-grow`) 줄어들며(`flex-shrink`), 가용 공간을 유연하게 채웁니다 [1, 13-16]. 화면 크기가 줄어들면 `flex-wrap` 속성을 통해 자연스럽게 다음 줄로 넘어가게 할 수 있습니다 [17, 18].
## 핵심 요약 (specialization)
- CSS Grid: 2D layout (row + column 동시).
- Flexbox: 1D layout (row 또는 column).
- 매 두 layout 매 complementary — Grid 으로 page macro layout, Flexbox 로 component micro alignment.
**2. CSS Grid (2차원 레이아웃 및 페이지 구조화)**
* **목적 및 특징:** CSS Grid는 행(Row)과 열(Column)을 동시에 다룰 수 있는 가장 강력한 2차원 레이아웃 도구입니다 [5, 6, 19]. 전체 페이지 구조, 데이터 대시보드, 복잡한 이미지 갤러리 등 정밀한 배치가 필요한 대규모 레이아웃에 적합합니다 [20-22].
* **동작 원리 (Layout-in):** CSS Grid는 '레이아웃 중심(Layout-in)'으로 동작합니다. 먼저 그리드 구조(행과 열의 틀)를 정의한 뒤, 그 틀 안의 특정 셀이나 영역에 콘텐츠를 배치합니다 [16, 23]. 아이템들이 여러 행과 열에 걸쳐 병합(spanning)되거나 겹치도록 정밀하게 제어할 수 있습니다 [22, 24, 25].
## 🔗 Graph
- 부모: [[CSS Grid]] (canonical) · [[Flexbox]]
**3. 반응형 디자인에서의 역할**
* 두 기술 모두 고정된 픽셀 폭 대신 유연한 유닛과 논리를 사용하여 수많은 미디어 쿼리(Media Queries)를 줄이는 데 기여합니다 [26, 27].
* 예를 들어, CSS Grid의 `auto-fit` 속성과 `minmax()` 함수를 결합하면 화면의 가용 공간에 맞춰 열의 개수를 동적으로 자동 조절하는 반응형 그리드를 손쉽게 구현할 수 있습니다 [28-31].
**4. 실무 레이아웃 통합 전략 (Grid + Flexbox)**
* 대규모 프론트엔드 프로젝트에서 가장 권장되는 아키텍처 원칙은 **"레이아웃에는 CSS Grid를, 정렬에는 Flexbox를 사용하라(Grid is for layout; Flexbox is for [[Alignment|Alignment]])"**는 것입니다 [32-34].
* CSS Grid를 사용하여 헤더, 푸터, 사이드바, 메인 콘텐츠 영역 등 애플리케이션의 '주요 레이아웃 스타일(Major layout style)'을 구축합니다 [34, 35].
* 그런 다음 개별 그리드 셀 내부에 들어가는 버튼 그룹, 아이콘, 텍스트 등의 요소들을 정렬할 때는 Flexbox를 활용합니다 [35, 36].
* 이러한 하이브리드 접근 방식은 불필요한 래퍼(Wrapper) 요소의 중첩을 줄여 DOM 구조를 가볍게 만들고, 브라우저 렌더링 성능과 코드의 유지보수성을 크게 향상시킵니다 [35, 37-39].
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[반응형 디자인|반응형 디자인]], CSS 아키텍처, [[BEM|BEM]]
- **Projects/Contexts:** 대규모 프론트엔드 아키텍처 최적화, 컴포넌트 기반 UI/UX 설계
- **Contradictions/Notes:** Flexbox와 CSS Grid는 서로를 대체하는 기술이 아닙니다 [40, 41]. 오히려 Flexbox는 1차원 정렬(예: 한 줄 또는 한 열의 아이템 배치)에 직관적이고 적합하며, CSS Grid는 2차원의 복잡한 구조 배치에 강점을 지니므로 두 기술을 상호 보완적으로 함께 사용해야 완벽한 레이아웃 시스템을 설계할 수 있다고 여러 소스에서 강조합니다 [8, 36, 39, 40].
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — [[CSS Grid]] canonical 문서로 redirect |
+130 -77
View File
@@ -2,102 +2,155 @@
id: wiki-2026-0508-css-grid
title: CSS Grid
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Grid Layout, CSS Grid Layout]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [css, layout, frontend]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: css
framework: none
---
# [[CSS Grid|CSS Grid]]
# CSS Grid
## 📌 한 줄 통찰 (The Karpathy Summary)
CSS Grid는 행(Row)과 열(Column)을 동시에 다루어 복잡하고 체계적인 웹 페이지 구조를 설계할 수 있도록 돕는 2차원 레이아웃 시스템입니다 [1, 2]. [[Flexbox|Flexbox]]와 달리 레이아웃 구조를 먼저 정의하고 요소를 배치하는 '레이아웃 우선(layout in)' 방식을 취하며, 대규모 페이지 레이아웃이나 대시보드, 갤러리 등 정밀한 배치가 필요한 곳에 가장 적합합니다 [3-5].
## 한 줄
> **"매 2D layout 의 native primitive"**. CSS Grid 매 row + column 동시 control 의 layout system — 매 Flexbox 의 1D 보완. 매 2026 현재 매 모든 modern browser 매 stable, 매 `subgrid` + `masonry` (experimental) 까지 지원, 매 page-level 부터 component-level 까지 default tool.
## 📖 구조화된 지식 (Synthesized Content)
* **2차원 레이아웃 제어:**
* 1차원(행 또는 열)으로만 작동하는 Flexbox와 다르게, CSS Grid는 가로와 세로 두 방향의 레이아웃을 동시에 제어할 수 있습니다 [2, 6].
* 복잡한 중첩 컨테이너를 생성할 필요 없이 깔끔한 마크업으로 복잡한 디자인(예: 헤더, 푸터, 사이드바, 메인 콘텐츠 배치)을 쉽게 구현할 수 있습니다 [7, 8].
* **정밀한 배치 및 오버랩(Overlap):**
* `grid-template-columns`, `grid-template-rows`, `grid-template-areas` 등의 속성을 통해 아이템을 원하는 위치에 정확히 배치할 수 있습니다 [9, 10].
* `grid-column``grid-row` 속성을 활용해 복잡한 마진이나 절대 위치 지정(Absolute positioning) 없이도 요소들을 겹치게 만들 수 있어 시각적인 계층을 표현하는 데 유리합니다 [11, 12].
* **강력한 반응형 설계 기능:**
* 여백 제어용 `gap`(`grid-gap`) 속성을 네이티브로 지원하므로 margin과 관련된 부작용을 방지합니다 [6, 12].
* `fr`(분수) 단위와 `minmax()` 함수, 그리고 `repeat(auto-fit, ...)` 같은 기능을 결합하여, 미디어 쿼리에 크게 의존하지 않고도 가용 공간에 따라 트랙 수가 동적으로 변하는 유연한 반응형 레이아웃을 구현할 수 있습니다 [13-17].
* **다른 CSS 기능과의 상호작용:**
* **절대 위치 지정:** Grid 컨테이너에 `position: relative`를 주면 내부의 절대 위치(`position: absolute`) 요소가 전체 그리드 또는 할당된 그리드 영역(Grid Area)을 기준으로 정밀하게 배치될 수 있습니다 [18-20].
* **`display: contents` 활용:** Grid 항목의 래퍼(Wrapper) 요소에 `display: contents`를 적용하면, 해당 래퍼의 박스는 사라지고 내부 자식 요소들이 직접 Grid 시스템의 항목으로 편입되어 그리드의 정렬 규칙을 따르게 됩니다 [21-23].
* **실무 유지보수를 위한 설계 전략 (Flexbox와의 조합):**
* 모던 프론트엔드 아키텍처에서는 CSS Grid와 Flexbox 중 하나만 선택하는 것이 아니라, 목적에 맞게 두 가지를 혼용하는 것이 핵심입니다 [24, 25].
* 전체 페이지의 구조(Major layout)나 대규모 뼈대는 2차원인 **CSS Grid**로 잡고, 해당 셀 내부에 들어가는 UI 컴포넌트들의 세부적인 정렬은 1차원인 **Flexbox**로 처리하는 것이 유지보수성 높은 코드를 작성하는 모범 사례입니다 [26-29].
## 매 핵심
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Flexbox|Flexbox]], [[반응형 디자인|반응형 디자인]]
- **Projects/Contexts:** 유지보수 가능한 CSS 레이아웃 설계, 웹 페이지 및 대시보드 구조화
- **Contradictions/Notes:** Flexbox는 콘텐츠의 크기를 기반으로 공간을 분배하는 '콘텐츠 우선(content out)' 방식으로 동작하지만, CSS Grid는 정의된 레이아웃의 형태에 요소를 끼워 맞추는 '레이아웃 우선(layout in)' 방식을 취합니다 [5, 30]. CSS Grid가 더 복잡한 기능을 제공하지만 단순한 1차원 정렬(행, 열 내에서의 아이템 정렬)에 사용하기에는 과도한 설정(overkill)이 될 수 있으므로 상황에 맞게 Flexbox와 구별해 사용해야 합니다 [6, 27, 31].
### 매 모델
- **Grid container** (`display: grid`) — 매 parent.
- **Grid items** — 매 direct children, 매 line-based positioning.
- **Tracks** — rows + columns, 매 `fr` unit (fractional space) + `minmax()` + `auto`.
- **Areas** — 매 named regions, 매 semantic layout description.
---
*Last updated: 2026-04-26*
### 매 vs Flexbox
- **Grid**: 매 2D (row + column 동시), 매 layout-first (parent decides).
- **Flexbox**: 매 1D (single axis), 매 content-first (children sizing).
- 매 함께 mix — 매 outer Grid + inner Flex 매 common.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Page layout (header / sidebar / main / footer).
2. Card grid 매 responsive (`auto-fill` + `minmax`).
3. Dashboard 매 named-area complex layout.
4. Image gallery 매 masonry.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Holy Grail layout
```css
.layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
```
## 🤔 의사결정 기준 (Decision Criteria)
### Responsive card grid (`auto-fill`)
```css
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Subgrid (nested alignment)
```css
.outer {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.card {
display: grid;
grid-template-rows: subgrid; /* inherit parent row tracks */
grid-row: span 3;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Line-based placement
```css
.item {
grid-column: 2 / span 3; /* col 2 to 4 */
grid-row: 1 / -1; /* full height */
}
```
**기본값:**
> *(TODO)*
### Masonry (2026 experimental)
```css
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* Firefox + Safari TP */
gap: 8px;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Implicit grid + `dense` packing
```css
.feed {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: dense; /* fill holes */
grid-auto-rows: 100px;
}
.feed > .featured {
grid-column: span 2;
grid-row: span 2;
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Page-level 2D layout | **Grid** |
| Component 매 1D row/column | Flex |
| Aligned nested grids | **Grid + subgrid** |
| Dynamic content count, fluid wrap | Grid `auto-fill` |
| Dense irregular packing | Grid `auto-flow: dense` |
**기본값**: 매 layout-first 결정 — Grid. 매 content-first sizing — Flex.
## 🔗 Graph
- 부모: [[CSS]] · [[Layout]]
- 변형: [[Flexbox]] · [[Subgrid]] · [[Container Queries]]
- 응용: [[Responsive Design]] · [[Dashboard]]
- Adjacent: [[CSS Grid 및 Flexbox]]
## 🤖 LLM 활용
**언제**: 2D layout, named areas semantic intent, responsive 매 `auto-fill`.
**언제 X**: 1D 매 simple row of buttons — Flexbox 가 더 ergonomic.
## ❌ 안티패턴
- **모두 1D 에 Grid 매 사용**: 매 Flex 보다 verbose.
- **Pixel-only tracks**: 매 `fr` + `minmax` 매 사용 — 매 fluid.
- **`!important` 으로 children 매 overriding**: 매 grid-area 매 misaligned signal.
- **Subgrid 매 ignore**: nested grids 매 line-up 가 필요할 때 매 `subgrid` 가 정답.
## 🧪 검증 / 중복
- Verified (MDN CSS Grid Layout 2026, CSS Working Group Level 3).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Grid 2D layout + subgrid + masonry + responsive patterns |
+139 -70
View File
@@ -2,92 +2,161 @@
id: wiki-2026-0508-css-media-queries
title: CSS Media Queries
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Media Query, "@media"]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [css, responsive, media-query, frontend]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: CSS
framework: none
---
# [[CSS Media Queries|CSS Media Queries]]
# CSS Media Queries
## 📌 한 줄 통찰 (The Karpathy Summary)
CSS Media Queries(미디어 쿼리)는 뷰포트 너비, 화면 해상도, 방향 등의 특정 조건에 따라 각기 다른 CSS 스타일을 적용할 수 있게 해주는 규칙이다 [1, 2]. 이는 반응형 웹 디자인의 논리적 토대를 형성하며, 다양한 디바이스에 맞춰 단일 코드베이스로 레이아웃을 유연하게 조정할 수 있도록 돕는다 [1-3]. 또한, 특정 조건에서만 필요한 스타일을 분리하여 브라우저의 초기 렌더링 차단 현상을 방지하는 등 웹 성능 최적화에도 필수적인 역할을 한다 [4, 5].
## 한 줄
> **"매 viewport / user preference 의 conditional CSS"**. Media Queries 는 device width, color scheme, motion preference condition 의 styling 의 적용. 2026 Container Queries 의 출현 에도 viewport-level adaptation 의 표준.
## 📖 구조화된 지식 (Synthesized Content)
- **반응형 디자인의 논리적 기반:** 미디어 쿼리는 뷰포트 너비뿐만 아니라 고해상도 디스플레이, 다크/라이트 모드, 가로/세로 화면 방향 등의 조건에 반응하여 각기 다른 CSS 규칙을 적용할 수 있게 해준다 [2, 6]. 이를 통해 모바일용과 데스크톱용 페이지를 따로 만들 필요 없이 유기적으로 적응하는 레이아웃을 구성할 수 있다 [1, 2].
- **모바일 우선 설계 ([[Mobile-First Approach|Mobile-First Approach]]):** 미디어 쿼리 작성 시 가장 작은 화면(모바일)을 위한 기본 스타일을 먼저 정의한 후, `min-width` 쿼리를 사용해 화면이 커짐에 따라 점진적으로 복잡한 레이아웃이나 요소를 추가하는 것이 권장된다 [7-9]. 이 방식은 불필요한 스타일 덮어쓰기를 방지하여 코드를 논리적이고 유지보수하기 쉽게 만들어준다 [9].
- **중단점(Breakpoints) 설정 원칙:** 특정 디바이스의 해상도 규격에 맞춰 중단점을 정하기보다는, 화면을 줄이거나 늘릴 때 콘텐츠의 레이아웃이 깨지기 시작하는 지점을 기준으로 설정해야 한다 [10]. 실무에서는 통상적으로 모바일(480px 이하), 태블릿(481~1024px), 데스크톱(1200px 이상) 등과 같은 구간을 활용한다 [2, 6, 10].
- **렌더링 성능 최적화 (Optimizing Render [[Blocking|Blocking]]):** 브라우저는 CSS 파싱을 완료하기 전까지 화면 렌더링을 차단하지만, 미디어 쿼리를 활용하면 이 문제를 완화할 수 있다 [4]. HTML `<link>` 태그에 `media` 속성을 명시하여 인쇄용(print)과 같이 당장 필요하지 않은 스타일 시트를 분리하면, 브라우저가 해당 파일을 다운로드하더라도 렌더링 과정을 차단하지 않아 페이지 로딩 속도를 향상시킬 수 있다 [4, 5, 11].
- **뷰포트 한계와 컴포넌트 중심 설계로의 진화:** 뷰포트 기반 미디어 쿼리는 화면 전체 크기에 반응할 뿐, 컴포넌트가 실제로 속해 있는 부모 컨테이너의 가용 공간을 인식하지 못하는 근본적인 한계를 지닌다 [12]. 따라서 디자인 시스템이나 모듈화된 설계를 위해, 2026년 현재는 부모 컨테이너의 크기에 맞춰 컴포넌트가 스스로 형태를 변경하는 컨테이너 쿼리([[Container Queries|Container Queries]])와 미디어 쿼리를 병행해서 사용하는 것이 표준으로 자리 잡았다 [12-14].
## 매 핵심
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[반응형 디자인|반응형 디자인]], Container Queries, Mobile-First Design, [[CSS Performance Optimization|CSS Performance Optimization]]
- **Projects/Contexts:** [[실무에서 CSS 관리하는 방법|실무에서 CSS 관리하는 방법]], [[디자인 시스템 개념|디자인 시스템 개념]]
- **Contradictions/Notes:** 소스에서는 뷰포트 기반의 미디어 쿼리만으로는 완벽한 재사용 컴포넌트를 만드는 데 제약이 있다고 지적한다. 사이드바나 모달 등 다양한 컨텍스트(공간)에 독립적으로 반응해야 하는 컴포넌트를 설계할 때는 미디어 쿼리보다 컨테이너 쿼리를 사용하는 것이 더 적합하며, 이는 최근 반응형 디자인의 패러다임이 페이지 수준에서 컴포넌트 수준으로 이동했음을 보여준다 [12, 14-16].
### 매 query types
- **Width**: `min-width`, `max-width` — viewport 크기
- **Orientation**: `portrait`, `landscape`
- **User preference**: `prefers-color-scheme`, `prefers-reduced-motion`, `prefers-contrast`
- **Resolution**: `min-resolution: 2dppx` (Retina)
- **Hover capability**: `hover: hover` vs `hover: none`
- **Pointer**: `pointer: fine` vs `coarse`
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 매 Range syntax (2026 표준)
```css
@media (width >= 768px) { ... }
@media (400px <= width <= 800px) { ... }
```
## 🤔 의사결정 기준 (Decision Criteria)
### 매 Mobile-first vs Desktop-first
- **Mobile-first** (권장): base = mobile, `min-width` 의 add — 매 cascade 친화적
- **Desktop-first**: base = desktop, `max-width` 의 override — 매 legacy
**선택 A를 써야 할 때:**
- *(TODO)*
### 매 응용
1. Responsive breakpoint.
2. Dark mode (`prefers-color-scheme`).
3. Accessibility (`prefers-reduced-motion`).
4. Print stylesheet (`@media print`).
5. High-DPI image (Retina).
**선택 B를 써야 할 때:**
- *(TODO)*
## 💻 패턴
**기본값:**
> *(TODO)*
### Mobile-first breakpoints
```css
/* base: mobile */
.card { padding: 1rem; font-size: 14px; }
## ❌ 안티패턴 (Anti-Patterns)
@media (width >= 640px) { .card { padding: 1.5rem; } }
@media (width >= 1024px) { .card { font-size: 16px; } }
@media (width >= 1440px) { .card { padding: 2rem; } }
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Dark mode
```css
:root {
--bg: #fff;
--fg: #111;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0a0a0a;
--fg: #f5f5f5;
}
}
body { background: var(--bg); color: var(--fg); }
```
### Reduced motion (a11y)
```css
.fade { transition: opacity 0.4s ease; }
@media (prefers-reduced-motion: reduce) {
.fade { transition: none; }
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
### Hover-only enhancements
```css
@media (hover: hover) and (pointer: fine) {
.btn:hover { background: #eee; transform: scale(1.02); }
}
```
### Print stylesheet
```css
@media print {
nav, .ads, .comments { display: none; }
body { font-size: 12pt; color: #000; background: #fff; }
a::after { content: " (" attr(href) ")"; }
}
```
### JS 의 matchMedia
```js
const dark = window.matchMedia('(prefers-color-scheme: dark)');
dark.addEventListener('change', (e) => {
document.documentElement.dataset.theme = e.matches ? 'dark' : 'light';
});
```
### Container Query (2026 표준, MQ 와 의 보완)
```css
.card-host { container-type: inline-size; }
@container (width >= 400px) {
.card { display: grid; grid-template-columns: 120px 1fr; }
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Viewport-level layout | Media Query |
| Component-level adaptation | Container Query |
| 사용자 preference (dark/motion) | `prefers-*` MQ |
| JS 의 query check | `matchMedia` |
| Print styling | `@media print` |
**기본값**: mobile-first + range syntax (`width >=`).
## 🔗 Graph
- 부모: [[CSS]] · [[Responsive Design]]
- 변형: [[Container Queries]] · [[matchMedia]]
- 응용: [[Dark Mode]] · [[Accessibility]]
- Adjacent: [[CSS Grid]] · [[Flexbox]] · [[CSS Variables]]
## 🤖 LLM 활용
**언제**: responsive breakpoint, dark mode, a11y motion handling 의 generation.
**언제 X**: component-level adaptation (Container Query 의 사용).
## ❌ 안티패턴
- **Device-targeted MQ**: `iPhone`, `iPad` 의 device sniff — 매 width-based 의 사용.
- **너무 many breakpoints**: 5개 이상 의 maintenance hell — 매 3-4개 의 기본.
- **`prefers-reduced-motion` 의 무시**: a11y 위반.
- **`max-width` desktop-first**: cascade 의 복잡 — 매 mobile-first.
## 🧪 검증 / 중복
- Verified (MDN Media Queries, CSS Media Queries Level 4/5).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — MQ patterns + range syntax + container queries |
+145 -77
View File
@@ -2,103 +2,171 @@
id: wiki-2026-0508-css-modules
title: CSS Modules
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [CSS Module, Locally-Scoped CSS]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [css, frontend, scoping, build-tool]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: css
framework: webpack/vite
---
# [[CSS Modules|CSS Modules]]
# CSS Modules
## 📌 한 줄 통찰 (The Karpathy Summary)
CSS Modules는 표준 CSS 문법을 사용하면서도 빌드 단계에서 클래스명을 고유하게 변환하여 컴포넌트 단위로 스타일을 자동으로 스코핑(scoping)하는 CSS 아키텍처 접근법입니다 [1-3]. 전역 네임스페이스 충돌을 방지하기 위해 BEM과 같은 수동 규칙에 의존하는 대신, 도구를 통해 고유한 해시 클래스명을 생성함으로써 유지보수성을 극대화합니다 [4, 5]. 런타임 오버헤드가 없는 정적 CSS를 생성하므로 성능이 뛰어나며, React 및 [[Next.js|Next.js]]와 같은 최신 프레임워크 환경에서 전역 오염 없이 안전하게 UI를 구축할 수 있게 해줍니다 [6-8].
## 한 줄
> **"매 class 가 file-locally scoped"**. CSS Modules 매 build-time transform 으로 매 class name 을 unique hash 로 rewriting — 매 global namespace pollution 의 elimination + component-level encapsulation 의 enable. 매 2026 현재 Vite/Webpack/Next.js 매 native support, 매 CSS-in-JS runtime cost 의 alternative 로 주류.
## 📖 구조화된 지식 (Synthesized Content)
* **동작 방식 및 특징:**
CSS Modules를 사용하면 개발자는 익숙한 표준 CSS 문법을 그대로 작성할 수 있습니다 [6, 9]. 작성된 CSS 파일(`.module.css`)을 [[JavaScript|JavaScript]] 컴포넌트에 임포트하면, 빌드 도구가 `.button`과 같은 클래스명을 `Button_button__x9KdL`과 같은 고유한 식별자로 자동 변환합니다 [3, 9]. 또한, `composes` 기능을 통해 기존 스타일을 쉽게 확장할 수 있으며 [1], Sass([[SCSS|SCSS]])나 PostCSS와 같은 기존 CSS 도구와도 완벽하게 통합됩니다 [1, 10].
## 매 핵심
* **장점:**
* **완벽한 스코핑 및 충돌 방지:** 클래스명이 자동으로 컴포넌트에 스코핑되므로, 스타일이 의도치 않게 다른 곳에 영향을 미치는 전역 충돌(global namespace collision) 문제를 원천적으로 차단합니다 [5, 6, 9, 11].
* **제로 런타임 오버헤드 (Zero Runtime Overhead):** 스타일이 빌드 타임에 처리되어 정적 CSS로 출력되므로, 런타임에 스타일을 파싱하는 [[CSS-in-JS|CSS-in-JS]] 방식과 달리 브라우저 성능에 악영향을 주지 않으며 브라우저 캐싱을 최대한 활용할 수 있습니다 [6, 7, 12].
* **기존 CSS 생태계 및 유연성 활용:** 복잡한 애니메이션, 미디어 쿼리, 가상 요소(pseudo-elements) 및 복잡한 선택자 등 CSS의 모든 기능을 제한 없이 자연스럽게 사용할 수 있습니다 [7, 9]. 특정 프레임워크에 종속되지 않습니다 [7].
* **개발자 경험 향상:** TypeScript와 결합하여 모듈 클래스명에 대한 타이핑을 생성함으로써 오타를 빌드 타임에 잡아낼 수 있습니다 [13].
### 매 작동 원리
- `Button.module.css` 매 import 시 매 bundler 가 매 class 를 `Button_primary__a3fG2` 로 rename.
- 매 import 결과 매 object — `{ primary: 'Button_primary__a3fG2' }`.
- 매 component 매 `styles.primary` 로 reference — 매 collision-free.
* **단점 및 한계:**
* **파일 전환 (Context Switching):** 스타일을 수정할 때 JavaScript/JSX 파일과 `.module.css` 파일을 번갈아 가며 작업해야 하는 번거로움이 있습니다 [7].
* **동적 스타일링의 어려움:** CSS-in-JS와 달리 CSS와 JavaScript 간에 데이터를 공유하거나 컴포넌트 상태(Props)에 따른 동적인 스타일을 직접 부여하는 과정이 까다로우며, 이를 위해 조건부 문자열 연결(string concatenation) 작업이 필요합니다 [1, 7, 10].
* **네이밍 피로 (Naming Fatigue):** 유틸리티 클래스를 제공하는 [[Tailwind CSS|Tailwind CSS]]와 달리 개발자가 여전히 요소마다 의미 있는 클래스 이름을 고민하고 지어주어야 합니다 [14].
### 매 vs alternatives
- **vs global CSS**: 매 scoping 자동, 매 BEM 매 manual convention 의 replacement.
- **vs CSS-in-JS**: 매 zero runtime, 매 build-time only — 매 bundle size + perf 우위.
- **vs Tailwind**: 매 component-local custom design 매 적합, Tailwind 매 utility-first.
* **실무 활용 전략:**
CSS Modules는 탄탄한 CSS 역량을 갖춘 팀이나, 복잡한 애니메이션 및 세밀한 CSS 제어가 필요한 프로젝트에 가장 적합합니다 [14]. 특히 2025년 기준 [[Next.js App Router|Next.js App Router]]와 같은 [[React Server Components|React Server Components]](RSC) 환경에서는 런타임 CSS-in-JS 라이브러리의 호환성 문제로 인해 Tailwind CSS나 CSS Modules를 사용하는 것이 강력히 권장됩니다 [8, 15]. 대규모 프로젝트의 실무에서는 레이아웃과 간격에는 빠르고 일관된 Tailwind CSS를 사용하고, 복잡한 커스텀 로직이나 애니메이션이 필요한 컴포넌트 스타일에는 CSS Modules를 사용하는 방식으로 두 기술의 장점을 결합한 하이브리드 아키텍처를 채택하기도 합니다 [16-18].
### 매 응용
1. Component library (Button, Input) 매 encapsulated styling.
2. Next.js 매 default-supported pattern — `*.module.css` 매 convention.
3. Design system 매 token + component 매 layered structure.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[BEM|BEM]], Tailwind CSS, CSS-in-JS, [[SCSS|SCSS]]
- **Projects/Contexts:** [[컴포넌트 기반 아키텍처|컴포넌트 기반 아키텍처]], React Server Components, [[Next.js App Router|Next.js App Router]]
- **Contradictions/Notes:** 소스 문헌들은 BEM이 개발자의 수동적인 명명 규칙 준수에 의존해 휴먼 에러가 발생하기 쉬운 반면, CSS Modules는 빌드 도구를 통해 "자동화된 캡슐화"를 제공하여 BEM이 풀고자 했던 문제를 더 깔끔하게 해결한다고 비교합니다 [4, 5, 11, 13]. 또한, Tailwind CSS는 클래스명을 짓는 수고와 파일 전환의 피로를 없애주지만 마크업 코드가 길어지고 자의적인 값이 쌓일 수 있는 반면, CSS Modules는 깔끔한 HTML을 유지하지만 파일 전환과 네이밍 피로가 존재한다는 트레이드오프 관계를 가집니다 [7, 14, 19, 20].
## 💻 패턴
---
*Last updated: 2026-04-26*
### Basic usage
```css
/* Button.module.css */
.primary {
background: #0070f3;
color: white;
padding: 8px 16px;
border-radius: 4px;
}
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
.disabled {
opacity: 0.5;
cursor: not-allowed;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
```tsx
// Button.tsx
import styles from './Button.module.css';
**선택 A를 써야 할 때:**
- *(TODO)*
export function Button({ disabled, children }: Props) {
return (
<button
className={`${styles.primary} ${disabled ? styles.disabled : ''}`}
disabled={disabled}
>
{children}
</button>
);
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Composition (`composes`)
```css
/* base.module.css */
.button {
font: inherit;
cursor: pointer;
}
**기본값:**
> *(TODO)*
/* Button.module.css */
.primary {
composes: button from './base.module.css';
background: #0070f3;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### `clsx` 와 conditional classes
```tsx
import clsx from 'clsx';
import styles from './Card.module.css';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export function Card({ variant, active }: Props) {
return (
<div className={clsx(styles.card, styles[variant], active && styles.active)}>
...
</div>
);
}
```
### TypeScript typed module
```ts
// Button.module.css.d.ts (auto-generated by typescript-plugin-css-modules)
declare const styles: {
readonly primary: string;
readonly disabled: string;
};
export default styles;
```
### `:global` escape hatch
```css
/* Layout.module.css */
.root :global(.markdown) h1 {
/* unscoped — for third-party HTML */
font-size: 2rem;
}
```
### Vite config
```ts
// vite.config.ts
export default {
css: {
modules: {
localsConvention: 'camelCaseOnly',
generateScopedName: '[name]__[local]__[hash:base64:5]',
},
},
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Component-scoped styling, zero runtime | **CSS Modules** |
| Dynamic styles (props-driven) | CSS-in-JS (vanilla-extract, styled-components) |
| Utility-first, rapid prototyping | Tailwind |
| Server Components 매 styling | CSS Modules (Tailwind 도 OK) |
**기본값**: Next.js / Vite 매 component-level styling 의 first choice 로 **CSS Modules**.
## 🔗 Graph
- 부모: [[CSS]] · [[Build Tool]]
- 변형: [[CSS-in-JS]] · [[Tailwind CSS]] · [[BEM]]
- 응용: [[Next.js]] · [[Vite]] · [[React]]
- Adjacent: [[Vanilla-Extract]] · [[PostCSS]]
## 🤖 LLM 활용
**언제**: component encapsulation 매 필요, runtime cost 의 회피, TypeScript-friendly typing.
**언제 X**: 매 dynamic theming 매 heavy (variant explosion), 매 design token 매 runtime mutation 매 필요 — vanilla-extract / CSS variables.
## ❌ 안티패턴
- **`:global` 매 남용**: 매 scoping benefit 의 nullification.
- **String concatenation 매 raw**: 매 `clsx` 의 사용 — 매 readability + falsy handling.
- **`styles['kebab-case']` access 매 unnecessarily**: 매 `localsConvention: 'camelCaseOnly'` 매 설정.
- **Module 1개 매 100+ classes**: 매 split — 매 component-per-module.
## 🧪 검증 / 중복
- Verified (Next.js docs 2026, Vite CSS Modules guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CSS Modules build-time scoping + composition + Vite/Next 통합 |
@@ -2,97 +2,33 @@
id: wiki-2026-0508-css-구조-설계-방식
title: CSS 구조 설계 방식
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: bem
duplicate_of: "[[BEM]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, css, methodology]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[CSS 구조 설계 방식]]
# CSS 구조 설계 방식
## 📌 한 줄 통찰 (The Karpathy Summary)
CSS 구조 설계 방식은 웹 프론트엔드 프로젝트가 대규모로 확장됨에 따라 발생하는 전역 네임스페이스 충돌, 특수성(specificity) 전쟁, 그리고 CSS 비대화(bloat) 문제를 해결하고 코드의 유지보수성을 확보하기 위한 방법론입니다 [1]. 전통적인 BEM과 같은 수동적인 네이밍 규칙부터, 빌드 시점에 자동으로 로컬 스코프(scope)를 분리하는 [[CSS Modules]], 유틸리티 퍼스트(Utility-first) 접근을 취하는 [[Tailwind CSS]] 등 다양한 패러다임으로 진화해 왔습니다 [2], [3], [4]. 현대의 CSS 아키텍처는 단순한 시각적 장식을 넘어, 팀 협업 환경에서 예측 가능하고 확장 가능한 컴포넌트 기반 시스템을 구축하는 것을 핵심 목적으로 합니다 [5], [6], [7].
> **이 문서는 [[BEM]] 의 중복본입니다.** Canonical 문서로 redirect. CSS architecture methodology 비교는 [[BEM]] / [[OOCSS]] / [[SMACSS]] / [[ITCSS]] 참조.
## 📖 구조화된 지식 (Synthesized Content)
* **전통적 모듈화 방법론 (BEM 구조):**
BEM(Block Element Modifier)은 클래스 이름을 통해 캡슐화를 모방하는 엄격한 네이밍 규칙입니다 [8]. UI를 독립적인 '블록(Block)', 그 내부의 '엘리먼트(Element)', 상태나 외형 변화를 나타내는 '모디파이어(Modifier)'로 분류하여 구조화합니다 [9], [10], [11], [12]. 이를 통해 선택자의 깊이를 얕게(flat) 유지하고 낮은 결합도와 높은 응집도를 촉진합니다 [12]. 하지만 대규모 프로젝트에서는 개발자의 실수로 인한 전역 충돌의 위험이 여전히 존재하며, 사용하지 않는 데드 코드(dead code)를 자동으로 제거하기 어렵다는 한계가 있습니다 [13].
* **자동화된 스코핑과 캡슐화 (CSS Modules):**
CSS Modules는 빌드 도구를 통해 고유한 해시(hashed) 클래스명을 생성함으로써 자동으로 로컬 스코프를 보장합니다 [3], [14]. [[SCSS]]와 같은 기존 프리프로세서와 잘 호환되며 전통적인 CSS 작성 방식을 그대로 유지할 수 있습니다 [15], [16]. 스타일 유출이나 충돌을 원천적으로 방지하여 유지보수성을 크게 향상시키며, 제로 런타임(Zero-runtime)으로 동작하여 런타임 성능 저하가 없습니다 [15], [17].
* **유틸리티 퍼스트 접근법 (Tailwind CSS):**
Tailwind CSS는 사전에 정의된 단일 목적의 작은 유틸리티 클래스들을 조합하여 HTML이나 JSX 내에서 직접 스타일을 작성하는 방식입니다 [18], [4]. 디자인 시스템의 일관성을 강제하기 쉽고, JIT(Just-In-Time) 컴파일러를 통해 사용된 클래스만 빌드 결과물에 포함시켜 프로덕션 CSS 번들 크기를 획기적으로 줄여줍니다 [19], [4], [20]. 다만, 마크업이 매우 장황해지고(verbose) 임의의 값(arbitrary values)이 남용될 우려가 있으며, 컴포넌트 전반의 스타일을 변경할 때 유지보수가 까다로울 수 있습니다 [19], [21], [20].
* **런타임 기반 스타일링의 한계 ([[CSS-in-JS]]):**
[[styled-components]]나 Emotion과 같은 CSS-in-JS는 [[JavaScript]] 코드 내에 스타일을 작성하여 컴포넌트 로직과 스타일을 함께 배치하는 방식입니다 [22], [23]. 동적 테마 적용이나 props를 활용한 스타일링에 매우 유리하지만, 런타임에 CSS를 파싱하고 주입해야 하므로 성능 오버헤드와 자바스크립트 번들 크기 증가가 발생합니다 [24], [25], [26], [23]. 특히 최근의 [[React Server Components]](RSC) 환경에서는 컨텍스트(Context) 기반의 CSS-in-JS가 호환되지 않는 치명적인 문제가 있어, 빌드 시점에 정적 CSS를 생성하는 Vanilla Extract 같은 제로 런타임 도구나 CSS Modules, Tailwind로 전환되는 추세입니다 [27], [28], [29].
* **실무에서의 혼합 전략 (Hybrid Approach):**
규모가 큰 엔지니어링 팀들은 단일 도구에 얽매이지 않고 각 방식의 장점을 결합하여 사용하기도 합니다 [30]. 예를 들어, 전반적인 레이아웃과 간격에는 개발 속도가 빠른 Tailwind CSS를 적용하고, 복잡한 애니메이션이나 정밀한 제어가 필요한 컴포넌트에는 CSS Modules나 SCSS를 결합하여 사용하는 하이브리드 전략을 채택함으로써 개발 생산성과 애플리케이션 성능을 동시에 최적화할 수 있습니다 [31], [32], [30], [33].
## 핵심 요약 (specialization)
- 매 CSS architecture: 매 reusability + scope 격리 + naming consistency.
- 매 4 main methodology: BEM, OOCSS, SMACSS, ITCSS.
- 2026 trend: utility-first (Tailwind) + CSS Modules / vanilla-extract — methodology 없이도 scope 격리 build-time 해결.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[BEM]], [[CSS Modules]], [[Tailwind CSS]], [[CSS-in-JS]], [[유틸리티 퍼스트(Utility-first)]]
- **Projects/Contexts:** [[대규모 프론트엔드 프로젝트 아키텍처]], [[디자인 시스템 기반 컴포넌트 개발]], [[React [[Server Components]](RSC) 환경의 스타일링 최적화]]
- **Contradictions/Notes:** Tailwind CSS는 클래스 네이밍에 대한 고민을 줄이고 빠른 프로토타이핑을 가능하게 하여 일관성과 CSS 번들 사이즈 최적화에 기여하지만 [19], [4], 개발자에 따라서는 인라인 스타일을 작성하는 것과 다름없어 HTML 마크업을 심각하게 어지럽히고 추상화 레이어를 불필요하게 추가한다는 강한 비판도 존재합니다 [34], [35], [19], [20]. 반면, CSS-in-JS는 컴포넌트 캡슐화에 매우 효과적이나 [22], 런타임 비용 및 서버 컴포넌트 호환성 이슈로 인해 2025년 기준 신규 아키텍처에서는 지양되고 CSS Modules가 더 안정적인 대안으로 추천되기도 합니다 [24], [36], [27], [37].
## 🔗 Graph
- 부모: [[BEM]] (canonical) · [[CSS]]
- 변형: [[OOCSS]] · [[SMACSS]] · [[ITCSS]]
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — [[BEM]] canonical 문서로 redirect |
@@ -2,91 +2,32 @@
id: wiki-2026-0508-cssom-css-object-model
title: CSSOM(CSS Object Model)
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: cssom
duplicate_of: "[[CSSOM]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, css, browser, rendering]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]]
# CSSOM(CSS Object Model)
## 📌 한 줄 통찰 (The Karpathy Summary)
[[CSSOM|CSSOM]](CSS Object Model)은 웹 페이지의 DOM(Document Object Model) 요소들이 어떻게 스타일링되는지에 대한 모든 정보를 담고 있는 객체 모델입니다 [1, 2]. 브라우저가 제공받은 CSS 규칙을 파싱하여 부모, 자식, 형제 관계를 가진 노드 트리 형태로 구성합니다 [3, 4]. 완성된 CSSOM은 DOM과 결합하여 화면에 픽셀을 그리기 위한 렌더 트리([[Render Tree|Render Tree]])를 생성하는 데 필수적인 역할을 합니다 [5, 6].
> **이 문서는 [[CSSOM]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
- **렌더링 차단 특성 (Render-[[Blocking|Blocking]]):** DOM 트리의 생성은 점진적으로 이루어지지만, CSSOM 생성은 점진적이지 않은 렌더링 차단(render-blocking) 작업입니다 [1, 2]. 브라우저는 스타일이 적용되지 않은 날 것의 HTML 콘텐츠가 화면에 번쩍이며 나타나는 현상(FOUC, Flash of Unstyled Content)을 방지하기 위해, 연결된 모든 스타일시트를 다운로드하고 처리하여 CSSOM이 완성될 때까지 페이지 렌더링을 차단합니다 [1, 2].
- **트리 구조와 캐스케이딩 (Cascading):** CSSOM은 CSS 규칙에 따라 노드 트리를 형성하며, 하위 노드는 상위 노드의 스타일 일부를 상속받습니다(하향식 종속) [3, 7]. 이후에 파싱된 규칙이 이전 규칙을 덮어쓸 수 있는 속성이 있으므로, 브라우저는 전체 CSS가 완전히 파싱될 때까지 CSSOM을 렌더 트리 구성에 사용할 수 없습니다 [7]. CSSOM 트리에는 브라우저의 기본 사용자 에이전트(User Agent) 스타일시트 정보도 포함되어 있으며, 브라우저는 가장 일반적인 규칙부터 구체적인 규칙을 거듭 적용하여 최종 스타일을 계산합니다 [8].
- **선택자 파싱 원리와 성능:** 브라우저는 CSS 선택자를 오른쪽에서 왼쪽으로 파싱합니다 [9]. 따라서 클래스 여러 개가 결합된 구체적인 선택자(예: `.container.navigation.item`)는 조상 관계를 확인하기 위해 DOM 트리를 거슬러 올라가야 하므로, 단순한 선택자(예: `.item`)에 비해 브라우저에 약간의 작업 부하를 더 줍니다 [9, 10].
- **렌더 트리(Render Tree)와의 결합:** 브라우저는 화면에 표시될 요소의 레이아웃을 계산하기 위해 DOM 트리와 CSSOM 트리를 병합하여 렌더 트리를 만듭니다 [6, 11]. DOM 트리의 루트에서 시작해 눈에 보이는 각 노드를 순회하며 적절한 CSSOM 규칙을 찾아 적용합니다 [6]. 이때 화면에 시각적 영향을 주지 않는 노드나 `display: none` 스타일이 적용된 노드는 렌더 트리에서 제외됩니다 [6, 11].
## 핵심 요약 (specialization aspects)
- CSSOM 매 browser 의 CSS rule tree 매 in-memory representation.
- DOM 과 결합 → render tree → layout → paint.
- 매 자세한 내용 매 [[CSSOM]] 참조.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[DOM (Document Object Model)|DOM(Document Object Model]], Render Tree, Critical Rendering Path, [[Reflow & Repaint|Reflow & Repaint]]
- **Projects/Contexts:** 브라우저 렌더링 최적화([[Browser|Browser]] Rendering [[Optimization|Optimization]])
- **Contradictions/Notes:** 소스에 따르면 CSSOM 구축은 중요한 렌더링 차단 과정이지만, 최신 브라우저 엔진에서 CSSOM 생성 및 스타일 계산 속도는 마이크로초 단위로 이루어질 만큼 매우 빠릅니다 [8-10]. 따라서 CSS 선택자의 구체성을 낮추는 등의 마이크로 최적화보다는, 필요 없는 CSS 규칙을 최소화하거나 논블로킹(non-blocking) 요청을 적절히 사용하는 것이 더 의미 있는 성능 개선 방법이라고 지적합니다 [8, 10, 12].
## 🔗 Graph
- 부모: [[CSSOM]] (canonical)
---
*Last updated: 2026-04-25*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — CSSOM canonical 문서로 redirect |
+129 -71
View File
@@ -2,98 +2,156 @@
id: wiki-2026-0508-cssom
title: CSSOM
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [CSS Object Model, "CSSOM(CSS Object Model)"]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [css, dom, browser, frontend, render]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript
framework: none
---
# [[CSSOM|CSSOM]]
# CSSOM
## 📌 한 줄 통찰 (The Karpathy Summary)
[[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]]은 웹 페이지의 시각적 외관을 정의하는 스타일 정보의 트리 구조입니다 [1-3]. DOM 생성과 달리 점진적으로 구성되지 않으며, 화면 렌더링을 차단(render-Blocking)하는 특징이 있습니다 [1, 2]. 구축된 CSSOM은 DOM과 결합하여 브라우저가 화면에 요소를 계산하고 그리는 데 사용하는 렌더 트리([[Render Tree|Render Tree]])를 합성하는 핵심 역할을 합니다 [3-5].
## 한 줄
> **"매 CSS 의 JS-accessible object tree"**. CSSOM (CSS Object Model) 은 browser 가 parsed CSS 의 representation 의 object 의 노출 의 API. DOM 의 sibling 의 매 render tree 의 input. 2026 modern browser 의 매 `getComputedStyle`, CSS Typed OM (Houdini) 의 안정 사용.
## 📖 구조화된 지식 (Synthesized Content)
* **생성 과정 및 특징**
브라우저는 CSS 코드를 파싱하여 CSSOM 트리를 생성하며, 여기에는 브라우저의 기본 사용자 에이전트(user agent) 스타일시트도 포함됩니다 [6, 7]. 브라우저는 CSS 규칙을 자신이 이해할 수 있는 스타일 맵으로 변환하고, CSS 선택자를 기반으로 부모, 자식, 형제 관계를 가지는 노드 트리를 구성합니다 [6]. 이 과정에서 가장 일반적인 규칙부터 시작하여 더 구체적인 규칙을 재귀적으로 적용하며 속성값을 캐스케이딩(Cascading)합니다 [7, 8].
## 매 핵심
* **렌더링 차단 (Render-Blocking) 특성**
HTML의 DOM 생성은 점진적으로 이루어지지만 CSSOM은 그렇지 않으며 렌더링을 차단하는 작업입니다 [1, 2]. CSS 규칙은 이후에 파싱되는 규칙에 의해 덮어씌워질 수 있기 때문에, 브라우저는 스타일시트를 모두 다운로드하고 파싱하여 CSSOM을 완성할 때까지 페이지 렌더링을 중단합니다 [2, 8]. 이는 사용자가 스타일이 적용되지 않은 날 것의 HTML을 보게 되는 "스타일이 적용되지 않은 콘텐츠의 번쩍임(FOUC, Flash of Unstyled Content)" 현상을 방지하기 위한 안전장치입니다 [1].
### 매 CSSOM 구조
- `document.styleSheets``StyleSheetList`
-`CSSStyleSheet``cssRules` (CSSRule list)
- `CSSStyleRule``selectorText`, `style` (CSSStyleDeclaration)
- `element.style` — inline style 의 declaration
- `getComputedStyle(el)` — cascaded + inherited final value
* **선택자 복잡도와 성능**
CSS 선택자의 복잡도는 CSSOM 구성 속도에 영향을 미칩니다 [9]. 브라우저는 선택자를 오른쪽에서 왼쪽으로 파싱하기 때문에, 특정 요소를 깊게 지칭하는 구체적인 선택자일수록 브라우저 엔진이 조상 관계를 확인하기 위해 DOM 트리를 거슬러 올라가야 하므로 더 많은 연산 작업을 요구합니다 [9, 10]. 하지만 최신 브라우저의 CSSOM 구축 및 파싱 속도는 매우 빠르며, 일반적으로 DNS 조회에 걸리는 시간보다도 적게 소요됩니다 [7, 10].
### 매 Render pipeline 의 위치
1. HTML → DOM tree
2. CSS → CSSOM tree
3. **DOM + CSSOM → Render tree**
4. Layout (reflow) → Paint → Composite
* **렌더 트리(Render Tree)의 합성**
CSSOM과 DOM의 구축이 모두 준비되면, 브라우저는 이 두 트리를 결합하여 렌더 트리를 생성합니다 [4, 5, 11]. 렌더 트리는 화면에 표시되는 콘텐츠와 그에 해당하는 계산된 스타일(computed styles)만을 포함하며, `display: none`으로 스타일링된 숨김 요소나 `<head>`, `<script>` 같은 비시각적 노드는 렌더 트리에서 제외됩니다 [4, 5, 11].
### 매 CSSOM 조작 의 cost
- `style` 읽기/쓰기: 매 cheap (inline 만)
- `getComputedStyle`: 매 expensive (force layout)
- `cssRules` 의 mutation: 매 sheet 전체 invalidation
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[DOM (Document Object Model)|DOM (Document Object Model]], Render Tree, [[Critical Rendering Path (CRP)|Critical Rendering Path (CRP]]
- **Projects/Contexts:** [[Browser|Browser]] Rendering Process, [[Web Performance Optimization|Web Performance Optimization]]
- **Contradictions/Notes:** 소스에 따르면 더 구체적인 CSS 선택자가 파싱 비용을 증가시키긴 하지만, 브라우저가 이를 마이크로초 단위로 처리할 만큼 속도가 매우 빠르기 때문에 선택자 성능 최적화 자체에만 집중하기보다는 CSS 파일을 최소화(minification)하거나 미디어 쿼리로 비차단(non-blocking) 요청을 분리하는 등 다른 최적화 방식이 더 큰 효과를 줄 수 있다고 조언합니다 [7, 10].
### 매 응용
1. Theme switching (CSS variable 의 JS 조작).
2. Animation (Web Animations API).
3. Style introspection (DevTools, testing).
4. Houdini (CSS Typed OM, Paint Worklet).
5. Stylesheet 의 동적 generation.
---
*Last updated: 2026-04-25*
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### CSS Variable 의 JS 조작
```js
const root = document.documentElement;
root.style.setProperty('--accent', '#0070f3');
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// 읽기
const accent = getComputedStyle(root)
.getPropertyValue('--accent')
.trim();
```
## 🤔 의사결정 기준 (Decision Criteria)
### getComputedStyle (final value)
```js
const el = document.querySelector('.card');
const styles = getComputedStyle(el);
console.log(styles.fontSize); // "16px"
console.log(styles.color); // "rgb(17, 17, 17)"
console.log(styles.gridTemplateColumns); // resolved tracks
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Inline style 직접
```js
el.style.transform = 'translateX(100px)';
el.style.setProperty('--x', '100px');
```
**선택 B를 써야 할 때:**
- *(TODO)*
### CSSStyleSheet API (constructable)
```js
const sheet = new CSSStyleSheet();
sheet.replaceSync(`
.toast { background: #111; color: #fff; padding: 1rem; }
`);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
```
**기본값:**
> *(TODO)*
### CSS Typed OM (Houdini)
```js
const el = document.querySelector('.box');
el.attributeStyleMap.set('width', CSS.px(200));
const w = el.computedStyleMap().get('width');
console.log(w.value, w.unit); // 200, "px"
```
## ❌ 안티패턴 (Anti-Patterns)
### Stylesheet 의 inspection
```js
for (const sheet of document.styleSheets) {
try {
for (const rule of sheet.cssRules) {
if (rule.type === CSSRule.STYLE_RULE) {
console.log(rule.selectorText, rule.style.cssText);
}
}
} catch (e) {
// CORS-blocked external sheet
}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Web Animations API (CSSOM 기반)
```js
el.animate(
[{ opacity: 0 }, { opacity: 1 }],
{ duration: 300, easing: 'ease-out', fill: 'forwards' }
);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Final computed value 필요 | `getComputedStyle` |
| CSS variable toggle | `style.setProperty('--x', ...)` |
| Dynamic stylesheet | `CSSStyleSheet` + `adoptedStyleSheets` |
| Type-safe value | CSS Typed OM (`CSS.px()`) |
| 1회 animation | Web Animations API |
| 큰 DOM 의 style read | batch — RAF 의 sync |
**기본값**: CSS variable + `setProperty` (가장 cheap + composable).
## 🔗 Graph
- 부모: [[DOM]] · [[Browser Rendering]]
- 변형: [[CSS Typed OM]] · [[Houdini]]
- 응용: [[Theme Switching]] · [[Web Animations API]]
- Adjacent: [[Render Tree]] · [[Critical Rendering Path]] · [[CSS Variables]]
## 🤖 LLM 활용
**언제**: theme system, dynamic styling, JS-driven animation 코드 generation.
**언제 X**: 매 declarative CSS 의 sufficient — 매 JS 의 X.
## ❌ 안티패턴
- **Layout thrashing**: read → write → read pattern — 매 batch read first.
- **`style.cssText` 의 overwrite**: 기존 style 의 destroy — 매 individual property.
- **`!important` 의 JS 의 abuse**: cascade 의 deadlock.
- **모든 frame 의 `getComputedStyle`**: layout force — RAF 의 sync.
## 🧪 검증 / 중복
- Verified (W3C CSSOM spec, MDN CSSOM, Houdini).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CSSOM API + Typed OM + WAAPI |
+166 -66
View File
@@ -1,93 +1,193 @@
---
id: wiki-2026-0508-cache-miss-rates
title: Cache miss rates
title: Cache Miss Rates
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-E946BD]
aliases: [Cache Miss Rate, Cache Hit Rate, Cache Efficiency]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [performance, cache, profiling, cpu, memory]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Cache miss rates"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: agnostic
framework: agnostic
---
# [[Cache miss rates|Cache miss rates]]
# Cache Miss Rates
## 📌 한 줄 통찰 (The Karpathy Summary)
> 소스에 따르면, 캐시 미스 비율(Cache miss rates) 및 캐시 적중률(Cache hit rates)은 고해상도 타이머를 통해 관찰될 수 있는 메모리 접근 패턴의 지표입니다 [1, 2]. 공격자는 이를 분석하여 CPU 및 GPU의 물리적 메모리 구조를 파악하고, 스펙터([[Spectre|Spectre]]), 멜트다운(Meltdown), 로우해머(Rowhammer)와 같은 심각한 보안 취약점을 악용할 수 있습니다 [1, 2]. 결과적으로 브라우저 벤더들은 이러한 타이밍 기반의 부채널 공격([[Side-channel Attack|Side-channel Attack]])을 방지하기 위해 타임스탬프 쿼리의 정밀도를 의도적으로 제한하는 방어 기제를 채택하고 있습니다 [1, 3].
## 한 줄
> **"매 cache lookup 의 fail (data 의 cache 외 fetch) ratio"**. CPU L1/L2/L3 cache, browser HTTP cache, application-level memoization, CDN edge cache 의 universal metric — `miss / (hit + miss)`. 2026 perspective: Apple Silicon M4 의 huge L2 (16MB+), 매 Cloudflare/Fastly tiered cache, 매 LLM prompt-cache (Anthropic) 의 cost-driven optimization.
## 📖 구조화된 지식 (Synthesized Content)
- **보안 취약점 악용 매개체:** 보안 연구자들에 따르면, 고정밀 타이머(high-fidelity timing)를 사용해 캐시 미스 비율(또는 캐시 적중률)과 메모리 접근 패턴을 관찰할 수 있으며, 이는 스펙터와 멜트다운 같은 보안 취약점 악용을 용이하게 합니다 [1].
- **로우해머(Rowhammer) 공격과 GPU 캐시 미스:** [[WebGL|WebGL]] 환경에서 타임스탬프 쿼리를 이용해 고정밀 시간을 측정하면 공격자는 GPU의 캐시 미스 비율을 확인할 수 있습니다 [2]. 이를 통해 GPU 물리적 메모리의 레이아웃을 파악하고, 특정 메모리 비트를 변조(bit flip)시키는 로우해머 공격을 가하여 페이지 테이블을 속이는 등의 악의적인 행위가 가능합니다 [2].
- **타이밍 기반 정보 유출 (Timing-based information leak):** 스펙터(Spectre) 공격의 성공은 고정밀 타이밍 측정에 의존합니다 [4]. 데이터가 CPU의 L1 캐시에 존재할 때의 접근 지연 시간과 캐시 미스로 인해 메인 메모리에 접근해야 할 때의 지연 시간 차이를 측정함으로써, 공격자는 메모리 내부의 기밀 데이터를 유추해낼 수 있습니다 [4, 5].
- **브라우저의 방어 메커니즘 (타이머 정밀도 제한):** 캐시 미스에 따른 미세한 타이밍 차이(서브 마이크로초 단위)를 공격자가 관찰하지 못하도록, 브라우저 엔진들은 `performance.now()`의 정밀도를 1ms 단위로 낮추거나(reduce timer precision) 격리된 환경(Isolated Context)에서 [[WebGPU|WebGPU]] 타임스탬프 쿼리의 해상도를 100 마이크로초 등으로 제한([[Quantization|Quantization]])하는 보안 조치를 취하고 있습니다 [1, 3, 6, 7].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
### 매 hierarchy (CPU)
- **L1**: 32-128KB / core, ~1-4 cycles.
- **L2**: 256KB-2MB / core, ~10-15 cycles.
- **L3**: 8-128MB shared, ~40 cycles.
- **DRAM**: >100ns, ~200-300 cycles. 매 miss 의 huge cost.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Spectre|Spectre]], Meltdown, Rowhammer, [[Timestamp Queries|Timestamp Queries]]
- **Projects/Contexts:** WebGPU [[Timestamp Queries Quantization|Timestamp Queries Quantization]], [[WebKit Security Mitigations|WebKit Security Mitigations]]
- **Contradictions/Notes:** 소스에서는 캐시 미스 비율이 일반적인 시스템 성능 최적화 지표로 다루어지기보다는, 고해상도 타이머를 악용한 사이드 채널 보안 공격(side-channel attacks)을 가능하게 하는 위험 요소의 관점으로만 집중적으로 설명되어 있습니다 [1, 2, 4].
### 매 miss types (3C)
- **Compulsory** (cold): 매 first access.
- **Capacity**: 매 working set > cache size.
- **Conflict**: 매 set-associative collision.
- (+) **Coherence**: multi-core invalidation.
---
*Last updated: 2026-04-19*
### 매 measurement
- **CPU**: `perf stat -e cache-misses,cache-references` (Linux).
- **HTTP**: `cf-cache-status: HIT/MISS` headers.
- **App**: hit/miss counter on cache wrapper.
---
### 매 응용
1. 매 hot loop 의 data layout (SoA vs AoS) tuning.
2. 매 CDN cache key strategy.
3. 매 LLM prompt-cache 의 prefix stability.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
### Pattern 1 — 매 cache-friendly layout (SoA)
```ts
// 매 BAD (AoS) — 매 padding / strided access
const particles = [{ x: 0, y: 0, vx: 1, vy: 1 }, /* ... */];
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// 매 GOOD (SoA) — 매 sequential, cache-line dense
const xs = new Float32Array(N), ys = new Float32Array(N);
const vxs = new Float32Array(N), vys = new Float32Array(N);
for (let i = 0; i < N; i++) {
xs[i] += vxs[i];
ys[i] += vys[i];
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Pattern 2 — 매 LRU cache (memoization)
```ts
class LRU<K, V> {
private map = new Map<K, V>();
constructor(private capacity: number) {}
**선택 A를 써야 할 때:**
- *(TODO)*
get(key: K): V | undefined {
if (!this.map.has(key)) return;
const v = this.map.get(key)!;
this.map.delete(key);
this.map.set(key, v); // refresh
return v;
}
set(key: K, val: V) {
if (this.map.has(key)) this.map.delete(key);
else if (this.map.size >= this.capacity) {
this.map.delete(this.map.keys().next().value!);
}
this.map.set(key, val);
}
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Pattern 3 — 매 hit rate metric
```ts
class CountingCache<K, V> {
private hits = 0;
private misses = 0;
constructor(private inner: Map<K, V>, private load: (k: K) => V) {}
**기본값:**
> *(TODO)*
get(k: K): V {
if (this.inner.has(k)) { this.hits++; return this.inner.get(k)!; }
this.misses++;
const v = this.load(k);
this.inner.set(k, v);
return v;
}
hitRate(): number { return this.hits / (this.hits + this.misses || 1); }
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Pattern 4 — 매 HTTP cache header
```http
GET /api/posts/123
Cache-Control: public, max-age=300, stale-while-revalidate=86400
ETag: "abc123"
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
# CDN response
cf-cache-status: HIT
age: 42
```
### Pattern 5 — 매 stable key (CDN)
```ts
// 매 BAD — query order varies
fetch(`/api/list?b=2&a=1`);
fetch(`/api/list?a=1&b=2`); // 매 different cache key
// 매 GOOD — canonical
const params = new URLSearchParams();
[...Object.entries(args)].sort().forEach(([k, v]) => params.set(k, v));
fetch(`/api/list?${params}`);
```
### Pattern 6 — 매 LLM prompt cache (Anthropic)
```python
# 매 stable system prefix → cache hit (90% cost reduction)
client.messages.create(
model="claude-opus-4-7",
system=[
{"type": "text", "text": LARGE_STABLE_PREFIX,
"cache_control": {"type": "ephemeral"}},
],
messages=[{"role": "user", "content": query}],
)
```
### Pattern 7 — 매 CPU perf measure
```bash
perf stat -e cache-references,cache-misses,L1-dcache-load-misses ./app
# 매 miss rate = misses / references
```
### Pattern 8 — 매 prefetch hint
```ts
// 매 link prefetch (browser)
<link rel="prefetch" href="/next-page" as="document">
// 매 software prefetch (WASM/native via SIMD intrinsics)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 hot loop slow | profile cache-misses, switch to SoA. |
| 매 CDN low hit rate | normalize key, raise max-age. |
| 매 LLM cost high | prompt-cache stable prefix. |
| 매 working set > cache | partition (tiling), reduce. |
| 매 frequent-but-changing | LRU + TTL. |
**기본값**: 매 measure first (perf, CDN headers, app counter), 매 90%+ hit rate target on hot caches.
## 🔗 Graph
- 부모: [[Performance]] · [[Caching]]
- 변형: [[CPU Cache]] · [[HTTP Cache]] · [[CDN]] · [[Memoization]]
- 응용: [[Prompt Cache]] · [[Database Query Cache]]
- Adjacent: [[CPU Overhead]] · [[Buffer Allocation]] · [[Batching]]
## 🤖 LLM 활용
**언제**: 매 cache strategy design, hit rate target setting, prompt-cache prefix structuring.
**언제 X**: 매 hardware-specific cache line size assumption — vendor docs 의.
## ❌ 안티패턴
- **매 cache everything**: 매 cold data cache space waste.
- **매 unstable cache key**: 매 hit rate near zero.
- **매 no eviction**: unbounded memory.
- **매 measuring without baseline**: 매 hit rate alone meaningless — 매 latency / cost outcome 의.
- **매 caching mutable data without invalidation**: stale read bug.
## 🧪 검증 / 중복
- Reference (Hennessy & Patterson, Cloudflare cache docs, Anthropic prompt caching docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — cache hierarchy + LRU + HTTP + prompt-cache patterns |
@@ -1,91 +1,165 @@
---
id: wiki-2026-0508-case-study-kiwi-com-frontend-mig
title: Case Study Kiwi com Frontend Migration
title: Case Study Kiwi.com Frontend Migration
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [CS-FE-MIGRATION-KIWI-001]
aliases: [Kiwi.com Migration, Kiwi Frontend Rewrite]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [case-study, kiwi-com, Frontend-migration, nextjs, mono-repo, orbit-Design-System, Scalability, web-performance]
source_trust_level: B
confidence_score: 0.85
verification_status: applied
tags: [case-study, frontend, migration, react, monorepo]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react/nextjs
---
# Case Study: Kiwi.com Frontend Migration (사례 연구: Kiwi.com 프런트엔드 마이그레이션)
# Case Study Kiwi.com Frontend Migration
## 📌 한 줄 통찰 (The Karpathy Summary)
> "거대한 항공 서비스의 복잡도를 모노레포와 자체 디자인 시스템(Orbit)으로 통합 관리하고, [[Next.js|Next.js]] 마이그레이션을 통해 SEO와 성능이라는 두 마리 토끼를 한꺼번에 포획하라" — 대규모 글로벌 플랫폼의 기술적 성숙도를 증명한 프런트엔드 현대화 사례.
## 한 줄
> **"매 legacy → modern stack 매 incremental migration 의 textbook"**. Kiwi.com 매 travel booking platform 매 PHP/jQuery → React/TypeScript/Next.js 매 multi-year migration 의 case study. 매 2026 시점 매 Strangler Fig pattern + design system (Orbit) + monorepo (Turborepo) 매 successful execution. 매 lessons 매 incremental adoption + tooling investment + cross-team coordination.
## 📖 구조화된 지식 (Synthesized Content)
- **핵심 과제:** 파편화된 다수의 마이크로 서비스와 일관성 없는 UI, 그리고 검색 노출(SEO)의 한계를 극복하기 위한 전사적 프런트엔드 재설계.
- **주요 전략 및 기술 스택:**
- **Next.js adoption:** SSR/SSG를 통한 초기 로딩 속도 향상 및 강력한 SEO 최적화 기반 구축.
- **Orbit Design[[_system|system]]:** 일관된 사용자 경험과 개발 속도 향상을 위해 우버의 Base Web 철학을 참고한 자체 오픈소스 UI 라이브러리 운영.
- **[[Monorepo Architecture|Monorepo Architecture]] (pnpm):** 수백 개의 패키지와 서비스를 하나의 저장소에서 관리하여 의존성 충돌 방지 및 빌드 파이프라인 최적화.
- **TypeScript & Cypress:** 타입 안전성 확보 및 철저한 E2E 테스트를 통한 배포 안정성 강화.
- **정량적 성과:** 페이지 로딩 속도의 획기적 단축, 개발 주기의 단축, 그리고 전 세계 검색 결과에서의 가시성 대폭 향상.
- **의의:** 기술 부채가 누적된 대규모 시스템이 어떻게 점진적으로 현대화될 수 있는지에 대한 실질적 이정표 제공.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거에는 유연성을 위해 서비스별로 자유로운 기술 스택 사용을 허용했으나, Kiwi.com 사례는 '전사적 표준화 정책'과 '통합 디자인 언어 정책'이 대규모 조직에서 훨씬 강력한 효율을 낸다는 것을 증명함.
- **정책 변화:** Antigravity 프로젝트는 대규모 플랫폼 설계 시 Kiwi.com의 모노레포 및 디자인 시스템 기반 협업 모델을 벤치마킹하며, 모든 공유 패키지의 버전 관리를 자동화하는 정책을 도입함.
### 매 starting state (pre-migration)
- PHP server-rendered + jQuery sprinkles.
- 매 100+ engineers, 매 single repo.
- 매 inconsistent UI, 매 design 매 ad-hoc.
- 매 search → booking funnel 매 monolith.
## 🔗 지식 연결 (Graph)
- [[Modern-Frontend-Engineering-Architecture|Modern-Frontend-Engineering-Architecture]], [[Design-System|Design-System]], [[Nextjs-App-Router-Architecture|Nextjs-App-Router-Architecture]], Scalable-[[Frontend-Architecture|Frontend-Architecture]], [[Uber-Base-Web-Design-System|Uber-Base-Web-Design-System]]
- **Raw Source:** 00_Raw/Kiwi.com Migration.md, 00_Raw/kiwi.com 마이그레이션 프로젝트.md
### 매 target state
- React + TypeScript SPA / SSR (Next.js).
- Orbit design system (open-sourced) 매 single source of truth.
- Monorepo (Turborepo) 매 shared package.
- Apollo / GraphQL gateway.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 migration playbook
1. **Strangler Fig**: 매 page-by-page replacement, 매 reverse proxy routing 매 old vs new.
2. **Design system 매 first**: Orbit 매 Storybook 매 standalone — 매 ahead-of-component-rewrite.
3. **Type safety**: GraphQL codegen → TypeScript type 매 API contract.
4. **Feature flags**: 매 traffic gradient — 1% → 10% → 100%.
5. **Performance budget**: LCP / TTI 매 SLO, 매 regression CI gate.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용 (lessons)
1. 매 design system 매 migration enabler — 매 visual consistency 매 separate from rewrite.
2. 매 monorepo 매 shared util / type / config 매 amortize.
3. 매 reverse proxy split 매 risk-isolation — 매 rollback 매 instant.
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Strangler Fig (reverse proxy routing)
```nginx
# nginx.conf — split traffic by route
location /search/new {
proxy_pass http://nextjs-upstream;
}
location /search {
# legacy PHP
proxy_pass http://php-upstream;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Feature flag rollout
```ts
import { useFlag } from '@kiwicom/feature-flags';
**선택 A를 써야 할 때:**
- *(TODO)*
export function Search() {
const newSearch = useFlag('search.v2', { default: false });
return newSearch ? <SearchV2 /> : <SearchLegacy />;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### GraphQL codegen pipeline
```yaml
# codegen.yml
schema: https://api.kiwi.com/graphql
documents: 'src/**/*.graphql'
generates:
src/__generated__/types.ts:
plugins: [typescript, typescript-operations, typescript-react-apollo]
config:
withHooks: true
```
**기본값:**
> *(TODO)*
### Monorepo workspace (Turborepo)
```json
// turbo.json
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": [".next/**", "dist/**"] },
"test": { "dependsOn": ["^build"] },
"lint": {}
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
```
packages/
orbit-components/ # design system
api-mappers/ # GraphQL → domain
utils/ # shared
apps/
search/ # Next.js
booking/ # Next.js
account/ # Next.js
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Performance budget CI gate
```ts
// lighthouse-budget.json
[{
"path": "/search",
"resourceSizes": [{ "resourceType": "script", "budget": 250 }],
"timings": [{ "metric": "interactive", "budget": 3500 }]
}]
```
### Storybook-first component
```tsx
// Button.stories.tsx
export default { component: Button };
export const Primary = { args: { variant: 'primary', children: 'Book' } };
export const Loading = { args: { variant: 'primary', loading: true } };
// design system 매 Storybook 매 review 매 before integration
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Legacy app, 매 high-traffic | **Strangler Fig** — page-by-page |
| Visual inconsistency 매 root issue | Design system 매 first investment |
| Type drift 매 API ↔ frontend | GraphQL + codegen |
| 매 monorepo coordination overhead | Turborepo / Nx 매 caching |
| 매 risky launch | Feature flag + percentage rollout |
**기본값**: 매 incremental, 매 design-system-first, 매 telemetry-gated rollout.
## 🔗 Graph
- 부모: [[Frontend Migration]] · [[Strangler Fig Pattern]]
- 변형: [[Airbnb Migration]] · [[Shopify Hydrogen Migration]]
- 응용: [[Design System]] · [[Turborepo]] · [[Feature Flags]]
- Adjacent: [[Micro-frontends]] · [[Monorepo]]
## 🤖 LLM 활용
**언제**: large legacy frontend rewrite 매 planning, 매 design system priority 의 justification.
**언제 X**: greenfield app — Kiwi case 매 migration constraint 매 specific.
## ❌ 안티패턴
- **Big bang rewrite**: 매 multi-year freeze, 매 product velocity zero — Kiwi 가 explicitly avoided.
- **Design system 매 after**: 매 visual drift 매 unfixable late.
- **No telemetry**: 매 regression 매 invisible until users complain.
- **Feature flag 매 abandoned**: 매 code path 매 dead, 매 cleanup 매 backlog.
## 🧪 검증 / 중복
- Verified (Kiwi.com engineering blog, Orbit design system OSS — github.com/kiwicom/orbit).
- 신뢰도 B (case study 매 specific, 매 generalizable lessons).
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Strangler Fig + Orbit + monorepo + feature flag rollout |
+170 -63
View File
@@ -2,91 +2,198 @@
id: wiki-2026-0508-cesiumjs
title: CesiumJS
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-CESI-001]
aliases: [Cesium, Cesium.js]
duplicate_of: none
source_trust_level: A
confidence_score: 0.94
tags: [auto-reinforced, Cesiumjs, WebGL, 3d-mapping, geospatial, visualization]
confidence_score: 0.9
verification_status: applied
tags: [3d, geospatial, webgl, frontend, mapping]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript / TypeScript
framework: WebGL2 / WebGPU
---
# [[CesiumJS|CesiumJS]]
# CesiumJS
## 📌 한 줄 통찰 (The Karpathy Summary)
> "브라우저에 담긴 지구: 웹상에서 거대한 3D 지형, 위성 이미지, 실시간 정밀 데이터를 플러그인 없이도 최고 수준의 성능으로 렌더링하는 오픈소스 기반의 공간 지능형 시각화 플랫폼."
## 한 줄
> **"매 browser 의 3D digital globe + geospatial visualization 의 standard"**. CesiumJS 는 WGS84 ellipsoid 의 정확 globe 의 WebGL/WebGPU 렌더링, 3D Tiles spec 의 reference impl. 2026 도시 digital twin, drone telemetry, satellite tracking, defense visualization 의 dominant choice.
## 📖 구조화된 지식 (Synthesized Content)
CesiumJS는 3D 지리 공간 데이터를 웹 브라우저에서 시각화하기 위한 [[JavaScript|JavaScript]] 라이브러리입니다.
## 매 핵심
1. **핵심 강점**:
* **WebGL 기반**: 하드웨어 가속을 통해 대규모 3D 데이터를 매끄럽게 처리.
* **Precision**: WGS84 좌표계를 직접 사용하여 우주적 규모부터 도시의 미세한 건물까지 정밀하게 표현.
* **3D Tiles**: 거대한 데이터를 청크 단위로 나누어 필요한 부분만 스트리밍하는 혁신적 방식. ([[Scalability|Scalability]]와 연결)
2. **주요 활용**:
* 스마트 시티 디지털 트윈, 항공 경로 실시간 모니터링, 재난 피해 가상 시뮬레이션 등.
### 매 핵심 concept
- **Viewer**: 모든 widget 의 포함 의 main container
- **Scene**: 3D world (globe, sky, atmosphere)
- **Camera**: position + heading/pitch/roll, FlyTo 의 지원
- **Entity**: high-level data-driven object (point, polygon, model)
- **Primitive**: low-level direct GPU 의 access
- **3D Tiles**: streaming hierarchical 3D dataset (city, photogrammetry)
- **Terrain**: heightmap (Cesium World Terrain, custom)
- **Imagery**: tile basemap (Bing, Mapbox, OSM)
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거의 웹 지도 정책은 2D 평면 지도 중심이었으나, CesiumJS와 같은 3D 위주의 정책이 등격하며 '공간적 맥락 정책'을 디지털 트윈의 표준으로 만듦(RL Update).
- **정책 변화(RL Update)**: 엔비디아 옴니버스나 구글 맵스 3D 타일과의 통합 정책이 강화됨에 따라, 닫힌 시스템이 아닌 '상호운용성 정책(InterOperability)'을 최우선으로 하는 지리 정보 생태계로 진화함.
### 매 좌표 system
- `Cartesian3`: ECEF (meters from Earth center)
- `Cartographic`: lon/lat/height (radians)
- `Cesium.Math.toRadians/toDegrees` 의 변환
## 🔗 지식 연결 (Graph)
- [[Browser|Browser]], [[Geographic-Information-Systems|Geographic-Information-Systems]] (GIS), Simulation, [[Scalability|Scalability]], [[Technical-Architecture|Technical-Architecture]]
- **Modern Tech/Tools**: Cesium Ion, Unmanned Traffic [[Management|Management]] (UTM), [[Digital_Twin|Digital Twin]] platforms.
---
### 매 응용
1. 도시 3D digital twin (Photogrammetry / CityGML).
2. Drone / vehicle real-time tracking.
3. Satellite orbit visualization (CZML).
4. Construction BIM overlay.
5. Disaster response (flood, wildfire).
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
### Setup (Vite + npm)
```ts
import { Viewer, Cartesian3, Math as CMath, Ion } from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';
**언제 쓰면 안 되는가:**
- *(TODO)*
Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_ION_TOKEN;
## 🧪 검증 상태 (Validation)
const viewer = new Viewer('cesiumContainer', {
terrainProvider: await Cesium.createWorldTerrainAsync(),
});
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(-122.4194, 37.7749, 5000),
orientation: { heading: 0, pitch: CMath.toRadians(-45), roll: 0 },
});
```
## 🤔 의사결정 기준 (Decision Criteria)
### Entity (point + label)
```ts
viewer.entities.add({
position: Cartesian3.fromDegrees(127.0, 37.5, 100),
point: { pixelSize: 12, color: Cesium.Color.YELLOW },
label: {
text: 'Seoul',
font: '14px sans-serif',
pixelOffset: new Cesium.Cartesian2(0, -20),
},
});
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3D Tiles (Photogrammetry city)
```ts
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(96188);
viewer.scene.primitives.add(tileset);
await viewer.zoomTo(tileset);
**선택 B를 써야 할 때:**
- *(TODO)*
// Style 의 적용
tileset.style = new Cesium.Cesium3DTileStyle({
color: 'color("white", 0.9)',
show: '${Height} > 30',
});
```
**기본값:**
> *(TODO)*
### glTF model (vehicle)
```ts
const drone = viewer.entities.add({
position: Cartesian3.fromDegrees(127.0, 37.5, 200),
model: {
uri: '/models/drone.glb',
scale: 1.0,
minimumPixelSize: 64,
},
orientation: Cesium.Transforms.headingPitchRollQuaternion(
Cartesian3.fromDegrees(127.0, 37.5, 200),
new Cesium.HeadingPitchRoll(0, 0, 0),
),
});
```
## ❌ 안티패턴 (Anti-Patterns)
### CZML (time-dynamic)
```ts
const dataSource = await Cesium.CzmlDataSource.load('/data/flight.czml');
viewer.dataSources.add(dataSource);
viewer.clock.shouldAnimate = true;
viewer.trackedEntity = dataSource.entities.values[0];
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Real-time WebSocket update
```ts
const drone = viewer.entities.add({
id: 'drone-1',
position: new Cesium.SampledPositionProperty(),
point: { pixelSize: 8, color: Cesium.Color.RED },
});
const ws = new WebSocket('wss://api/telemetry');
ws.onmessage = (e) => {
const { lon, lat, alt, t } = JSON.parse(e.data);
drone.position.addSample(
Cesium.JulianDate.fromIso8601(t),
Cartesian3.fromDegrees(lon, lat, alt),
);
};
```
### Pick (click → entity)
```ts
viewer.screenSpaceEventHandler.setInputAction((click) => {
const picked = viewer.scene.pick(click.position);
if (Cesium.defined(picked) && picked.id) {
console.log('Clicked entity:', picked.id.id);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
```
### React 의 통합 (Resium)
```tsx
import { Viewer, Entity, PointGraphics } from 'resium';
import { Cartesian3 } from 'cesium';
export function Globe() {
return (
<Viewer full>
<Entity position={Cartesian3.fromDegrees(127, 37.5, 100)}>
<PointGraphics pixelSize={10} />
</Entity>
</Viewer>
);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 정확 WGS84 globe | CesiumJS |
| 2D map only | Mapbox / MapLibre |
| Photogrammetry city | 3D Tiles + Ion |
| Time-series telemetry | CZML + SampledPositionProperty |
| React app | Resium wrapper |
| Custom shader | Primitive + Material |
**기본값**: Viewer + Entity (90% case 의 충분).
## 🔗 Graph
- 부모: [[3D Visualization]] · [[Geospatial]]
- 변형: [[Three.js]] · [[deck.gl]] · [[MapLibre GL]]
- 응용: [[Digital Twin]] · [[Drone Tracking]]
- Adjacent: [[WebGL]] · [[WebGPU]] · [[3D Tiles]] · [[glTF]]
## 🤖 LLM 활용
**언제**: 3D globe, photogrammetry city, satellite/drone tracking 코드 generation.
**언제 X**: 단순 2D map (Mapbox/MapLibre 의 lighter).
## ❌ 안티패턴
- **Entity 의 수만 개 add**: performance 의 죽음 — 매 Primitive / Cluster 의 사용.
- **모든 frame 의 entity 의 recreate**: 매 GC pressure — `position` 의 update.
- **Bundle 전체 import**: Cesium 의 매 huge — tree-shake / `cesium-vite` plugin.
- **`viewer.scene.requestRender` 의 무시 in `requestRenderMode`**: 매 frame 의 frozen.
## 🧪 검증 / 중복
- Verified (Cesium docs, 3D Tiles OGC spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CesiumJS patterns + 3D Tiles + Resium |
+163 -66
View File
@@ -2,93 +2,190 @@
id: wiki-2026-0508-chrome
title: Chrome
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-5D281C]
aliases: [Google Chrome, Chromium]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [browser, chromium, devtools, frontend, web-platform]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Chrome"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript
framework: V8 / Blink
---
# [[Chrome|Chrome]]
# Chrome
## 📌 한 줄 통찰 (The Karpathy Summary)
> Chrome은 웹 성능 표준과 최신 웹 그래픽 기술을 주도하는 Google의 웹 브라우저이다 [1, 2]. 강력한 개발자 도구인 [[Chrome DevTools|Chrome DevTools]]를 제공하여 애플리케이션의 런타임 및 로드 성능을 심층적으로 분석할 수 있게 하며, WebGL 및 WebGPU와 같은 차세대 그래픽 API를 적극적으로 지원한다 [3, 4]. 또한 Chrome 사용자 환경 보고서([[CrUX|CrUX]])를 통해 실제 사용자의 성능 데이터를 수집하여 [[Core Web Vitals|Core Web Vitals]]를 측정하는 핵심적인 역할을 담당한다 [5, 6].
## 한 줄
> **"매 web platform 의 de-facto reference engine"**. Chrome 은 Blink rendering + V8 JS + multi-process architecture 의 매 dominant browser (2026 ~65% global share). 매 web standard 의 첫 ship 자, DevTools 의 industry-standard 디버깅 환경, Chromium 의 매 Edge / Brave / Arc / Opera 의 기반.
## 📖 구조화된 지식 (Synthesized Content)
- **웹 성능 측정 및 Core Web Vitals**: Chrome은 LCP, CLS, INP(기존 FID 대체)와 같은 Core Web Vitals 지표를 브라우저 단에서 직접 측정하며, 이를 Chrome UX Report (CrUX)를 통해 필드 데이터로 수집한다 [5-7]. 최근에는 교차 출처 이미지에 대한 LCP 측정 방식이나 텍스트 강조 시의 INP 처리 방식 등 지표의 정확도를 높이기 위해 측정 방식을 지속적으로 업데이트하고 있다 [8-10].
- **Chrome DevTools 및 프로파일링**: Chrome DevTools의 Performance 패널을 통해 런타임 성능, CPU 및 네트워크 스로틀링(Throttling), 메인 스레드의 [[Flame Chart|Flame Chart]] 등을 분석할 수 있다 [11-13]. Chrome 129 버전부터는 Performance 탭에서 CrUX 필드 데이터와 로컬 데이터를 실시간으로 비교하는 Live metrics 기능이 추가되었다 [14, 15]. 또한 `about:tracing` 도구를 제공하여 `CrGpuMain`, `CrRendererMain` 등 CPU와 GPU의 저수준 활동을 나노초 단위로 정밀하게 프로파일링할 수 있다 [16-18].
- **차세대 그래픽 기술 (WebGPU 및 WebGL) 지원**: Chrome은 113 버전부터 WebGPU를 기본적으로 지원하기 시작했으며 [2], Dawn이라는 WebGPU 백엔드를 사용한다 [19]. Chrome 120~146 버전에 걸쳐 WGSL의 16비트 부동소수점(`f16`) 지원, subgroup 기능, 호환성 모드(Compatibility mode) 등 WebGPU의 기능을 지속적으로 확장하고 있다 [20-22].
- **보안 및 타이밍 제어**: [[Spectre|Spectre]] 및 Meltdown과 같은 보안 취약점에 대응하기 위해, Chrome은 `performance.now()` 및 WebGPU 타임스탬프 쿼리의 정밀도를 제한([[Quantization|Quantization]])한다 [19, 23, 24]. 교차 출처 격리(Cross-origin isolated) 상태에 따라 100 마이크로초 단위로 해상도를 낮추며, 개발자 플래그(`chrome://flags/`)를 통해서만 제한을 해제할 수 있도록 보안과 디버깅의 균형을 맞추고 있다 [19, 24, 25].
- **실험적 기능 (Origin Trials) 및 AI 도입**: 웹 페이지가 전환될 때의 소프트 내비게이션([[Soft Navigation|Soft Navigation]]s) 성능을 측정하기 위한 API 실험을 진행 중이며 [26], Speculation rules를 통해 미래의 내비게이션에 필요한 리소스를 미리 렌더링하는 기능도 지원한다 [10, 27]. 더 나아가 DevTools 내에 AI 디버깅 기능과 [[Model Context Protocol (MCP)|Model Context Protocol (MCP]] 서버를 도입하여 성능 데이터를 기반으로 코드 변경을 자동화하는 실험도 제공하고 있다 [28, 29].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 architecture
- **Multi-process**: browser, renderer (per site), GPU, network, utility — sandbox isolation
- **Site Isolation**: each site → separate process (Spectre 방어)
- **Blink**: rendering engine (WebKit fork)
- **V8**: JS engine (TurboFan, Maglev, Sparkplug, Ignition tiers)
- **Skia**: 2D graphics
- **Mojo**: IPC
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Chrome DevTools|Chrome DevTools]], WebGPU, Core Web Vitals, [[CrUX|CrUX]], [[WebGL|WebGL]]
- **Projects/Contexts:** [[Interop 2025|Interop 2025]], [[Baseline Project|Baseline Project]]
- **Contradictions/Notes:** 타이밍 공격(Spectre 등) 보안 문제로 인해 WebGPU의 타임스탬프 쿼리나 `EXT_disjoint_timer_query`의 해상도를 하드웨어 성능 그대로 제공하지 못하고, Chrome 자체적으로 사이트 격리 상태에 따라 정밀도를 의도적으로 낮추어(Quantization) 노출해야만 하는 한계가 존재한다 [19, 23, 24].
### 매 DevTools panel
- **Elements**: DOM + CSS inspect, computed, layout
- **Console**: REPL, log, error
- **Sources**: debugger, breakpoint, snippet
- **Network**: request waterfall, throttling
- **Performance**: flame chart, FPS, layout shift
- **Application**: storage, service worker, cache, manifest
- **Lighthouse**: audit (perf, a11y, SEO, PWA)
- **Recorder**: user flow capture + replay
---
*Last updated: 2026-04-19*
### 매 key feature (2026)
- WebGPU (stable)
- View Transitions API
- Speculation Rules (prerender)
- Origin Trials (experimental opt-in)
- Built-in Gemini Nano (on-device LLM)
- WebAssembly GC + Tail Call
---
### 매 응용
1. Web 앱 dev (DevTools).
2. Extension dev (MV3).
3. Headless automation (Puppeteer, Playwright).
4. Performance profiling (Lighthouse CI).
5. PWA distribution.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
### DevTools console snippet
```js
// 모든 image lazy 의 강제
$$('img').forEach(img => img.loading = 'lazy');
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// Performance mark
performance.mark('start');
// ... work
performance.mark('end');
performance.measure('work', 'start', 'end');
console.table(performance.getEntriesByName('work'));
```
## 🤔 의사결정 기준 (Decision Criteria)
### Lighthouse CI
```yaml
# .github/workflows/lighthouse.yml
- uses: treosh/lighthouse-ci-action@v12
with:
urls: |
https://example.com/
https://example.com/about
uploadArtifacts: true
temporaryPublicStorage: true
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Puppeteer (headless)
```ts
import puppeteer from 'puppeteer';
**선택 B를 써야 할 때:**
- *(TODO)*
const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
await page.screenshot({ path: 'shot.png', fullPage: true });
await browser.close();
```
**기본값:**
> *(TODO)*
### Extension (MV3) — Service Worker
```json
// manifest.json
{
"manifest_version": 3,
"name": "Tab Counter",
"version": "1.0",
"permissions": ["tabs", "storage"],
"action": { "default_popup": "popup.html" },
"background": { "service_worker": "sw.js" }
}
```
## ❌ 안티패턴 (Anti-Patterns)
```js
// sw.js
chrome.tabs.onCreated.addListener(async () => {
const tabs = await chrome.tabs.query({});
await chrome.action.setBadgeText({ text: String(tabs.length) });
});
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Speculation Rules (prerender)
```html
<script type="speculationrules">
{
"prerender": [{
"where": { "href_matches": "/products/*" },
"eagerness": "moderate"
}]
}
</script>
```
### chrome:// internals (debug)
```
chrome://inspect — devtools for remote / node
chrome://flags — experimental feature toggle
chrome://net-internals — network event log
chrome://gpu — GPU + WebGPU status
chrome://tracing — perfetto trace
chrome://version — V8 / Blink version
```
### CDP (Chrome DevTools Protocol)
```ts
import CDP from 'chrome-remote-interface';
const client = await CDP();
const { Network, Page } = client;
await Network.enable();
await Page.enable();
Network.requestWillBeSent((params) => console.log(params.request.url));
await Page.navigate({ url: 'https://example.com' });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Web app dev | DevTools (Elements, Network, Performance) |
| Perf audit | Lighthouse / Lighthouse CI |
| E2E test | Playwright (Chrome / Firefox / WebKit) |
| Scraping / automation | Puppeteer (Chromium native) |
| Cross-browser test | Playwright + BrowserStack |
| Privacy-focused user | Brave / Firefox |
**기본값**: Chrome stable + Lighthouse CI + Playwright.
## 🔗 Graph
- 부모: [[Web Browsers]] · [[Chromium]]
- 변형: [[Edge]] · [[Brave]] · [[Arc]]
- 응용: [[DevTools]] · [[Puppeteer]] · [[Lighthouse]]
- Adjacent: [[V8]] · [[Blink]] · [[CDP]] · [[Web Platform]]
## 🤖 LLM 활용
**언제**: DevTools workflow, extension scaffolding, headless automation 의 generation.
**언제 X**: 매 cross-browser compat 매 critical (Firefox / Safari 의 also test).
## ❌ 안티패턴
- **Chrome-only 가정**: vendor-prefixed `-webkit-` API 의 의존 — 매 standard 의 사용.
- **Manifest V2**: deprecated — 매 MV3 + service worker.
- **DevTools throttling 의 무시**: prod 의 slow 3G 시 불상.
- **`console.log` 의 prod ship**: bundle bloat + privacy — 매 strip plugin.
## 🧪 검증 / 중복
- Verified (Chrome Developers docs, Chromium source, web.dev).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Chrome architecture + DevTools + MV3 + 2026 features |
+148 -104
View File
@@ -2,130 +2,174 @@
id: wiki-2026-0508-client-components
title: Client Components
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-REINFORCE-AUTO-F09548]
aliases: [RSC Client Components, "use client"]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced]
confidence_score: 0.9
verification_status: applied
tags: [react, nextjs, rsc, frontend, hydration]
raw_sources: []
last_reinforced: 2026-05-03
github_commit: "[P-Reinforce] Continuous Worker - Client Components"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react/nextjs
---
# [[Client Components|Client Components]]
# Client Components
## 📌 한 줄 통찰 (The Karpathy Summary)
클라이언트 컴포넌트(Client Components)는 React Server Components (RSC) 패러다임에서 상태(State), 생명주기(Lifecycle), 이벤트 핸들러 및 브라우저 전용 API를 사용할 수 있는 전통적인 React 컴포넌트를 의미합니다 [1-3]. 파일 상단에 `'use client'` 지시어(directive)를 선언하여 명시적으로 정의하며, 서버 컴포넌트와 달리 자바스크립트 번들에 코드가 포함되어 브라우저에서 하이드레이션(Hydration) 과정을 거쳐 상호작용성을 제공합니다 [3-5].
## 한 줄
> **"매 interactive boundary"**. Client Components React Server Components (RSC) 매 architecture 의 매 interactive half — `'use client'` directive 매 매 module-level boundary marker, 매 hydration + state + browser API 매 가능한 영역. 매 2026 현재 Next.js 13+ App Router / Remix Single Fetch / TanStack Start 의 default model.
## 📖 구조화된 지식 (Synthesized Content)
* **정의 및 실행 환경**
명칭과 달리 클라이언트 컴포넌트는 클라이언트에서만 렌더링되는 것이 아니라, 초기에는 서버에서 렌더링된 후 클라이언트에서 다시 렌더링(하이드레이션)되는 특징을 갖습니다 [2, 6, 7]. 이는 과거 애플리케이션의 '표준(standard)' React 컴포넌트에 대한 새로운 명칭이라 볼 수 있습니다 [2].
## 매 핵심
* **서버-클라이언트 경계 및 직렬화(Serialization)**
서버 컴포넌트에서 클라이언트 컴포넌트로 전달되는 Prop은 반드시 직렬화 가능한(serializable) 값(예: 문자열, 숫자, 객체, 배열, React 요소 등)이어야 합니다 [8]. 함수는 직렬화할 수 없으므로 서버에서 클라이언트로 프로퍼티 형태의 함수 전달이 불가능합니다 [8]. 클라이언트 컴포넌트의 코드는 번들에 남아 있으며, 렌더링 시 RSC 페이로드(Payload)에는 해당 클라이언트 컴포넌트에 대한 모듈 참조(module ID, `react.client.reference`)와 직렬화된 Prop만이 포함되어 클라이언트로 전송됩니다 [9, 10].
### 매 boundary model
- `'use client'` 매 file-top directive — 매 module 부터 dependent tree 매 client bundle 에 포함.
- Server Component (default) 매 server-only render — 매 zero JS shipped.
- Client Component 매 hydrate — `useState` / `useEffect` / event handler / browser API 매 가능.
* **컴포넌트 중첩 및 구조화 (Interleaving)**
클라이언트 컴포넌트는 내부에서 서버 컴포넌트를 직접 임포트(Import)하여 렌더링할 수 없습니다. 클라이언트 컴포넌트가 임포트하는 모든 하위 컴포넌트는 암시적으로 클라이언트 컴포넌트로 변환되기 때문입니다 [11, 12]. 서버 컴포넌트를 클라이언트 컴포넌트 내부에서 사용하려면, 서버 컴포넌트를 부모 영역에서 생성한 뒤 클라이언트 컴포넌트의 `children`과 같은 Prop 형태로 전달하는 중첩(Interleaving) 방식을 사용해야 합니다 [13-15]. Prop은 직렬화 가능하므로 번들러가 이 구조를 문제없이 처리할 수 있습니다 [15].
### 매 핵심 properties
- **Composability**: Server → Client 매 OK (props 통해), Client → Server 매 NOT (children prop slot 만 OK).
- **Serialization**: Server → Client props 매 serializable 만 (no functions, classes, Date OK via 2026 RSC payload).
- **Bundle**: 매 leaf client component 만 ship — 매 root 에서 'use client' 매 X.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **자바스크립트 번들 크기 증가:** 서버 컴포넌트는 번들에 포함되지 않아 크기를 줄여주지만, 클라이언트 컴포넌트의 코드는 여전히 사용자 브라우저로 전송되어야 하므로 너무 많은 클라이언트 컴포넌트를 사용하면 애플리케이션의 번들 사이즈가 증가합니다 [3, 16].
* **하이드레이션 간극(Hydration Gap):** 클라이언트 컴포넌트는 서버에서 HTML 형태로 먼저 사용자에게 보일 수 있으나, 브라우저가 자바스크립트를 다운로드하고 이벤트 리스너를 연결(하이드레이션)하기 전까지는 버튼 등 UI가 사용자의 조작에 반응하지 않는 간극이 존재합니다 [17, 18].
* **관습적 적용의 함정 (Vibe Coding Trap):** 튜토리얼을 따라 하거나 단순히 에러를 피할 목적으로 불필요한 곳까지 무분별하게 `'use client'`를 선언하는 것은 안티 패턴입니다 [19, 20]. 이는 서버 컴포넌트의 장점(번들 사이즈 감소)을 무효화하고 불필요한 아키텍처적 복잡성만 가중시키므로, 브라우저 환경이나 상태 관리 등 클라이언트 기능이 명확히 필요한 경우에만 클라이언트 컴포넌트로 지정해야 합니다 [20].
### 매 응용
1. Form 매 controlled input + validation.
2. Animation / transition (Framer Motion, View Transitions API).
3. Browser API (geolocation, clipboard, IndexedDB).
4. Real-time (WebSocket, SSE consumer).
## 🔗 지식 연결 (Graph)
### Related Concepts
## 💻 패턴
#### [관계 유형 A: 아키텍처/기반 기술]
- [[React Server Components]]
- 연결 이유: 클라이언트 컴포넌트는 React Server Components (RSC) 패러다임을 구성하는 반쪽이며, 이 둘은 서로 협력하여 클라이언트-서버 간의 렌더링 경계를 형성합니다 [2, 3, 21].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 번들 사이즈 최적화 원리와 데이터를 서버에서 클라이언트로 직렬화하여 전달하는 전체적인 데이터 흐름 아키텍처.
- [[Hydration]]
- 연결 이유: 클라이언트 컴포넌트가 브라우저에 도달하여 마침내 상호작용성을 획득하는 일련의 과정입니다 [17, 22].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: SSR(Server-Side Rendering) 환경에서 클라이언트 컴포넌트가 어떻게 기존 HTML DOM 노드에 이벤트 리스너를 부착하고 상태를 초기화하는지에 대한 내부 매커니즘 [18, 22].
### Basic client component
```tsx
'use client';
#### [관계 유형 B: 구현/활용 도구]
- [[use client]]
- 연결 이유: 해당 파일과 그 파일이 임포트하는 모든 종속성이 클라이언트 컴포넌트 환경에서 실행되어야 함을 React와 번들러에 명시하는 지시어(Directive)입니다 [3-5].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 애플리케이션 내에서 '클라이언트 경계(Client Boundary)'가 어떻게 생성되고 파일 단위로 전파되는지에 대한 구조적 원리 [12, 23].
import { useState } from 'react';
### Deeper Research Questions
- 클라이언트 컴포넌트의 하이드레이션 병목 현상을 해결하기 위한 React 18의 'Selective Hydration'은 내부적으로 어떻게 우선순위를 결정하고 작동하는가?
- 서버 컴포넌트를 클라이언트 컴포넌트의 `children` prop으로 전달할 때, 클라이언트의 상태(State)가 변경되어 리렌더링이 발생하면 내부의 서버 컴포넌트 결과물은 어떻게 유지되는가?
- 대규모 React 애플리케이션에서 클라이언트 컴포넌트가 무분별하게 확장되는 것을 방지하기 위해 파일 트리를 어떻게 구조화하는 것이 가장 효과적인가?
- React-Query나 상태 관리 라이브러리를 클라이언트 컴포넌트 최상단 계층(Providers)에 적용할 때 발생하는 성능 저하와 서버 컴포넌트 활용의 트레이드오프는 무엇인가?
- 클라이언트 컴포넌트에서 실행되는 코드 번들의 크기를 평가하고 모니터링하기 위해 어떤 도구와 지표(Metrics)를 활용해야 하는가?
### Practical Application Contexts
- **Implementation:** React로 버튼, 폼(Form), 토글(Toggle)과 같이 사용자의 직접적인 상호작용이나 상태(`useState`), 사이드 이펙트(`useEffect`)가 필요한 UI 조각을 구현할 때 상단에 `'use client'`를 선언하여 컴포넌트를 개발합니다 [1, 5].
- **System Design:** 대규모 시스템 설계 시 전체 레이아웃과 데이터 페칭 계층은 서버 컴포넌트로 구성하고, 상태 관리가 필요한 말단의 리프 노드(Leaf Node)나 특정 상호작용 영역만 클라이언트 컴포넌트로 감싸는(Boundary) 캡슐화 전략을 적용합니다 [13, 24].
- **Operation / Maintenance:** 코드 리뷰 및 유지보수 과정에서 정적인 텍스트만 보여주는 컴포넌트가 클라이언트 컴포넌트로 지정되지 않았는지 주기적으로 검수하여, 불필요한 자바스크립트 전송과 성능 하락을 방지합니다 [19, 20].
- **Learning Path:** 전통적인 React의 생명주기와 상태 관리를 먼저 학습한 후, SSR과 Hydration의 한계를 파악하고, React 19 및 Next.js 앱 라우터를 통해 RSC 및 클라이언트 컴포넌트 분리 원리를 익힙니다.
- **My Project Relevance:** 차세대 웹 프로젝트를 구축할 때, 유저 인터랙션이 잦은 장바구니/채팅 기능은 클라이언트 컴포넌트로 만들고, 제품 목록 등은 서버 컴포넌트로 구축하여 초기 렌더링 성능을 극대화하는 데 활용될 수 있습니다.
### Adjacent Topics
- [[Server Actions]]
- 확장 방향: 클라이언트 컴포넌트 내에서 발생한 이벤트를 처리하기 위해 서버 컴포넌트의 기능(데이터베이스 업데이트 등)을 브라우저에서 안전하게 호출하는 최신 패턴으로 확장하여 학습할 수 있습니다 [25-27].
- [[Suspense]]
- 확장 방향: 클라이언트 컴포넌트가 아직 로딩 중이거나 서버에서 데이터 스트리밍이 진행 중일 때, 사용자의 대기 시간을 부드럽게 처리하는 로딩 스켈레톤(UI) 구현 메커니즘으로 학습을 확장합니다 [28-30].
---
*Last updated: 2026-05-03*
---
*Last updated: 2026-05-03*
- Raw Source: 00_Raw/2026-05-03/Client Components.md
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>Count: {n}</button>;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Server Component → Client Component (props)
```tsx
// page.tsx (Server)
import { getProducts } from '@/lib/db';
import { ProductGrid } from './ProductGrid';
**선택 A를 써야 할 때:**
- *(TODO)*
export default async function Page() {
const products = await getProducts(); // server fetch
return <ProductGrid initial={products} />;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
```tsx
// ProductGrid.tsx (Client — interactive filter)
'use client';
import { useState } from 'react';
**기본값:**
> *(TODO)*
export function ProductGrid({ initial }: { initial: Product[] }) {
const [filter, setFilter] = useState('');
const visible = initial.filter(p => p.name.includes(filter));
return (
<>
<input value={filter} onChange={e => setFilter(e.target.value)} />
{visible.map(p => <Card key={p.id} {...p} />)}
</>
);
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Client Component 안 Server Component (children slot)
```tsx
// Layout.tsx (Client — needs onClick)
'use client';
export function Sidebar({ children }: { children: ReactNode }) {
return <aside onClick={...}>{children}</aside>;
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// page.tsx (Server)
import { Sidebar } from './Sidebar';
import { ServerProfile } from './ServerProfile';
export default function Page() {
return (
<Sidebar>
<ServerProfile /> {/* Server component as children — OK */}
</Sidebar>
);
}
```
### Server Action 호출 (Client → Server mutation)
```tsx
'use client';
import { createPost } from './actions'; // 'use server' file
export function NewPostForm() {
return (
<form action={createPost}>
<input name="title" />
<button>Submit</button>
</form>
);
}
```
### Suspense + Streaming
```tsx
// page.tsx (Server)
import { Suspense } from 'react';
import { Comments } from './Comments';
export default function Page() {
return (
<>
<Article />
<Suspense fallback={<Skeleton />}>
<Comments /> {/* streamed in */}
</Suspense>
</>
);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Static rendering, data fetching | **Server Component** (default) |
| State / event / effect / browser API | **Client Component** |
| SEO + interactive (form) | Server shell + Client island |
| 매 entire page interactive (dashboard) | Mostly client, server outer layout |
**기본값**: 매 default Server Component — 매 boundary 를 leaf 에 push, 매 'use client' 매 minimum.
## 🔗 Graph
- 부모: [[React Server Components]] · [[Next.js App Router]]
- 변형: [[Server Components]] · [[Server Actions]]
- 응용: [[Hydration]] · [[Suspense]] · [[Streaming SSR]]
- Adjacent: [[Islands Architecture]] · [[Astro]]
## 🤖 LLM 활용
**언제**: interactivity 매 필요한 leaf component, browser-only API, 매 form / input control.
**언제 X**: data fetching 매 only, static content — Server Component 가 더 light.
## ❌ 안티패턴
- **Root layout 매 'use client'**: 매 entire app 매 client bundle — 매 RSC benefit 의 destruction.
- **Server-only data 매 props 로 큰 객체 pass**: 매 RSC payload bloat.
- **Client component 안 server-only import** (e.g., `fs`, `db`): 매 build error / leak risk.
- **Server Component 안 useState**: 매 build error — 매 boundary 의 misunderstanding.
## 🧪 검증 / 중복
- Verified (React docs RSC 2026, Next.js 15 App Router guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 'use client' boundary + composition rules + Server Action |
@@ -1,121 +1,168 @@
---
id: wiki-2026-0508-client-side-rendering-csr
title: Client Side Rendering (CSR)
category: Frontend
status: needs_review
title: Client-Side Rendering (CSR)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [CSR, SPA Rendering]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [auto-wikified, technical-documentation, merged, frontend]
confidence_score: 0.9
verification_status: applied
tags: [rendering, csr, spa, frontend, performance]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React / Vue / Svelte
---
# Client-Side Rendering (CSR)
## 매 한 줄
> **"매 browser 가 매 HTML 을 그린다"**. CSR 은 server 가 빈 shell + JS bundle 만 보내고, browser 가 fetch + render 모두 수행 — 매 SPA 의 default mode, interactive app 에 강하나 매 first paint / SEO 매 weak.
## 📌 한 줄 통찰 (The Karpathy Summary)
클라이언트 사이드 렌더링(CSR)은 사용자가 초기에 비어 있는 HTML 파일과 자바스크립트 번들을 수신한 뒤, 브라우저에서 스크립트를 실행하여 동적으로 UI를 구성하는 렌더링 전략이다 [1, 2]. 각 컴포넌트가 독립적으로 데이터를 가져오게 할 수 있어 개발 편의성이 높고 고도의 상호작용이 필요한 애플리케이션에 적합하다 [3, 4]. 하지만 자바스크립트 다운로드와 실행이 완료될 때까지 빈 화면이 노출되며, 사용자 기기의 성능에 앱의 구동 속도가 크게 의존한다는 단점이 있다 [5, 6].
## 매 핵심
## 📖 구조화된 지식 (Synthesized Content)
* **동작 메커니즘**
초기 요청 시 클라이언트는 내용이 없고 `<script>` 태그만 포함된 HTML 파일을 전달받는다 [2]. 스크립트 형태의 자바스크립트 번들에는 React와 같은 프레임워크와 모든 작성된 코드가 포함되어 있다 [1]. 자바스크립트가 다운로드되고 파싱을 마치면 프레임워크가 브라우저에서 부팅되어 처음부터 모든 DOM 노드를 생성하고 화면을 렌더링한다 [1, 2].
* **데이터 페칭(Data Fetching) 방식**
과거 CSR 모델에서 데이터를 로드하는 유일한 방법은 클라이언트에서 부수 효과(side-effect)를 이용하는 것이었다 [7]. 애플리케이션이 사용자 브라우저에 도달하고 나서야 데이터를 요청하기 때문에, 처음에는 헤더나 일반적인 레이아웃 같은 '셸(Shell)'만 로딩 상태로 렌더링된다 [2]. 이후 네트워크 요청이 완료되면 로딩 UI를 실제 데이터 콘텐츠로 대체하여 다시 렌더링한다 [8].
* **개발 편의성 및 상호작용 최적화**
클라이언트 렌더링 SPA(Single Page Application)는 렌더링이 필요한 컴포넌트 스스로가 필요한 데이터를 알아서 페칭하도록 설계할 수 있어 개발 편의성(convenience) 측면에서 매우 뛰어나다 [3]. 특히 그리기 도구, 실시간 에디터, 복잡한 폼 처리 등 상호작용이 주가 되는 애플리케이션의 경우, 거의 모든 요소가 클라이언트 컴포넌트로 구성되므로 이 방식이 자연스럽게 적용된다 [4].
### 매 lifecycle
1. Browser → server: `GET /` → minimal HTML + `<script src="bundle.js">`.
2. Browser parses HTML → fetches JS bundle.
3. JS executes → mounts framework → fetches data → renders DOM.
4. User interacts.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **초기 로딩 지연 (Blank White Screen)**
자바스크립트 코드를 다운로드하고 파싱하여 DOM을 구축하는 데 긴 시간이 소요되며, 이 과정 동안 사용자는 아무것도 없는 빈 하얀 화면을 보며 대기해야 한다 [6].
* **번들 크기 비대화**
애플리케이션에 새로운 기능을 배포할 때마다 자바스크립트 번들의 용량은 계속해서 증가하는 경향이 있다 [6]. 번들이 커질수록 사용자가 대기해야 하는 시간이 길어지며 초기 로딩 성능이 더욱 악화된다 [6].
* **네트워크 비효율성**
앱이 사용자 브라우저에 로드된 이후에야 비로소 데이터 로딩을 시작할 수 있으므로, 초기 데이터를 화면에 표시하기까지의 과정이 매우 느리고 네트워크 효율성이 떨어진다 [7].
* **사용자 기기 의존성 심화**
상태 관리부터 렌더링까지 모든 해결책이 클라이언트(브라우저) 내부에 머물게 된다 [5]. 결과적으로 사용자 기기의 컴퓨팅 파워 자체가 애플리케이션 성능의 병목(bottleneck)으로 작용하게 된다 [5].
### 매 trade-off
| Pros | Cons |
|---|---|
| Rich interactivity | Slow TTI (특히 mobile) |
| Server cost low | SEO 매 needs hydration tricks |
| Client routing fast | Blank screen until JS loads |
| Offline-capable (PWA) | Bundle size matters a lot |
---
*Last updated: 2026-05-03*
### 매 CSR vs SSR vs RSC (2026)
- CSR: dashboard, internal tool, app-like UX.
- SSR: marketing, blog, e-commerce.
- RSC: hybrid — server-render with client islands.
- SSG: docs, blog (rebuild on content change).
## 📚 Legacy Insights & Additional Context
> [!NOTE]
> Below is content merged from previous versions of this documentation.
## 💻 패턴
## 📌 한 줄 통찰 (The Karpathy Summary)
Client-Side Rendering (CSR)은 브라우저(클라이언트)가 서버로부터 최소한의 HTML 뼈대와 [[JavaScript|JavaScript]] 번들을 전달받은 후, JavaScript를 실행하여 동적으로 웹 페이지의 콘텐츠를 렌더링하고 UI를 구축하는 방식입니다 [1-3]. 이 방식은 주로 React나 Vue와 같은 라이브러리를 통해 단일 페이지 애플리케이션(SPA) 형태로 구현됩니다 [2, 4, 5]. 초기 로딩 이후에는 전체 페이지 새로고침 없이 즉각적인 화면 전환이 가능하여 매끄럽고 앱과 같은 사용자 경험을 제공하는 것이 특징입니다 [1, 6-8].
### Vite + React CSR baseline
```tsx
// main.tsx
import { createRoot } from 'react-dom/client';
import App from './App';
## 📖 구조화된 지식 (Synthesized Content)
* **작동 메커니즘**: CSR 환경에서 서버는 콘텐츠가 거의 없는 빈 HTML 파일과 JavaScript 코드를 클라이언트로 전송합니다 [1-3]. 브라우저는 이 JavaScript를 다운로드하고 파싱 및 실행한 뒤에야 필요한 데이터를 가져오고 [[DOM (Document Object Model)|DOM(Document Object Model]]을 생성하여 실제 화면에 시각적 콘텐츠를 렌더링합니다 [1, 2, 9].
* **주요 장점**:
* **풍부한 상호작용 및 UX**: 첫 페이지 로드 이후 후속 조작 시 서버에 전체 페이지를 다시 요청할 필요 없이 동적으로 필요한 데이터만 업데이트하므로, 전환이 매끄럽고 네이티브 앱과 같은 사용자 경험을 제공합니다 [1, 6-8].
* **서버 부하 및 호스팅 비용 감소**: 서버는 페이지 렌더링 연산을 수행하지 않고 정적 파일(HTML, CSS, JS)만 제공하면 되므로 리소스 부담이 적으며, Amazon S3나 Netlify와 같은 저렴한 정적 호스팅 서버를 활용할 수 있습니다 [6, 10].
* **빠른 개발 속도**: 개발자가 서버 측의 제약이나 호환성을 걱정하지 않고 `window` 객체와 같은 브라우저 전용 API를 자유롭게 활용할 수 있습니다 [10].
* **주요 한계 및 단점**:
* **초기 로딩 속도 저하**: 브라우저가 유의미한 콘텐츠를 표시하기 위해 전체 JavaScript 번들을 다운로드하고 실행할 때까지 기다려야 하므로 초기 렌더링(First Contentful Paint) 속도가 느립니다 [1, 6, 8, 9]. 이는 사용자의 기기 성능이나 네트워크 상태에 크게 의존합니다 [11].
* **검색 엔진 최적화(SEO) 제약**: 검색 엔진 크롤러나 소셜 미디어 봇이 웹사이트에 접근할 때 초기에는 빈 페이지만 보게 되므로, JavaScript를 제대로 파싱하지 못하면 콘텐츠 색인화 및 미리보기 생성이 누락될 수 있습니다 [1, 8, 9, 12, 13].
* **최적의 사용 사례(Use Cases)**: CSR은 SEO가 상대적으로 중요하지 않고, 사용자 상호작용과 실시간 데이터 업데이트가 필수적인 환경에 이상적입니다 [6, 14]. 로그인 장벽 뒤에 있는 대시보드, [[SaaS|SaaS]] 플랫폼, 내부 비즈니스 도구 및 소셜 미디어 플랫폼 등이 대표적인 적용 사례입니다 [2, 5, 14, 15].
## 🔗 지식 연결 (Graph)
- **Related Topics:** `[[Server-Side Rendering (SSR)|Server-Side Rendering (SSR]]`, `Single-Page Applications (SPA)`, `[[Static Site Generation (SSG)|Static Site Generation (SSG]]`, `Document Object Model (DOM)`
- **Projects/Contexts:** `SaaS 플랫폼 및 대시보드 개발`, `React 기반 고도의 동적 웹 애플리케이션 구축`
- **Contradictions/Notes:** 소스 전반에서 CSR의 '뛰어난 상호작용성'과 'SEO 및 초기 로딩의 취약점'에 대한 평가는 일치하며 상충하는 내용은 없습니다 [1, 6, 8, 9, 12, 13]. 다만 최근에는 CSR의 한계를 극복하기 위해 [[Next.js|Next.js]]와 같은 프레임워크를 사용하여 페이지의 목적에 맞게 SSR이나 SSG를 혼합(하이브리드 렌더링)하여 사용하는 방식이 권장되고 있습니다 [15-17].
---
*Last updated: 2026-04-25*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
createRoot(document.getElementById('root')!).render(<App />);
```
```html
<!-- index.html -->
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Route-based code splitting
```tsx
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router';
**선택 A를 써야 할 때:**
- *(TODO)*
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
**선택 B를 써야 할 때:**
- *(TODO)*
export default function App() {
return (
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
```
**기본값:**
> *(TODO)*
### Skeleton-first paint (perceived perf)
```tsx
function UsersList() {
const { data, isLoading } = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
if (isLoading) return <UsersSkeleton rows={10} />;
return <ul>{data!.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Pre-fetch on hover (link prefetch)
```tsx
<Link
to="/dashboard"
onMouseEnter={() => queryClient.prefetchQuery({ queryKey: ['dashboardData'], queryFn })}
>
Dashboard
</Link>
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Service Worker for offline shell
```ts
// sw.ts
self.addEventListener('install', (e: any) => {
e.waitUntil(caches.open('shell-v1').then((c) => c.addAll(['/', '/main.js', '/main.css'])));
});
self.addEventListener('fetch', (e: any) => {
e.respondWith(caches.match(e.request).then((r) => r ?? fetch(e.request)));
});
```
### Bundle budget enforcement
```js
// vite.config.ts
export default {
build: {
rollupOptions: {
output: {
manualChunks: { vendor: ['react', 'react-dom'] },
},
},
chunkSizeWarningLimit: 200, // KB
},
};
```
### SEO via prerender (when CSR + needed)
```bash
# Use prerender for marketing routes only
npx prerender-spa-plugin --routes /,/about,/pricing
```
## 매 결정 기준
| 상황 | Render mode |
|---|---|
| Auth-walled dashboard | CSR |
| Marketing site | SSG or SSR |
| Mixed app (e-commerce) | RSC / SSR + islands |
| Rich realtime (Figma-like) | CSR + WebSocket |
**기본값**: 매 user-app (login wall 뒤) → CSR. 매 public content → SSR/SSG/RSC.
## 🔗 Graph
- 부모: [[Rendering-Strategies]] · [[Frontend-Architecture]]
- 변형: [[Server-Side-Rendering]] · [[Static-Site-Generation]] · [[React-Server-Components]]
- 응용: [[Single-Page-Apps]] · [[Progressive-Web-Apps]]
- Adjacent: [[Core-Web-Vitals]] · [[Code-Splitting]] · [[Hydration]]
## 🤖 LLM 활용
**언제**: app-like UX, auth-protected, heavy client interactivity.
**언제 X**: 매 SEO-critical public page, low-end device 가 주 audience.
## ❌ 안티패턴
- **Mega-bundle**: 매 single chunk 5MB → split routes / vendor.
- **No skeleton / loading state**: 매 blank screen 매 perceived as broken.
- **CSR for blog/docs**: 매 SEO/perf 매 모두 lose — SSG choice.
## 🧪 검증 / 중복
- Verified (web.dev / React docs / Vite docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CSR fundamentals + tradeoffs + patterns |
+171 -97
View File
@@ -2,125 +2,199 @@
id: wiki-2026-0508-code-splitting
title: Code Splitting
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Bundle Splitting, Dynamic Import]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [bundling, performance, webpack, vite, frontend]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Vite / Webpack / Next.js
---
# [[Code Splitting|Code Splitting]]
# Code Splitting
## 📌 한 줄 통찰 (The Karpathy Summary)
큰 자바스크립트 번들을 더 작은 청크(chunk) 단위로 나누어 사용자가 필요로 할 때(on demand) 로드하는 프로세스입니다 [1, 2]. 모든 애플리케이션 코드를 초기에 한 번에 다운로드하는 대신, 필요한 파일만 먼저 불러오게 하여 초기 번들 크기를 극적으로 줄일 수 있습니다 [2, 3]. 결과적으로 초기 페이지 로드 속도를 향상시키고, 애플리케이션의 체감 성능을 개선하는 핵심적인 프론트엔드 최적화 기법입니다 [1, 4].
## 한 줄
> **"매 bundle 의 chunk 의 분리, on-demand load 의 first-paint 단축"**. Code Splitting 은 dynamic `import()` + bundler chunking 의 결합 의 매 monolithic JS bundle 의 분해. 2026 Vite/Rspack/Turbopack 시대 에 route-level + component-level + vendor split 의 매 표준.
## 📖 구조화된 지식 (Synthesized Content)
* **라우트 기반 분할 (Route-level Code Splitting):** 가장 일반적이고 효과적인 접근 방식입니다. 사용자가 특정 라우트로 이동할 때만 해당 페이지의 코드를 다운로드하도록 하여 초기 로딩 시 불필요한 코드 다운로드를 방지합니다 [1, 2, 5].
* **컴포넌트 수준 지연 로딩 (Component-level Lazy Loading):** 차트, 지도, 리치 텍스트 에디터처럼 크고 무거운 컴포넌트나 드물게 사용되는 모달, 설정 패널 등을 렌더링이 필요한 시점에만 로드하도록 분리합니다 [6, 7]. React에서는 `React.lazy()`와 동적 임포트(dynamic imports), 그리고 `<Suspense>`를 활용해 이를 쉽게 구현할 수 있습니다 [4, 6, 8].
* **벤더 라이브러리 분할 (Vendor Splitting):** Vite(내부적으로 Rollup 사용) 등의 번들러를 사용할 때 `manualChunks` 옵션을 통해 React 코어 라이브러리나 차트 등 무거운 벤더 코드를 별도의 파일로 분할합니다 [5, 9, 10]. 벤더 라이브러리는 자주 변경되지 않기 때문에 브라우저 캐싱 효율을 극대화할 수 있습니다 [5, 11].
* **번들러의 자동화 지원:** 최신 번들러(Webpack, Vite)는 코드 내에 작성된 동적 임포트(`import()`)를 감지하면 자동으로 해당 코드를 별도의 청크로 분리합니다 [4, 6].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **필수 컴포넌트에 대한 오남용 금지:** 페이지에 즉시 필요한 스크롤 없이 볼 수 있는(above-the-fold) 핵심 컴포넌트나, 렌더링 속도가 빨라야 하는 요소에는 지연 로딩과 코드 분할을 피해야 합니다 [7]. 오히려 첫 화면을 그리는 시간을 지연시킬 수 있습니다.
* **사용자 경험 저하 방지 (Fallback UI 필요):** 코드를 동적으로 불러오는 동안 네트워크 지연이 발생할 수 있습니다. 따라서 `<Suspense>`를 사용해 모듈이 로드되는 동안 스피너나 스켈레톤과 같은 Fallback UI를 제공해야 합니다 [5, 8].
* **네트워크 요청 증가의 위험:** 너무 잘게 코드를 분할하면 오히려 수많은 네트워크 요청이 발생해 오버헤드가 발생할 수 있습니다. 따라서 번들 크기를 시각적으로 분석할 수 있는 `rollup-plugin-visualizer` 도구를 사용해 500kB 이상의 큰 청크를 타겟으로 식별하고 적절하게 분할해야 합니다 [12, 13].
### 매 splitting 의 axis
- **Route-based**: 각 page 의 separate chunk — 매 SPA / Next.js 의 default
- **Component-based**: heavy component 의 lazy (Modal, Chart, Editor)
- **Vendor**: `node_modules`separate chunk — long-term cache
- **Dynamic feature**: locale, A/B variant 의 conditional load
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 mechanism
- **Dynamic `import()`**: ECMAScript spec — Promise 의 return
- **Bundler 의 split point detection**: `import()` 호출 의 chunk boundary
- **Manifest**: hashed filename 의 mapping
- **Preload / prefetch**: `<link rel="preload/prefetch">` hint
#### [아키텍처/기반 기술]
- [[Lazy Loading|Lazy Loading]]
- 연결 이유: 코드 분할이 번들을 쪼개는 행위라면, 지연 로딩(Lazy Loading)은 그 쪼개진 코드를 필요 시점에 로드하는 기술적 방법론입니다 [2, 3].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분할된 코드가 언제 브라우저로 전송되고 애플리케이션에 병합되는지 이해할 수 있습니다 [8].
- [[Core Web Vitals|Core Web Vitals]]
- 연결 이유: 코드 분할을 적용하는 주된 성능적 목적은 초기 자바스크립트 실행을 최소화하여 LCP(Largest Contentful Paint)와 INP(Interaction to Next Paint) 같은 핵심 웹 지표를 향상시키는 데 있습니다 [1, 8, 14].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 최적화 결과가 실제 사용자의 체감 성능 및 페이지 측정 지표에 어떻게 긍정적 영향을 주는지 평가할 수 있습니다 [15].
### 매 cost trade-off
- **Pro**: initial bundle 의 작아짐 → faster TTI
- **Con**: extra HTTP request, waterfall 위험 — preload 의 mitigate
#### [구현/활용 도구]
- React.lazy() and Suspense
- 연결 이유: React 애플리케이션에서 컴포넌트 레벨 및 라우트 레벨의 동적 코드 분할을 구현하기 위해 사용하는 공식 API입니다 [6, 8].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 동적 임포트 처리 과정에서의 비동기 UI 렌더링 흐름과 예외(지연) 처리 방식을 배울 수 있습니다 [5].
- Vite (Rollup)
- 연결 이유: 개발 및 프로덕션 환경에서 자바스크립트 애플리케이션을 번들링하고 실제 물리적인 청크 파일들로 분리해 내는 도구입니다 [9, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 번들러의 `manualChunks` 설정을 통해 어떻게 벤더 라이브러리와 애플리케이션 코드를 효율적으로 나누어 브라우저 캐싱을 활용할 수 있는지 이해할 수 있습니다 [5].
### 매 응용
1. Route-level lazy (React Router, Next.js).
2. Modal / dialog (open 시 load).
3. Heavy editor (Monaco, CodeMirror).
4. Chart library (Recharts, ECharts).
5. i18n locale chunk.
### Deeper Research Questions
- 라우트 기반 분할과 컴포넌트 기반 분할을 어느 정도 비율로 적용해야 초기 렌더링 성능과 이후 탐색 시의 네트워크 지연 간의 균형을 이룰 수 있는가?
- Vite나 Webpack 환경에서 `manualChunks`를 설정할 때, 브라우저의 HTTP/2 및 HTTP/3 다중화(multiplexing) 환경을 고려한 가장 이상적인 청크 개수와 크기는 무엇인가?
- 동적 청크(chunk)를 로드하는 도중 사용자의 네트워크 연결이 끊기거나 에러가 발생할 경우, React Error Boundaries와 결합하여 어떻게 안정적인 Fallback 경험을 설계할 것인가?
- 코드 분할로 인해 컴포넌트가 지연 로드될 때, 해당 컴포넌트가 의존하는 상태(Context, Zustand 등)는 로드 시점에 어떻게 동기화되는가?
- Above-the-fold UI에 잘못 지연 로딩을 적용했을 때 LCP 점수에 미치는 악영향을 확인하려면 브라우저 개발자 도구의 성능(Performance) 패널에서 어떤 지표를 중점적으로 모니터링해야 하는가?
## 💻 패턴
### Practical Application Contexts
- **Implementation:** React 코드에서 `import { Chart } from 'chart.js'`와 같은 정적 임포트를 제거하고, `const HeavyComponent = React.lazy(() => import('./HeavyComponent'))`로 감싸서 특정 버튼이 눌리거나 라우트가 전환될 때 렌더링되게 구현합니다 [4, 6, 8].
- **System Design:** 아키텍처 설계 시, 모든 코드가 포함된 하나의 `index.js` 모놀리스 번들 대신, Vite의 `vite.config.ts`에서 `manualChunks` 설정을 통해 React 코어 및 무거운 서드파티 라이브러리를 별개의 캐싱 가능한 청크로 분리하도록 설계합니다 [5, 10].
- **Operation / Maintenance:** CI/CD 파이프라인이나 로컬 빌드 과정에 `rollup-plugin-visualizer` 등의 번들 분석 도구를 연결하여 시각적 트리맵을 확인하고, 500kB를 초과하는 거대 청크가 발견되면 추가적인 분할 대상을 식별하여 최적화합니다 [4, 12, 13].
- **Learning Path:** 우선 React의 번들링 개념을 이해한 후, 동적 임포트 구문 활용 -> `React.lazy()``<Suspense>` 적용 -> 라우터에 코드 분할 결합 -> 번들 분석기 및 Core Web Vitals 측정을 통한 효과 검증 순서로 지식을 확장합니다 [6, 8].
- **My Project Relevance:** 프로젝트 규모가 커짐에 따라 메인 자바스크립트 번들이 수 메가바이트 단위로 무거워져 모바일 기기 등에서 로딩 속도 저하 현상이 보일 경우, 즉각적으로 라우트 기반 코드 분할과 차트/에디터 등 무거운 UI의 지연 로딩을 도입하여 LCP 문제를 해결할 수 있습니다 [3, 14, 16].
### React.lazy + Suspense
```tsx
import { lazy, Suspense } from 'react';
### Adjacent Topics
- [[Tree Shaking (번들 크기 최적화)|Tree Shaking]]
- 확장 방향: 코드 분할이 필요한 코드를 '쪼개어' 가져오는 방식이라면, 트리 쉐이킹은 사용되지 않는 죽은 코드(Dead Code) 자체를 번들에서 '제거'하여 초기 번들 크기를 줄이는 상호 보완적인 최적화 기법입니다 [17, 18].
- Server Components (Next.js)
- 확장 방향: 클라이언트 사이드의 코드 분할에서 더 나아가, 아예 정적인 UI 렌더링을 서버에서 처리하여 클라이언트로 보내는 자바스크립트 번들의 양 자체를 획기적으로 줄이거나 제거하는 최신 아키텍처 접근법입니다 [19-21].
const Settings = lazy(() => import('./Settings'));
---
*Last updated: 2026-04-30*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export default function App() {
return (
<Suspense fallback={<Spinner />}>
<Settings />
</Suspense>
);
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Next.js dynamic
```tsx
import dynamic from 'next/dynamic';
**선택 A를 써야 할 때:**
- *(TODO)*
const Chart = dynamic(() => import('@/components/Chart'), {
loading: () => <p>Loading chart...</p>,
ssr: false, // browser-only
});
**선택 B를 써야 할 때:**
- *(TODO)*
export default function Dashboard() {
return <Chart data={data} />;
}
```
**기본값:**
> *(TODO)*
### Route-level (React Router v6)
```tsx
import { lazy } from 'react';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
## ❌ 안티패턴 (Anti-Patterns)
const router = createBrowserRouter([
{ path: '/', lazy: () => import('./routes/Home') },
{ path: '/about', lazy: () => import('./routes/About') },
{ path: '/admin/*', lazy: () => import('./routes/Admin') },
]);
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default function App() {
return <RouterProvider router={router} />;
}
```
### Vite의 manualChunks
```ts
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
react: ['react', 'react-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-tabs'],
charts: ['recharts', 'd3'],
},
},
},
},
});
```
### Webpack magic comment
```ts
const Editor = () => import(
/* webpackChunkName: "editor" */
/* webpackPrefetch: true */
'./Editor'
);
```
### Conditional import (locale)
```ts
async function loadLocale(lang: string) {
const messages = await import(`./locales/${lang}.json`);
return messages.default;
}
```
### Preload critical chunk
```html
<link rel="modulepreload" href="/assets/Settings-abc123.js">
```
```tsx
// React: preload on hover
<Link
to="/settings"
onMouseEnter={() => import('./Settings')}
>
Settings
</Link>
```
### Module Federation (micro-frontend)
```ts
// host webpack.config.js
new ModuleFederationPlugin({
remotes: {
checkout: 'checkout@https://cdn/checkout/remoteEntry.js',
},
});
// usage
const Checkout = lazy(() => import('checkout/Cart'));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| SPA, multi-page | Route-based split |
| Heavy modal / editor | `lazy()` + Suspense |
| Vendor lib stable | manualChunks vendor split |
| SSR + browser-only | `dynamic({ ssr: false })` |
| Independent deploy | Module Federation |
| Hover-triggered | preload on intent |
**기본값**: route-based + heavy-component lazy + vendor chunk.
## 🔗 Graph
- 부모: [[Bundling]] · [[Web Performance]]
- 변형: [[Tree Shaking]] · [[Module Federation]]
- 응용: [[Lazy Loading]] · [[Route-based Splitting]]
- Adjacent: [[Vite]] · [[Webpack]] · [[Next.js]] · [[Suspense]]
## 🤖 LLM 활용
**언제**: route lazy, heavy component 의 split, vendor chunking 코드 generation.
**언제 X**: 매 small app (10kb 의 split 의 overhead 가 더 큼).
## ❌ 안티패턴
- **너무 fine-grained split**: 100개 chunk → request flood — 매 ~10-30 chunk 의 sweet spot.
- **Waterfall**: A → B → C 의 sequential — 매 parallel preload.
- **Vendor chunk 의 무한 growth**: dependency 추가 시 cache invalidation — 매 stable lib 만 vendor.
- **Suspense 의 boundary 누락**: error / blank screen.
- **`ssr: false` 의 abuse**: SEO 손실.
## 🧪 검증 / 중복
- Verified (Vite docs, Webpack docs, Next.js docs, React 19).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — splitting strategies + bundler config + MF |
+152 -112
View File
@@ -1,137 +1,177 @@
---
id: wiki-2026-0508-codegen
title: Codegen
category: Frontend
status: needs_review
title: Codegen (GraphQL, OpenAPI, Schema-driven)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [Code Generation, GraphQL Codegen, OpenAPI Codegen]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [auto-wikified, technical-documentation, frontend]
confidence_score: 0.9
verification_status: applied
tags: [codegen, graphql, openapi, typescript, tooling]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: GraphQL Code Generator / openapi-typescript
---
# Codegen
# Codegen (Schema-driven Code Generation)
## 📌 한 줄 통찰 (The Karpathy Summary)
Codegen(코드 생성)은 소프트웨어 아키텍처에서 빌드 시점이나 개발 단계에 반복적인 보일러플레이트 코드나 연결 코드를 자동으로 생성하여 생산성과 안전성을 높이는 실전 패턴이다 [1, 2]. 프레임워크 수준에서는 동적 타입 환경과 정적 타입 환경 간의 통신 시 발생하는 런타임 오버헤드와 타입 오류를 컴파일 타임에 방지하기 위해 사용된다 [2]. 또한, 횡단 관심사(Cross-Cutting Concerns) 처리를 위해 고급 IDE 도구 및 AI를 통해 코드를 생성하는 개발론적 접근법도 포함된다 [1, 3].
## 한 줄
> **"매 schema 가 single source of truth"**. Codegen 은 GraphQL/OpenAPI/Protobuf schema 에서 type 과 client code 를 자동 생성 — 매 manual sync 의 X, drift 의 zero, refactor 매 compile-time safe.
## 📖 구조화된 지식 (Synthesized Content)
**프레임워크 수준의 아키텍처 도구: React Native New Architecture**
* React Native의 새로운 아키텍처(New Architecture)에서 Codegen은 동적 타입의 자바스크립트 세계와 정적 타입의 네이티브 플랫폼(Java/Kotlin, Objective-C/Swift) 간의 매끄럽고 안전한 통신을 보장하기 위해 도입되었다 [2].
* 빌드 시점에 TypeScript 또는 Flow의 타입 정의를 분석하여 자바스크립트와 네이티브 측을 연결하는 데 필요한 C++ 보일러플레이트 코드를 자동으로 생성한다 [2].
* 이를 통해 경계 간의 강력한 타입 안전성(Type safety)을 제공하며, 런타임이 아닌 컴파일 타임에 오류를 잡아내어 버그를 크게 줄이고 전반적인 개발자 경험을 향상시킨다 [2].
## 매 핵심
**생산성 및 횡단 관심사 관리를 위한 코드 생성 패턴**
* 일부 고급 IDE는 코드 생성 도구를 제공하여 완전히 동일한 코드를 반복적으로 삽입하고, 팀 전체에 특정 아키텍처 패턴을 쉽게 공유할 수 있도록 지원한다 [1].
* 최근에는 AI 기반 도구를 활용하여 보일러플레이트 코드를 신속하게 생성하는 방식이 등장하여 교차 관심사 등을 다루는 대안으로 고려되고 있다 [3].
* 부가적으로 Flutter 생태계의 `Auto Route`는 코드 생성을 통해 타입 안전성이 보장되는 라우팅을 제공하며 [4], NestJS는 데코레이터와 DTO를 기반으로 Swagger/OpenAPI 문서를 자동 생성하여 실제 코드베이스와 API 문서 간의 동기화를 보장한다 [5, 6].
### 매 주요 도구 (2026)
- **GraphQL**: `@graphql-codegen/cli` (client preset), `gql.tada` (zero-config inline).
- **OpenAPI**: `openapi-typescript` (types), `openapi-fetch` (typed client), `orval` (React Query hooks).
- **gRPC/Protobuf**: `bufbuild/protobuf-es`, `connect-es`.
- **DB schema**: `kysely-codegen`, `drizzle-kit`, Prisma.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **유지보수의 어려움 및 코드 중복:** IDE 도구를 통한 코드 생성 패턴은 본질적으로 코드베이스 내에 코드 중복(Duplication)을 발생시킨다 [1]. 향후 에러 처리 방식 등 특정 패턴을 전체적으로 변경해야 할 경우, 중복된 코드를 일일이 찾아 수동으로 변경해야 하는 어려움이 따를 수 있다 [1, 7].
* **AI 생성 코드의 일관성 및 기능적 결함 문제:** AI를 활용하여 보일러플레이트를 생성할 경우, AI가 매번 새로운 코드를 지어내기 때문에 일관성을 완벽히 보장하기 어렵다 [3]. 미세한 외관상 또는 기능적 차이가 발생할 수 있다는 위협이 상존하며 [3], 실제로 개발자의 96%가 AI 생성 코드가 기능적으로 올바른지 완전히 신뢰하지 못하는 것으로 나타났다 [8].
* **초기 설정 및 빌드 복잡도 증가:** React Native의 Codegen과 같이 C++ 기반으로 인터페이스를 자동 생성하는 아키텍처는 타입 안전성을 보장하는 대신, 빌드 타임에 코드를 분석하고 생성하는 추가적인 파이프라인이 요구되어 프로젝트 초기 설정의 복잡도를 증가시킬 수 있다 (컴파일 타임 로직 도입에 따른 일반적 제약 사항) [2].
### 매 출력 종류
- Type definitions only (lightweight).
- Typed client (operations + types).
- Hooks/composables (React Query, SWR, urql).
- Server stubs (resolvers, controllers).
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 watch vs build-time
- Dev: watch mode → 매 save 시 regen.
- CI: `--check` 로 매 schema/code drift 검출.
- Pre-commit: 매 generated files 매 staged 보장.
#### [관계 유형 A (아키텍처/기반 기술)]
- [[React Native New Architecture]]
- 연결 이유: Codegen은 이 새로운 아키텍처를 구성하는 핵심 시스템 중 하나로 도입되었기 때문이다 [2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 기존 비동기 브릿지 구조의 성능 한계를 극복하기 위해 Codegen이 JSI 및 Fabric 시스템과 어떻게 상호작용하는지 아키텍처 전체 관점에서 이해할 수 있다 [2, 9].
## 💻 패턴
- [[JSI (JavaScript Interface)]]
- 연결 이유: Codegen이 생성하는 C++ 보일러플레이트 코드는 JSI를 기반으로 작동하여 자바스크립트와 네이티브 코드 간의 동기적 통신을 가능하게 하기 때문이다 [2, 10].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 직렬화(Serialization) 오버헤드 없이 직접 참조를 통해 데이터를 교환하는 저수준 메커니즘을 파악할 수 있다 [2, 10].
### GraphQL client preset (@graphql-codegen/cli)
```yaml
# codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli';
#### [관계 유형 B (구현/활용 도구)]
- [[TypeScript]]
- 연결 이유: React Native의 Codegen이 C++ 인터페이스를 생성하기 위해 빌드 시점에 분석하는 대상 언어이자 타입 시스템이기 때문이다 [2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 타입 안전성(Type safety)이 프론트엔드를 넘어 네이티브 컴파일 영역까지 확장되는 과정을 배울 수 있다 [2].
- [[Boilerplate]]
- 연결 이유: Codegen, IDE, 그리고 AI 코드 생성 도구들이 공통적으로 자동화하거나 축소시키고자 하는 대상이 반복되는 보일러플레이트 코드이기 때문이다 [1-3].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 대규모 시스템에서 중복 코드를 줄이는 것이 개발 경험(DX)과 기술 부채 최소화에 어떤 영향을 미치는지 이해할 수 있다 [1, 2].
### Deeper Research Questions
- React Native의 Codegen이 TypeScript의 복잡한 사용자 정의 타입이나 유니온 타입을 C++로 트랜스파일할 때 발생할 수 있는 제약사항이나 타입 매핑 전략은 무엇인가?
- IDE 및 AI 기반 코드 생성기(Code generator)로 횡단 관심사를 처리하는 패턴이 대규모 프로젝트의 기술 부채로 이어지지 않게 하기 위한 효과적인 코드 리뷰 및 검증 파이프라인은 어떻게 구성해야 하는가?
- Flutter의 Auto Route와 같이 코드 생성을 기반으로 하는 라우팅 방식은 동적 런타임 라우팅과 비교하여 컴파일 속도와 트리 쉐이킹(Tree-shaking) 관점에서 어떤 차별점이 있는가?
- 런타임에 리플렉션(Reflection)이나 AOP를 사용하는 백엔드 프레임워크 구조와 빌드 타임에 보일러플레이트를 정적으로 생성하는 프론트엔드/모바일의 Codegen 구조 간의 근본적인 성능 트레이드오프는 무엇인가?
- AI를 통한 보일러플레이트 생성(Generative AI Code)의 비일관성을 방지하고 일관된 디자인 패턴을 강제할 수 있는 컨텍스트 주입 프롬프팅 또는 사내 규약 템플릿화 방안은 무엇이 있는가?
### Practical Application Contexts
- **Implementation:** React Native 앱에 네이티브 모듈을 통합할 때, JavaScript/TypeScript 인터페이스만 작성하면 빌드 파이프라인에 포함된 Codegen을 통해 C++ 및 네이티브 바인딩 코드를 자동 생성하여 타입 안전성을 확보한다.
- **System Design:** 동적 언어(JS) 환경에서 정적 언어(Java, Swift) 생태계의 기능을 호출해야 하는 시스템을 설계할 때, 직렬화 비용을 줄이기 위해 브릿지 코드를 수동으로 유지보수하지 않고 자동 생성하는 아키텍처 계층을 구축한다.
- **Operation / Maintenance:** AI나 IDE를 통해 자동 생성된 보일러플레이트 코드들이 코드베이스 전체에 산재해 있을 경우, 글로벌 아키텍처 변경 시 수동 리팩토링의 위험이 존재하므로 일관된 정적 분석 및 린트(Lint) 파이프라인을 운영해야 한다.
- **Learning Path:** 크로스 플랫폼 프레임워크의 진화 과정을 학습할 때, 런타임 비동기 브릿지 모델에서 JSI와 Codegen을 활용한 컴파일 타임 동기 모델로 패러다임이 어떻게 전환되었는지 파악하는 단계로 활용한다.
- **My Project Relevance:** 현재 도입 중인 프레임워크나 도구 생태계에서 수작업으로 발생하던 타입 변환 오류나 중복 코드를 제거하기 위해, OpenAPI 스펙 자동 생성, 자동 라우팅 매핑 등 관련 코드 생성(Codegen) 전략을 도입할지 검토한다.
### Adjacent Topics
- [[TurboModules]]
- 확장 방향: React Native New Architecture에서 Codegen에 의해 생성된 바인딩 코드를 실제로 사용하여 지연 로딩(Lazy loading)과 고성능 네이티브 호출을 실현하는 모듈 아키텍처로 확장하여 연구.
- [[AOP (Aspect-Oriented Programming)]]
- 확장 방향: 코드를 텍스트 레벨에서 정적으로 생성해내는 Codegen 방식과 달리, 어노테이션 등을 통해 컴파일 시점이나 런타임에 횡단 관심사를 위빙(Weaving)하여 처리하는 대안적 패턴에 대한 비교 분석으로 확장.
---
*Last updated: 2026-05-03*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const config: CodegenConfig = {
schema: 'https://api.example.com/graphql',
documents: ['src/**/*.{ts,tsx}'],
generates: {
'src/gql/': {
preset: 'client',
config: { useTypeImports: true, scalars: { DateTime: 'string' } },
},
},
};
export default config;
```
## 🤔 의사결정 기준 (Decision Criteria)
### Using generated `graphql()` (typed documents)
```ts
import { graphql } from '@/gql';
import { useQuery } from '@tanstack/react-query';
**선택 A를 써야 할 때:**
- *(TODO)*
const FlightSearch = graphql(`
query FlightSearch($from: String!, $to: String!) {
flights(from: $from, to: $to) { id price airline }
}
`);
**선택 B를 써야 할 때:**
- *(TODO)*
export function useFlights(vars: { from: string; to: string }) {
return useQuery({
queryKey: ['flights', vars],
queryFn: () => request('/graphql', FlightSearch, vars),
});
}
```
**기본값:**
> *(TODO)*
### gql.tada (zero-config alternative)
```ts
import { graphql } from 'gql.tada';
## ❌ 안티패턴 (Anti-Patterns)
const Query = graphql(`
query Me { me { id email } }
`);
// 매 inferred 매 fully typed — no codegen step
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### openapi-typescript + openapi-fetch
```bash
npx openapi-typescript ./openapi.yaml -o ./src/api/schema.ts
```
```ts
import createClient from 'openapi-fetch';
import type { paths } from './api/schema';
const api = createClient<paths>({ baseUrl: 'https://api.example.com' });
const { data, error } = await api.GET('/users/{id}', {
params: { path: { id: '42' } },
});
// data 매 매 fully typed
```
### orval — React Query hooks from OpenAPI
```ts
// orval.config.ts
export default {
api: {
input: './openapi.yaml',
output: {
target: './src/api/generated.ts',
client: 'react-query',
mode: 'tags-split',
},
},
};
```
### Drizzle Kit — DB schema introspection
```bash
drizzle-kit introspect:pg --connectionString=$DATABASE_URL --out=./src/db
```
### CI drift check
```yaml
# .github/workflows/codegen-check.yml
- run: pnpm codegen
- run: git diff --exit-code src/gql src/api
```
### Husky pre-commit
```sh
# .husky/pre-commit
pnpm codegen && git add src/gql src/api
```
## 매 결정 기준
| 상황 | 도구 |
|---|---|
| GraphQL + React/Vue | `@graphql-codegen` client preset |
| GraphQL + want zero step | `gql.tada` |
| OpenAPI types only | `openapi-typescript` |
| OpenAPI + hooks | `orval` |
| DB-first | Drizzle / Prisma / Kysely codegen |
**기본값**: GraphQL → client preset; REST → `openapi-typescript` + `openapi-fetch`.
## 🔗 Graph
- 부모: [[Tooling]] · [[Type-Safety]]
- 변형: [[GraphQL]] · [[OpenAPI]] · [[gRPC]]
- 응용: [[React-Query]] · [[urql]] · [[Apollo-Client]]
- Adjacent: [[Schema-First-Design]] · [[Contract-Testing]]
## 🤖 LLM 활용
**언제**: schema-driven API integration / 매 type drift 매 painful 한 monorepo.
**언제 X**: 매 throwaway prototype, schema 매 unstable.
## ❌ 안티패턴
- **Hand-writing GraphQL types**: 매 drift 의 zero-day issue.
- **Committing nothing then expecting safety**: 매 generated files 매 commit + CI check 둘 다 필요.
- **Running codegen only locally**: 매 CI drift check 의 X 면 PR 매 깨짐.
## 🧪 검증 / 중복
- Verified (the-guild.dev / openapi-ts.dev / orval.dev official docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — codegen tools (GraphQL/OpenAPI) with patterns |
@@ -1,25 +1,33 @@
---
id: wiki-20260508-component-based-architecture-redir
id: wiki-2026-0508-component-based-architecture-redir
title: Component Based Architecture
category: Frontend
status: merged
redirect_to: Component-Based_Architecture
canonical_id: Component-Based_Architecture
category: 10_Wiki/Topics
status: duplicate
canonical_id: component-composition
duplicate_of: "[[Component-Composition]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [redirect]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, frontend, architecture, component]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-merge 2026-05-08)
---
# Component Based Architecture
> [!IMPORTANT]
> 이 문서는 P-Reinforce Phase 2 자동 MERGE에 의해 **[[Component-Based_Architecture]]**로 통합되었습니다.
> **이 문서는 [[Component-Composition]] 의 중복본입니다.** Canonical 문서로 redirect.
---
*Redirected to: [[Component-Based_Architecture]]*
## 핵심 요약 (specialization aspects)
- Component-based architecture 매 UI 의 reusable + composable unit decomposition.
- 매 React / Vue / Svelte / Web Components 매 공통 mental model.
- 매 자세한 composition pattern 매 [[Component-Composition]] 참조.
## 🔗 Graph
- 부모: [[Component-Composition]] (canonical)
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — Component-Composition canonical 문서로 redirect |
+148 -64
View File
@@ -1,89 +1,173 @@
---
id: wiki-2026-0508-component-composition
title: Component Composition
title: Component Composition (React)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [FE-REACT-COMP-001]
aliases: [React Composition, Compound Components]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [react, Frontend, component-composition, reusability, Modularity, design-patterns, clean-code]
confidence_score: 0.9
verification_status: applied
tags: [react, composition, component-design, frontend]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React 19
---
# Component Composition (컴포넌트 합성)
# Component Composition (React)
## 📌 한 줄 통찰 (The Karpathy Summary)
> "상속(Inheritance)의 경직성 대신 합성(Composition)유연함을 선택하여, 작고 독립적인 컴포넌트들을 마치 레고 블록처럼 조합함으로써 거대하고 복잡한 시스템을 관리 가능한 수준으로 유지하라" — React 아키텍처의 핵심 설계 원칙 중 하나.
## 한 줄
> **"매 inheritance 의 X, composition O"**. React 의 design principle — UI 를 작은 composable component 로 분해, props.children + slot pattern + compound API 로 매 flexible 한 reuse 달성.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Containment and Specialization" — 자식 컴포넌트를 `props.children`으로 전달받아 렌더링하는 컨테인먼트 패턴과, 일반적인 컴포넌트를 구체적인 사례로 설정하는 특수화 패턴의 결합.
- **주요 구현 기법:**
- **Props.children:** 컴포넌트 내부의 구멍(Slot)을 열어두어 호출부에서 자유롭게 UI를 주입하게 함.
- **[[Render Props|Render Props]]:** 함수를 prop으로 전달하여 렌더링 로직을 외부에서 결정하게 함.
- **HOC (High-Order Components):** 컴포넌트를 인자로 받아 기능을 강화된 새 컴포넌트를 반환 (최근에는 Custom Hooks로 많이 대체됨).
- **의의:** 컴포넌트 간의 결합도를 낮추고(Decoupling), 비즈니스 로직과 UI 로직을 명확히 분리하여 코드의 재사용성과 테스트 용이성을 극대화함.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거 객체지향 기반 프레임워크는 클래스 상속을 권장했으나, React 정책은 '상속보다 합성(Composition over Inheritance)' 정책을 절대적 원칙으로 고수함.
- **정책 변화:** Antigravity 프로젝트는 모든 공용 UI 라이브러리 설계 시 '슬롯 기반 합성(Slot-based Composition)' 아키텍처를 강제하며, 3단계 이상의 깊은 [[Prop Drilling|Prop Drilling]]이 발생하는 경우 반드시 합성을 통해 구조를 재설계하도록 함.
### 매 핵심 idioms
- `props.children` (default slot).
- Named slots (props as render fn / ReactNode).
- Compound components (parent + children share context).
- Render props / function-as-children.
- Polymorphic `as` prop.
- `React.cloneElement` / `Slot` (Radix).
## 🔗 지식 연결 (Graph)
- React-[[Architecture|Architecture]], [[Custom-Hooks-Patterns|Custom-Hooks-Patterns]], Reusable-UI-Components, Scalable-React-Architecture
- **Raw Source:** 00_Raw/Component Composition.md
### 매 vs Inheritance
- React 매 class extension 의 X — 매 wrapper component.
- `<Parent>` + `<Parent.Item>` style 매 implicit relation expression.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Modal / Dialog (Header / Body / Footer slots).
2. Form fields (Field / Label / Input / Error).
3. Menu / Combobox (Radix-style headless).
4. Layout primitives (Stack, Grid).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Children as default slot
```tsx
function Card({ children }: { children: React.ReactNode }) {
return <div className="card">{children}</div>;
}
// <Card><h2>Hi</h2><p>Body</p></Card>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Named slots via props
```tsx
type Props = {
header?: React.ReactNode;
footer?: React.ReactNode;
children: React.ReactNode;
};
**선택 A를 써야 할 때:**
- *(TODO)*
function Page({ header, footer, children }: Props) {
return (
<>
{header && <header>{header}</header>}
<main>{children}</main>
{footer && <footer>{footer}</footer>}
</>
);
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Compound components with Context
```tsx
import { createContext, useContext, useState } from 'react';
**기본값:**
> *(TODO)*
const TabsCtx = createContext<{ active: string; set: (v: string) => void } | null>(null);
## ❌ 안티패턴 (Anti-Patterns)
function Tabs({ defaultValue, children }: { defaultValue: string; children: React.ReactNode }) {
const [active, set] = useState(defaultValue);
return <TabsCtx value={{ active, set }}>{children}</TabsCtx>;
}
function Tab({ value, children }: { value: string; children: React.ReactNode }) {
const { active, set } = useContext(TabsCtx)!;
return <button data-active={active === value} onClick={() => set(value)}>{children}</button>;
}
function Panel({ value, children }: { value: string; children: React.ReactNode }) {
const { active } = useContext(TabsCtx)!;
return active === value ? <div>{children}</div> : null;
}
Tabs.Tab = Tab;
Tabs.Panel = Panel;
export { Tabs };
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// Usage:
// <Tabs defaultValue="a"><Tabs.Tab value="a">A</Tabs.Tab><Tabs.Panel value="a">…</Tabs.Panel></Tabs>
```
### Render prop
```tsx
function Toggle({ children }: { children: (state: { on: boolean; toggle: () => void }) => React.ReactNode }) {
const [on, setOn] = useState(false);
return <>{children({ on, toggle: () => setOn((v) => !v) })}</>;
}
// <Toggle>{({ on, toggle }) => <button onClick={toggle}>{on ? 'on' : 'off'}</button>}</Toggle>
```
### Polymorphic `as` prop
```tsx
type AsProp<T extends React.ElementType> = { as?: T } & React.ComponentPropsWithoutRef<T>;
function Box<T extends React.ElementType = 'div'>({ as, ...rest }: AsProp<T>) {
const Tag = as ?? 'div';
return <Tag {...rest} />;
}
// <Box as="section" className="x">…</Box>
```
### Radix Slot pattern (asChild)
```tsx
import { Slot } from '@radix-ui/react-slot';
function Button({ asChild, ...props }: { asChild?: boolean } & React.ComponentProps<'button'>) {
const Comp = asChild ? Slot : 'button';
return <Comp className="btn" {...props} />;
}
// <Button asChild><a href="/x">link styled as button</a></Button>
```
### Layout primitives (Stack)
```tsx
function Stack({ gap = 8, children }: { gap?: number; children: React.ReactNode }) {
return <div style={{ display: 'flex', flexDirection: 'column', gap }}>{children}</div>;
}
```
## 매 결정 기준
| 상황 | Pattern |
|---|---|
| Single content area | `children` |
| Multiple structured slots | Named props or compound |
| Tightly-coupled siblings | Compound + context |
| Behavior + UI separation | Render props / hook |
| Style polymorphism | `as` prop or `Slot` |
**기본값**: 매 children prop 으로 시작 → 복잡해지면 compound + context.
## 🔗 Graph
- 부모: [[React]] · [[Component-Design]]
- 변형: [[Vue-Slots]] · [[Svelte-Snippets]] · [[Web-Components]]
- 응용: [[Radix-UI]] · [[Headless-UI]] · [[shadcn]]
- Adjacent: [[Hooks]] · [[Server-Components]] · [[Composition API]]
## 🤖 LLM 활용
**언제**: design system 구축, library API 설계, complex form/dialog UI.
**언제 X**: 매 trivial leaf component — over-engineering.
## ❌ 안티패턴
- **Prop explosion**: 매 20+ props → 매 compound 로 분해.
- **`cloneElement` everywhere**: 매 fragile, prefer context.
- **Deep prop drilling**: 매 context or compound 로 해결.
## 🧪 검증 / 중복
- Verified (react.dev / Radix UI patterns / Kent Dodds blog).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — React composition idioms + compound pattern |
+160 -105
View File
@@ -1,130 +1,185 @@
---
id: wiki-2026-0508-composables
title: Composables
title: Composables (Vue)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-REINFORCE-AUTO-889EC5]
aliases: [Vue Composables, useX functions]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced]
confidence_score: 0.9
verification_status: applied
tags: [vue, composition-api, composables, frontend]
raw_sources: []
last_reinforced: 2026-05-03
github_commit: "[P-Reinforce] Continuous Worker - Composables"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Vue 3
---
# [[Composables|Composables]]
# Composables (Vue)
## 📌 한 줄 통찰 (The Karpathy Summary)
Composables는 Vue 3 Composition API 환경에서 상태 저장 로직(stateful logic)을 캡슐화하여 재사용할 수 있도록 설계된 함수 패턴입니다. [1, 2] 기존 Vue의 Mixin이 가지던 이름 충돌과 암시적 데이터 흐름의 한계를 해결하며, 애플리케이션의 뷰 레이어와 비즈니스 로직을 분리하는 '기능적 코어(functional core)' 역할을 수행합니다. [3, 4] React의 커스텀 훅(Custom Hooks)과 유사하게 작동하지만, 호출 순서나 조건부 호출에 대한 제약이 적어 더욱 유연하게 활용될 수 있습니다. [5]
## 한 줄
> **"매 reactive logic 의 reusable function"**. Composable Vue 3 Composition API 의 stateful logic 을 추출한 `useX()` 함수 — React Hooks 와 유사하나 매 reactivity primitive (`ref`, `reactive`, `computed`) 기반이라 caller 매 free of dependency arrays.
## 📖 구조화된 지식 (Synthesized Content)
* **논리의 캡슐화와 단일 책임 원칙**: Composables는 특정 기능이나 단일 책임(single responsibility)에 초점을 맞춰 설계되어야 합니다. 데이터 페칭 로직을 예로 들면, 주요 상태(데이터)와 함께 로딩 상태, 에러 처리 등의 보조 상태, 그리고 이를 제어하는 메서드를 하나의 함수 내에 통합하여 관리합니다. [1, 6]
* **상속을 넘어선 합성(Composition over Inheritance)**: 과거 객체지향적 접근이나 Mixin을 통한 코드 공유는 속성 충돌과 출처가 불분명한 데이터 문제를 낳았습니다. Composables는 명시적으로 정의된 반응형 참조(refs)와 함수만을 반환하므로, 의존성 관계가 투명하고 안전한 타입스크립트 기반의 논리 공유가 가능합니다. [3, 4]
* **컴포넌트 설계와 결합**: 더 복잡한 기능을 만들기 위해 작은 Composable 여러 개를 중첩(nesting)하여 사용할 수 있습니다. [7] 이렇게 추출된 Composables를 사용하면, 복잡한 인증 흐름이나 폼 유효성 검사, 드래그 앤 드롭 등의 인터랙션 로직을 컴포넌트 밖으로 빼내어 UI 컴포넌트를 가볍게 유지할 수 있습니다. [4, 8]
* **팀 협업 및 테스트 용이성 극대화**: 각 Composable은 `useAuth`, `useCounter`와 같이 의도를 명확히 드러내는 명명 규칙을 따르는 것이 권장됩니다. [5, 9] 또한 UI DOM 요소 전체를 마운트할 필요 없이, 반응형 상태와 비즈니스 로직이 담긴 Composable 함수만 개별적으로 유닛 테스트할 수 있어 대규모 프로젝트에서 코드 오염을 방지하고 견고함을 유지할 수 있습니다. [4, 5, 10]
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **유연성으로 인한 코드 파편화 위험**: Composition API와 Composables가 제공하는 높은 유연성은 오히려 양날의 검이 될 수 있습니다. 로직을 어떻게 추출하고 명명할지에 대해 팀 내의 명확한 코딩 표준(naming conventions, 파일 구조 등)이 확립되지 않으면, 일관성 없는 코드가 양산되어 장기적인 유지보수가 어려워질 수 있습니다. [5, 9, 11]
* **가파른 학습 곡선**: 소규모 프로젝트나 Vue에 처음 입문하는 개발자에게는 직관적이고 선언적인 Options API에 비해, 상태와 반응성 객체를 직접 조립해야 하는 Composables 패턴이 상대적으로 가파른 학습 곡선을 요구합니다. [12-14]
* **반응성(Reactivity) 손실 주의**: 원시 값과 객체의 반응성을 다루는 방식(`ref` vs `reactive`)을 정확히 이해하지 못하고 구조 분해 할당(destructuring)을 오용할 경우, 컴포넌트와의 반응성 연결이 끊어지는 흔한 함정(pitfall)에 빠질 수 있습니다. [15]
### 매 정의
- `use*` prefix 매 convention.
- Returns reactive refs / computed / methods.
- Side-effects via `onMounted` / `onScopeDispose` (`watchEffect` cleanup).
- `effectScope` 매 manual lifecycle (e.g., outside components).
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 vs React Hooks
| Aspect | Vue Composable | React Hook |
|---|---|---|
| Re-run | 매 once on setup | every render |
| Deps | reactive auto-track | manual array |
| Cleanup | `onScopeDispose` | return fn |
| Conditional call | 허용 (with caveats) | 금지 |
#### [아키텍처/기반 기술]
- [[Composition API]]
- 연결 이유: Composables를 구현하고 실행하기 위한 Vue 3의 핵심 API입니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 논리를 컴포넌트 옵션(data, methods 등)이 아닌 기능별로 묶어내는 메커니즘과 반응성 기초를 이해할 수 있습니다. [16, 17]
- [[Custom Hooks]]
- 연결 이유: React 진영에서 상태 기반 로직을 추출하기 위해 사용하는, Composables와 직접적으로 대응되는 설계 패턴입니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 함수 합성을 통한 로직 재사용 패러다임을 이해하고, 두 프레임워크 간의 호출 제약(Hook의 규칙 등) 차이를 심층적으로 비교할 수 있습니다. [5, 18]
### 매 응용
1. `useFetch` / `useAsyncData` — async + cancellation.
2. `useElementSize`, `useEventListener` — DOM bindings (VueUse).
3. `useStore`, `useFeatureFlag` — cross-cutting state.
#### [구현/활용 도구]
- [[Mixins]]
- 연결 이유: Vue 2에서 널리 쓰이던 로직 재사용 패턴이자, Composables가 극복하고자 한 핵심 대상입니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이름 충돌(Naming collision)과 암시적 데이터 출처 문제 등 구형 패턴의 한계를 인지함으로써 Composables 도입의 당위성을 체감할 수 있습니다. [3, 4]
- [[Smart vs Dumb Components]]
- 연결 이유: 프레임워크 전반의 UI 설계 패턴으로, Composables와 시너지를 내는 컴포넌트 구조화 전략입니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 데이터 페칭 및 상태 관리(Smart)를 Composables로 분리하여, 오직 렌더링에만 집중하는 재사용 가능한 프리젠테이셔널 컴포넌트(Dumb)를 효과적으로 구성하는 방법을 익힐 수 있습니다. [19]
## 💻 패턴
### Deeper Research Questions
- Vue 3의 Composables는 React의 Custom Hooks와 비교하여, 라이프사이클 처리 및 반응성 추적(Dependency Tracking) 메커니즘에서 어떠한 근본적 차이와 이점을 가지는가?
- 대규모 애플리케이션에서 다수의 Composables와 중앙 집중식 전역 상태 관리 라이브러리(Pinia 등)를 아키텍처 수준에서 어떻게 명확히 구분하고 조화롭게 설계할 수 있는가?
- 서버 사이드 렌더링(SSR) 환경에서 Composables를 설계할 때, 교차 요청 상태 오염(Cross-Request State Pollution) 현상을 방지하기 위한 메모리 및 상태 관리 지침은 무엇인가?
- 여러 개의 Composables를 깊게 중첩(Nesting)하여 사용할 때 발생하는 테스트 복잡성이나 성능 한계를 완화하기 위한 모범 패턴은 무엇인가?
- Composables가 내부적으로 생성하는 부수 효과(Side effects)를 안전하게 해제하기 위해 Vue 3.5에서 도입된 `onWatcherCleanup`과 같은 API를 실무에 어떻게 적용할 것인가?
### Basic counter composable
```ts
import { ref, computed } from 'vue';
### Practical Application Contexts
- **Implementation:** 드래그 앤 드롭 기능, 다단계 워크플로우 진행 상태 추적, API 데이터 페칭(로딩, 에러, 응답 상태 통합)과 같이 복잡한 UI 상호작용 및 상태 변화 로직을 개별 함수로 캡슐화하여 구현할 때 사용합니다. [7, 8]
- **System Design:** 애플리케이션의 로직이 여러 컴포넌트에 분산되는 것을 막고, '기능적 코어' 역할을 하는 독립된 모듈 단위로 시스템을 설계함으로써 마이크로 프론트엔드나 모노레포 아키텍처 확장에 대응합니다. [4, 20]
- **Operation / Maintenance:** 비즈니스 규칙이 변경되거나 버그 패치가 필요할 때, 여러 컴포넌트를 탐색할 필요 없이 해당 로직을 담당하는 단일 Composable만 수정하여 즉각적인 전역 업데이트 효과를 얻습니다. [5, 21]
- **Learning Path:** Vue의 기본 Reactivity(`ref`, `reactive`, `computed` 등)를 이해한 후, 코드의 모듈화를 위해 학습해야 하는 핵심 패턴이며, 이후 대규모 상태 관리(Pinia)로 넘어가기 위한 징검다리 역할을 합니다. [2, 22]
- **My Project Relevance:** 프론트엔드 코드베이스가 커짐에 따라 발생하는 중복 코드를 제거하고, UI 표현 계층과 비즈니스 로직 계층의 결합도를 낮춰 팀 단위 협업 시 충돌 없이 안전하게 개발하기 위해 즉각적으로 도입해야 할 패턴입니다. [23, 24]
### Adjacent Topics
- [[Pinia]]
- 확장 방향: Composables를 통해 개별 상태 로직을 캡슐화하는 것을 넘어, 애플리케이션 전체에서 공유되어야 하는 글로벌 상태를 타입 안전하고 일관된 방식으로 관리하는 아키텍처로 지식을 확장할 수 있습니다. [25, 26]
- [[TypeScript Generics]]
- 확장 방향: 재사용성을 더욱 고도화하기 위해, Composables가 다루는 데이터의 타입을 동적으로 추론하고 보호할 수 있도록 제네릭을 접목하는 고급 타입 설계 기법을 연구할 수 있습니다. [27-29]
---
*Last updated: 2026-05-03*
---
*Last updated: 2026-05-03*
- Raw Source: 00_Raw/2026-05-03/Composables.md
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export function useCounter(initial = 0) {
const count = ref(initial);
const isZero = computed(() => count.value === 0);
const inc = () => count.value++;
const dec = () => count.value--;
return { count, isZero, inc, dec };
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### useFetch with abort + reactive URL
```ts
import { ref, watchEffect, onScopeDispose, type MaybeRefOrGetter, toValue } from 'vue';
**선택 A를 써야 할 때:**
- *(TODO)*
export function useFetch<T>(url: MaybeRefOrGetter<string>) {
const data = ref<T | null>(null);
const error = ref<Error | null>(null);
const loading = ref(false);
let ctrl: AbortController | null = null;
**선택 B를 써야 할 때:**
- *(TODO)*
watchEffect(async () => {
ctrl?.abort();
ctrl = new AbortController();
loading.value = true;
try {
const r = await fetch(toValue(url), { signal: ctrl.signal });
data.value = await r.json();
} catch (e) {
if ((e as Error).name !== 'AbortError') error.value = e as Error;
} finally {
loading.value = false;
}
});
**기본값:**
> *(TODO)*
onScopeDispose(() => ctrl?.abort());
return { data, error, loading };
}
```
## ❌ 안티패턴 (Anti-Patterns)
### useEventListener (auto cleanup)
```ts
import { onMounted, onScopeDispose, type Ref } from 'vue';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export function useEventListener<K extends keyof WindowEventMap>(
target: Window | Ref<HTMLElement | null>,
event: K,
handler: (e: WindowEventMap[K]) => void,
) {
onMounted(() => {
const el = 'value' in target ? target.value : target;
el?.addEventListener(event, handler as EventListener);
});
onScopeDispose(() => {
const el = 'value' in target ? target.value : target;
el?.removeEventListener(event, handler as EventListener);
});
}
```
### useLocalStorage (sync ref ↔ storage)
```ts
import { ref, watch } from 'vue';
export function useLocalStorage<T>(key: string, initial: T) {
const stored = localStorage.getItem(key);
const value = ref<T>(stored ? JSON.parse(stored) : initial);
watch(value, (v) => localStorage.setItem(key, JSON.stringify(v)), { deep: true });
return value;
}
```
### useDebouncedRef
```ts
import { customRef } from 'vue';
export function useDebouncedRef<T>(value: T, delay = 300) {
let t: ReturnType<typeof setTimeout>;
return customRef<T>((track, trigger) => ({
get() { track(); return value; },
set(v) {
clearTimeout(t);
t = setTimeout(() => { value = v; trigger(); }, delay);
},
}));
}
```
### Detached scope (composable outside component)
```ts
import { effectScope } from 'vue';
const scope = effectScope();
scope.run(() => {
const counter = useCounter();
// ... use anywhere
});
// later
scope.stop();
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Component-local state | `ref` directly |
| Logic reused in 2+ components | Composable |
| Global state (auth, theme) | Pinia store (composable underneath) |
| DOM API integration | VueUse composable or custom |
**기본값**: 매 reusable reactive logic → composable. Single-use → inline.
## 🔗 Graph
- 부모: [[Composition API]] · [[Vue 3]]
- 변형: [[React-Hooks]] · [[Solid-Primitives]]
- 응용: [[VueUse]] · [[Pinia]] · [[Nuxt-Composables]]
- Adjacent: [[Reactivity]] · [[Component-Composition]]
## 🤖 LLM 활용
**언제**: stateful logic 매 2+ components 에서 사용 / DOM·async 의 lifecycle wrapping.
**언제 X**: 매 pure function (no reactivity) — 매 plain util 로 충분.
## ❌ 안티패턴
- **Returning reactive() with destructure**: loses reactivity → use `toRefs`.
- **Global side-effects in composable body**: 매 `onMounted` 안에 넣을 것.
- **Naming without `use` prefix**: 매 convention break, lint rule 매 fail.
## 🧪 검증 / 중복
- Verified (Vue.js docs / VueUse source).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Vue 3 composables with patterns |
+160 -107
View File
@@ -1,133 +1,186 @@
---
id: wiki-2026-0508-composition-api
title: Composition API
title: Composition API (Vue 3)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-REINFORCE-AUTO-69B9E0]
aliases: [Vue Composition API, setup script]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced]
confidence_score: 0.9
verification_status: applied
tags: [vue, composition-api, reactivity, frontend]
raw_sources: []
last_reinforced: 2026-05-03
github_commit: "[P-Reinforce] Continuous Worker - Composition API"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Vue 3
---
# [[Composition API|Composition API]]
# Composition API (Vue 3)
## 📌 한 줄 통찰 (The Karpathy Summary)
Vue 3 Composition API는 컴포넌트의 옵션(`data`, `methods`, `computed` 등)이 아닌 '논리적 관심사(Logical concerns)'를 기준으로 코드를 구성하고 조직할 수 있게 해주는 강력한 기능이다 [1]. 반응형 원시 타입(`ref`, `reactive`)과 함수를 활용하여 상태와 로직을 캡슐화하고 재사용 가능한 형태로 만든다 [1]. 기존의 Options API에 비해 대규모 프로젝트에서의 확장성, 코드 재사용성, 그리고 TypeScript와의 뛰어난 호환성을 제공하여 유지보수성을 극대화한다 [2-4].
## 한 줄
> **"매 reactive primitive 으로 logic 을 조합한다"**. Composition API Vue 3 의 `setup()` / `<script setup>` 기반 model — `ref`, `reactive`, `computed`, `watch` 를 직접 import 하여 매 logic 조각을 자유 조합, 매 Options API 의 `data/methods/computed` partition 을 대체.
## 📖 구조화된 지식 (Synthesized Content)
* **반응형 상태 관리 (Reactive State Management)**: `ref()``reactive()` 함수를 통해 반응형 상태를 선언한다. `ref()`는 원시 값과 객체를 모두 지원하며 `.value` 속성을 통해 접근하고, `reactive()`는 주로 복잡한 객체나 배열을 다루기 위해 설계되었다 [5, 6]. 내재된 한계로 인해 유연성을 갖춘 `ref()`를 반응형 상태 선언의 주요 API로 사용하는 것이 종종 권장된다 [6].
* **컴포저블 (Composables)**: 재사용 가능한 상태 기반 로직을 캡슐화한 함수로, Composition API 재사용성의 초석이다 [7, 8]. 과거 Vue 2의 Mixins 패턴이 초래하던 네이밍 충돌이나 데이터 출처가 불분명해지는 문제를 '상속 대신 합성(Composition over Inheritance)'이라는 접근법을 통해 투명하고 타입 안전하게 해결한다 [9].
* **논리적 관심사 그룹화**: 기존 Options API에서는 단일 기능에 대한 로직이 `data`, `methods`, `computed` 곳곳에 흩어져 있었으나, Composition API를 사용하면 관련된 모든 로직을 한 곳에 밀집시킬 수 있어 가독성과 추적성이 향상된다 [10, 11].
* **`<script setup>` 문법의 결합**: 현대 Vue 3 개발에서는 `<script setup>` 문법을 일관되게 사용하여 보일러플레이트를 줄인다 [12]. 이 구문 내에서 선언된 변수와 함수는 템플릿에 자동으로 노출되며, 코드를 더 간결하게 만들고 IDE의 지원을 극대화한다 [13].
* **Provide / Inject를 통한 컨텍스트 공유**: 엔터프라이즈 환경에서 데이터가 불필요한 중간 컴포넌트 계층을 거치는 'Prop Drilling' 문제를 방지한다 [14]. 전역 로거, API 클라이언트 주입이나 테마 및 다국어 지원 등 '컨텍스트 인식(Context-aware)' 컴포넌트 트리를 구성하는 데 활용된다 [14, 15].
* **강력한 TypeScript 호환성**: Composition API는 TypeScript와 매끄럽게 통합되어 뛰어난 타입 추론을 제공한다 [2, 11]. 이는 런타임 에러를 사전에 방지하고 버그를 최소화하며 개발 속도를 높이는 결정적 요인으로 작용한다 [3, 4].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **가파른 학습 곡선 (Steeper Learning Curve)**: 단순하고 선언적인 구조를 가진 Options API에 비해 Composition API는 상대적으로 학습 곡선이 가파르다 [16, 17].
* **반응성(Reactivity) 상실의 위험**: `reactive`를 원시 값에 잘못 사용하거나, 반응형 객체를 직접 구조 분해 할당(Destructuring)할 경우 반응성 연결이 끊어지는 흔한 실수가 발생할 수 있다. 이를 유지하려면 속성에 직접 접근하거나 `toRefs()` 유틸리티를 사용해야 한다 [18]. 또한 JavaScript 내부에서 `ref` 변수에 접근할 때 `.value`를 누락하는 실수에 유의해야 한다 [18].
* **라이프사이클 및 비동기 로직의 위치 제약**: 데이터 페칭 및 이벤트 리스너 설정 로직은 `setup` 함수 내부의 적절한 라이프사이클 훅 안에서 호출되어야 한다. 이 규칙을 벗어날 경우 메모리 누수(Memory leaks)나 예기치 않은 동작이 발생할 수 있다 [19].
* **단순 컴포넌트에서의 오버엔지니어링**: 재사용성이 낮고 기능이 단순한 단일 기능 컴포넌트에서는 Composition API를 도입하는 것이 불필요하게 복잡할 수 있으며, 이 경우 Options API를 사용하는 것이 더 직관적일 수 있다 [16, 20].
### 매 핵심 primitives
- `ref(v)`: 매 wraps any value, `.value` access.
- `reactive(obj)`: deep proxy — object/array 만.
- `computed(fn)`: derived ref, lazy + cached.
- `watch(src, cb)`: explicit deps + cb.
- `watchEffect(fn)`: auto-track, eager.
- `effectScope()`: manual lifecycle group.
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 vs Options API
| Aspect | Options | Composition |
|---|---|---|
| Logic reuse | mixins (collision-prone) | composables (clean) |
| TypeScript | OK | excellent |
| File length scaling | grows by category | grows by feature |
| Learning curve | gentle | steeper but worth it |
#### [관계 유형 A: 아키텍처/기반 기술]
* [[Options API]]
* 연결 이유: Composition API 이전의 기본 컴포넌트 작성 방식이자 대조되는 개념이다 [1].
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 프로젝트의 크기(단순함 vs 복잡성)에 따라 어떤 API 설계가 더 적합한지 트레이드오프를 명확히 비교 평가할 수 있다 [16, 20].
* [[Composables]]
* 연결 이유: Composition API의 유연성을 실질적인 재사용 단위로 구현하는 핵심 패턴이다 [7, 8].
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: Mixins을 대체하며 복잡한 상태 로직을 어떻게 투명하고 안전하게 모듈화하여 캡슐화할 수 있는지 설계 원리를 이해할 수 있다 [8, 9].
* [[Reactivity System (ref, reactive)]]
* 연결 이유: Composition API의 근간이 되는 반응형 원시 타입 메커니즘이다 [21].
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: Vue가 데이터 변경을 어떻게 추적하고 파생 상태(`computed`)나 부수 효과(`watch`)를 처리하는지 내부 렌더링 원리를 이해할 수 있다 [5, 21].
### 매 `<script setup>` perks
- Top-level await.
- Auto-expose for template.
- `defineProps`, `defineEmits`, `defineModel`, `defineExpose` macros.
- Compile-time optimizations (no `setup()` boilerplate).
#### [관계 유형 B: 구현/활용 도구]
* [[Pinia]]
* 연결 이유: Vuex를 대체하며 Composition API 스타일을 완벽하게 지원하는 Vue 3의 공식 상태 관리 라이브러리이다 [22-24].
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 로컬 상태 관리(Composables)를 넘어 전역 상태 관리를 어떻게 타입 안전하게 구축하고 관리하는지 확장할 수 있다 [23, 25, 26].
* [[TypeScript]]
* 연결 이유: Composition API가 제공하는 구조적 이점을 극대화하는 강력한 정적 타입 시스템이다 [2, 27].
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: Props/Emits의 엄격한 계약(Contract) 정의를 통해 대규모 협업에서 어떻게 런타임 에러를 방지하고 IDE 지원을 향상시키는지 배울 수 있다 [27, 28].
## 💻 패턴
### Deeper Research Questions
* Options API와 Composition API의 아키텍처적 차이는 무엇이며, 프로젝트의 규모, 팀의 경험, 컴포넌트 재사용성에 따라 이 둘을 어떻게 선택하거나 혼용해야 하는가?
* `ref()``reactive()`의 내부적인 반응성 추적(Reactivity Tracking) 메커니즘 차이는 무엇이며, 구조 분해 할당 시 발생하는 반응성 상실(Reactivity Loss)은 왜 일어나는가?
* 기존 Vue 2의 Mixins 패턴이 대규모 프로젝트에서 야기했던 네이밍 충돌과 암묵적 의존성 문제를 Composables 패턴은 어떤 구조적 원리로 해결하는가?
* 대규모 엔터프라이즈 환경에서 Composition API와 `<script setup>` 문법을 결합하여 사용할 때, 메모리 누수를 방지하고 번들 사이즈를 최적화하기 위한 모범 코딩 표준은 무엇인가?
* 로컬 상태를 관리하는 Composables와 애플리케이션 전역 상태를 관리하는 Pinia 스토어 사이의 경계와 역할은 어떻게 설계해야 하는가?
### Basic setup with ref + computed
```vue
<script setup lang="ts">
import { ref, computed } from 'vue';
### Practical Application Contexts
* **Implementation:** `<script setup>` 블록을 활용하여 관련 있는 상태(`ref`), 계산된 속성(`computed`), 사이드 이펙트(`watch`)를 묶어서 응집력 있게 구현하며, 템플릿에 불필요한 래핑 없이 데이터를 바인딩한다.
* **System Design:** 대규모 애플리케이션에서 '스마트(Container) 컴포넌트'와 '덤(Presentational) 컴포넌트' 패턴을 나눌 때, 복잡한 데이터 페칭 및 비즈니스 로직을 Composable 함수로 분리하여 스마트 컴포넌트에 주입하는 아키텍처를 설계한다.
* **Operation / Maintenance:** 기능 단위로 코드가 묶여 있어 리팩토링 시 추적과 분리가 용이해지며(최대 30%의 리팩토링 시간 단축), 강력한 TypeScript 추론을 통해 다수 개발자가 협업하는 런타임 환경에서 코드의 무결성과 유지보수성을 크게 높일 수 있다.
* **Learning Path:** `ref``reactive`의 동작 원리를 이해하는 것을 시작으로, 기본적인 컴포넌트 내부 로직을 작성해 본 후 자주 사용되는 로직을 Composable 함수로 추출하고, 마지막으로 Pinia를 활용한 전역 상태 패턴을 학습하는 순서로 접근한다.
* **My Project Relevance:** 프레임워크별 실전 아키텍처 패턴을 분석하는 데 있어, UI와 비즈니스 로직을 모듈화하고 프론트엔드의 상태 관리를 확장성 있게 가져가기 위한 핵심적인 구조적 전략으로 평가될 수 있다.
const count = ref(0);
const double = computed(() => count.value * 2);
const inc = () => count.value++;
</script>
### Adjacent Topics
* [[React Hooks]]
* 확장 방향: Composition API의 철학적 영감이 된 React의 패턴으로, 양대 프레임워크가 상태 기반 로직의 재사용성이라는 과제를 어떻게 다르게 해석하고 해결했는지 패러다임 비교 학습을 진행할 수 있다.
* [[Micro-frontends]]
* 확장 방향: 대규모 애플리케이션을 여러 독립적인 모듈로 분할하는 엔터프라이즈 아키텍처로, Composition API로 철저히 캡슐화된 컴포넌트들이 분산 환경에서 어떻게 일관성을 유지하는지 탐구할 수 있다.
---
*Last updated: 2026-05-03*
- Raw Source: 00_Raw/2026-05-03/Composition API.md
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
<template>
<button @click="inc">{{ count }} (×2 = {{ double }})</button>
</template>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Typed props + emits + v-model
```vue
<script setup lang="ts">
const props = defineProps<{ initial?: number }>();
const emit = defineEmits<{ change: [value: number] }>();
const model = defineModel<string>({ default: '' });
</script>
**선택 A를 써야 할 때:**
- *(TODO)*
<template>
<input v-model="model" />
</template>
```
**선택 B를 써야 할 때:**
- *(TODO)*
### reactive with toRefs (avoid losing reactivity)
```ts
import { reactive, toRefs } from 'vue';
**기본값:**
> *(TODO)*
export function useUser() {
const state = reactive({ name: 'Ada', age: 36 });
return { ...toRefs(state) }; // 매 destructurable + reactive
}
```
## ❌ 안티패턴 (Anti-Patterns)
### watch with explicit source
```ts
import { ref, watch } from 'vue';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
const query = ref('');
watch(query, async (q, _old, onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort());
const r = await fetch(`/search?q=${q}`, { signal: ctrl.signal });
// ...
});
```
### watchEffect (auto-track)
```ts
import { ref, watchEffect } from 'vue';
const userId = ref(1);
watchEffect(async () => {
const r = await fetch(`/api/users/${userId.value}`);
user.value = await r.json();
});
```
### Provide / inject (typed)
```ts
// keys.ts
import type { InjectionKey, Ref } from 'vue';
export const ThemeKey: InjectionKey<Ref<'light' | 'dark'>> = Symbol('theme');
// Parent
import { provide, ref } from 'vue';
const theme = ref<'light' | 'dark'>('dark');
provide(ThemeKey, theme);
// Child
import { inject } from 'vue';
const theme = inject(ThemeKey)!;
```
### Async setup with Suspense
```vue
<!-- Parent -->
<Suspense>
<UserProfile :id="42" />
<template #fallback><Skeleton /></template>
</Suspense>
<!-- UserProfile.vue -->
<script setup lang="ts">
const props = defineProps<{ id: number }>();
const user = await (await fetch(`/users/${props.id}`)).json();
</script>
```
### Lifecycle hooks
```ts
import { onMounted, onUnmounted } from 'vue';
onMounted(() => console.log('mounted'));
onUnmounted(() => console.log('cleanup'));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New Vue 3 project | Composition + `<script setup>` |
| Migrating from Vue 2 | Options 유지 → 점진 conversion |
| Logic reuse needed | Composable function |
| Simple 1-off component | Either OK, prefer setup for TS |
**기본값**: `<script setup>` + Composition API. Options API 는 legacy maintenance only.
## 🔗 Graph
- 부모: [[Vue 3]] · [[Reactivity]]
- 변형: [[Options-API]] · [[React-Hooks]] · [[Solid-Signals]]
- 응용: [[Composables]] · [[Pinia]] · [[Nuxt]]
- Adjacent: [[Component-Composition]] · [[TypeScript]]
## 🤖 LLM 활용
**언제**: Vue 3 component 작성, composable 추출, TS 강한 typing 필요.
**언제 X**: Vue 2.7 이전 — 매 backport limited.
## ❌ 안티패턴
- **Mixing reactive() destructure without toRefs**: loses reactivity silently.
- **Using `ref.value` in template**: 매 unwrap 자동, `.value` 의 X.
- **Excessive `watch`**: 매 computed 로 충분한 경우 매 prefer computed.
## 🧪 검증 / 중복
- Verified (vuejs.org official guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Composition API primitives + setup patterns |
+23 -15
View File
@@ -1,25 +1,33 @@
---
id: wiki-20260508-compound-components-redir
id: wiki-2026-0508-compound-components-redir
title: Compound Components
category: Frontend
status: merged
redirect_to: Compound_Components
canonical_id: Compound_Components
category: 10_Wiki/Topics
status: duplicate
canonical_id: compound-components
duplicate_of: "[[Component-Composition]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [redirect]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, react, patterns]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-merge 2026-05-08)
---
# Compound Components
> [!IMPORTANT]
> 이 문서는 P-Reinforce Phase 2 자동 MERGE에 의해 **[[Compound_Components]]**로 통합되었습니다.
> **이 문서는 [[Component-Composition]] 의 중복본입니다.** Canonical 문서로 redirect.
---
*Redirected to: [[Compound_Components]]*
## 핵심 요약
-`<Tabs><Tab/></Tabs>` 의 implicit shared state via Context.
- 매 Radix UI / Headless UI 의 dominant pattern.
- 매 props drilling 의 회피 + flexible composition.
## 🔗 Graph
- 부모: [[Component-Composition]] (canonical)
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+164 -64
View File
@@ -1,90 +1,190 @@
---
id: wiki-2026-0508-computational-geometry
title: Computational Geometry
title: Computational Geometry (Frontend)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AI-053]
aliases: [2D Geometry, Geometric Algorithms]
duplicate_of: none
source_trust_level: A
confidence_score: 0.97
tags: [geometry, computational geometry, 3d, rendering]
confidence_score: 0.9
verification_status: applied
tags: [geometry, algorithms, canvas, frontend, math]
raw_sources: []
last_reinforced: 2026-06-XX
github_commit: "[P-Reinforce] Processed Computational Geometry."
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Canvas / SVG / WebGL
---
# [[Computational Geometry|Computational Geometry]] (계산 기하학)
# Computational Geometry (Frontend)
## 📌 한 줄 통찰 (The Karpathy Summary)
> 수학적 알고리즘을 사용하여 컴퓨터가 점, 곡선, 다각형 같은 기하학적 객체들 사이의 관계와 공간 구조를 효율적으로 분석하고 조작하는 기술 분야이다.
## 한 줄
> **"매 pixel 의 math 가 geometry 다"**. Hit-testing, polygon clipping, convex hull, spatial index — 매 canvas/SVG/Figma-style editor 의 core, 매 numerical robustness + spatial accel structure 가 핵심.
## 📖 구조화된 지식 (Synthesized Content)
- **정의:** 수학과 컴퓨터 과학이 만나는 영역으로, 현실 세계의 형태(건축물, 인체 모델, 게임 오브젝트 등)를 디지털로 표현하고 이를 바탕으로 물리적/시각적 시뮬레이션을 수행하는 기반 기술이다.
- **핵심 알고리즘 및 구조:**
1. **메쉬 데이터 구조:** 3D 객체를 삼각형(Tri[[ANGLE|ANGLE]])의 집합으로 근사화하여 저장하고 처리한다. (Vertices, Edges, Faces).
2. **공간 분할 기법:** 대규모 데이터를 효율적으로 검색하기 위해 공간을 나누는 방법들 (예: Octree, BVH - Bounding Volume Hierarchy). 이는 렌더링의 성능(Culling)에 필수적이다.
3. **좌표 변환 및 근사화:** 카메라 위치나 오브젝트 이동에 따른 좌표계 변환(Transformation Matrix), 그리고 복잡한 곡선을 단순화하는 과정이 포함된다.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 기하학적 모델링은 단순히 형태를 만드는 것을 넘어, 물리 엔진과의 결합을 통해 '물리 법칙'을 시뮬레이션하고 그 결과를 예측하는 데 사용된다.
- **정책 변화:** 최신 트렌드는 하드웨어 가속(GPU)과 연동하여 복잡한 기하학적 계산(예: Ray Tracing)을 실시간으로 처리하는 방향으로 진화하고 있다.
### 매 fundamental ops
- Point-in-polygon (ray casting / winding number).
- Line-line / segment-segment intersection.
- Polygon-polygon clipping (Sutherland-Hodgman, Weiler-Atherton).
- Convex hull (Graham scan, Andrew's monotone chain).
- Bounding box / sphere.
- Distance: point-segment, point-polygon.
## 🔗 지식 연결 (Graph)
- Parent: [[Computational Geometry|Computational Geometry]]
- Related: Bounding Volume Hierarchy (BVH) , [[Three.js 렌더링 최적화|Three.js 렌더링 최적화]] , [[Physics|Physics]]-Based-Simulation
### 매 spatial accel
- Quadtree — 2D static/dynamic.
- R-tree — bbox-based, dynamic insert/delete (rbush lib).
- Spatial hash — uniform grid.
- BVH — for raycasting in 2D/3D.
---
### 매 numerical pitfalls
- Floating-point cross product near zero → epsilon checks.
- Robust orientation predicates (Shewchuk).
- 매 SVG path parsing → degenerate cubic 처리.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Figma-style hit-testing.
2. Map polygon labeling / clipping.
3. Drag-select rectangle vs many shapes.
4. Snap-to-grid / snap-to-edge.
5. Boolean ops on shapes (union/intersect/difference).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Point-in-polygon (ray casting)
```ts
type Pt = { x: number; y: number };
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export function pointInPolygon(p: Pt, poly: Pt[]): boolean {
let inside = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const a = poly[i], b = poly[j];
const intersect =
(a.y > p.y) !== (b.y > p.y) &&
p.x < ((b.x - a.x) * (p.y - a.y)) / (b.y - a.y) + a.x;
if (intersect) inside = !inside;
}
return inside;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Segment-segment intersection
```ts
export function segIntersect(p1: Pt, p2: Pt, p3: Pt, p4: Pt): Pt | null {
const d = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x);
if (Math.abs(d) < 1e-10) return null; // parallel
const t = ((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / d;
const u = ((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) / d;
if (t < 0 || t > 1 || u < 0 || u > 1) return null;
return { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) };
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Convex hull (Andrew's monotone chain)
```ts
export function convexHull(pts: Pt[]): Pt[] {
const p = [...pts].sort((a, b) => a.x - b.x || a.y - b.y);
const cross = (o: Pt, a: Pt, b: Pt) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
const lower: Pt[] = [];
for (const pt of p) {
while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], pt) <= 0) lower.pop();
lower.push(pt);
}
const upper: Pt[] = [];
for (let i = p.length - 1; i >= 0; i--) {
const pt = p[i];
while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], pt) <= 0) upper.pop();
upper.push(pt);
}
upper.pop(); lower.pop();
return lower.concat(upper);
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Bounding box
```ts
export function bbox(pts: Pt[]): { min: Pt; max: Pt } {
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
for (const { x, y } of pts) {
if (x < minX) minX = x; if (y < minY) minY = y;
if (x > maxX) maxX = x; if (y > maxY) maxY = y;
}
return { min: { x: minX, y: minY }, max: { x: maxX, y: maxY } };
}
```
**기본값:**
> *(TODO)*
### R-tree spatial index (rbush)
```ts
import RBush from 'rbush';
## ❌ 안티패턴 (Anti-Patterns)
type Item = { minX: number; minY: number; maxX: number; maxY: number; id: string };
const tree = new RBush<Item>();
tree.load(items);
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
const hits = tree.search({ minX: 0, minY: 0, maxX: 100, maxY: 100 });
```
### Point-segment distance
```ts
export function distPtSeg(p: Pt, a: Pt, b: Pt): number {
const dx = b.x - a.x, dy = b.y - a.y;
const lenSq = dx * dx + dy * dy;
if (lenSq === 0) return Math.hypot(p.x - a.x, p.y - a.y);
let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / lenSq;
t = Math.max(0, Math.min(1, t));
return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
}
```
### Polygon clipping (using martinez-polygon-clipping)
```ts
import * as martinez from 'martinez-polygon-clipping';
const subject = [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]];
const clip = [[[5, 5], [15, 5], [15, 15], [5, 15], [5, 5]]];
const intersection = martinez.intersection(subject, clip);
```
### Snap-to-grid
```ts
export const snap = (v: number, grid: number) => Math.round(v / grid) * grid;
export const snapPt = (p: Pt, g: number): Pt => ({ x: snap(p.x, g), y: snap(p.y, g) });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 1k+ shape hit-test | R-tree (rbush) |
| Static map polygons | Quadtree pre-built |
| Boolean ops on polygons | martinez-polygon-clipping |
| Hull / triangulation | d3-delaunay, earcut |
| Robust numerics | Shewchuk predicates |
**기본값**: bbox pre-filter → exact test. Spatial index 매 N>500.
## 🔗 Graph
- 부모: [[Algorithms]] · [[Graphics]]
- 변형: [[Computer-Graphics]] · [[GIS]]
- 응용: [[Canvas-API]] · [[SVG]] · [[WebGL]] · [[Map-Rendering]]
- Adjacent: [[Spatial-Indexing]] · [[Collision-Detection]]
## 🤖 LLM 활용
**언제**: canvas editor, map UI, drag-select, snapping, boolean ops on shapes.
**언제 X**: 매 trivial fixed UI — 매 CSS layout 으로 충분.
## ❌ 안티패턴
- **Naive O(N) hit-test on 10k shapes**: 매 lag — spatial index 필수.
- **No epsilon in cross product**: 매 collinear 매 wrong branch.
- **Re-building spatial tree per frame**: 매 only on data change, drag 매 incremental update.
## 🧪 검증 / 중복
- Verified (CGAL docs / "Computational Geometry: Algorithms and Applications" — de Berg et al.).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 2D geometry algorithms + spatial index patterns |
@@ -1,28 +1,162 @@
---
category: Frontend
tags: [auto-wikified, technical-documentation, frontend]
id: wiki-2026-0508-computed-properties-watchers
title: Computed Properties & Watchers
description: "Computed Properties와 Watchers는 Vue 3 Composition API에서 파생된 상태를 관리하고 데이터 변경에 대응하기 위한 필수적인 도구입니다 [1]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Vue computed, Vue watch, reactive-derivations]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [vue, reactivity, composition-api, computed, watch]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: vue3
---
# Computed Properties & Watchers
## 📌 Brief Summary
Computed Properties와 Watchers는 Vue 3 Composition API에서 파생된 상태를 관리하고 데이터 변경에 대응하기 위한 필수적인 도구입니다 [1]. Computed Properties는 반응형 데이터에 기반해 값을 계산하고 캐시(cache)하는 반면, Watchers는 데이터 변경 시 특정 액션이나 비동기 작업 등의 부수 효과(side effects)를 처리하는 데 사용됩니다 [1, 2].
## 매 한 줄
> **"매 derived state 의 declarative cache (`computed`), 매 side-effect 의 explicit subscription (`watch`)"**. 매 Vue 3.5 (2024) reactive system 의 두 축. 매 computed 는 pull-based memoization, watch 는 push-based callback.
## 📖 Core Content
* **Computed Properties (계산된 속성)**
* 반응형 데이터(reactive data)로부터 파생된 값을 생성하는 데 최적화되어 있습니다 [1].
* 결과값을 자동으로 캐시하며, 의존하고 있는 데이터가 변경될 때만 다시 계산을 수행하므로 데이터 필터링이나 총계 계산과 같은 작업에 이상적입니다 [1].
* `computed()`를 사용하여 생성된 반응형 상태는 여러 컴포넌트 인스턴스 간에 공유하여 사용할 수도 있습니다 [3].
## 매 핵심
* **Watchers (감시자)**
* 반응형 데이터의 변경이 발생했을 때 API 호출과 같은 특정 액션을 트리거하기 위해 사용됩니다 [2].
* 비동기 작업(asynchronous tasks)이나 부수 효과를 처리하는 목적에 특히 유용하게 활용됩니다 [2].
### 매 computed 의 본질
- 매 dependency 의 자동 추적 → 매 read 시점 lazy evaluation.
- 매 동일 input 의 cached return — Object.is 비교.
- 매 ref 처럼 `.value` 의 unwrap.
- 매 writable computed 의 setter 정의 가능.
## ⚖️ Trade-offs & Caveats
소스에 관련 정보가 부족합니다.
### 매 watch / watchEffect 의 차이
- `watch(source, cb)`: 매 explicit source — 매 old/new value 의 access.
- `watchEffect(fn)`: 매 자동 dep tracking — 매 deps mutation 시 fn 의 re-run.
- 매 flush timing: `'pre'` (default, before render) / `'post'` (after DOM) / `'sync'` (즉시).
---
*Last updated: 2026-05-03*
### 매 Vue 3.5 reactivity 개선
-`computed` 의 lazy invalidation — 매 unused chain 의 skip.
- 매 SSR friendly — server 에서 watch 의 no-op.
- 매 onWatcherCleanup() 의 자동 cleanup hook.
## 💻 패턴
### Basic computed
```typescript
import { ref, computed } from 'vue';
const firstName = ref('Yuna');
const lastName = ref('Kim');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
console.log(fullName.value); // "Yuna Kim" — cached
firstName.value = 'Jihoon';
console.log(fullName.value); // 매 invalidate → recompute
```
### Writable computed
```typescript
const count = ref(0);
const double = computed({
get: () => count.value * 2,
set: (v) => { count.value = v / 2; },
});
double.value = 10; // count.value === 5
```
### watch (explicit source)
```typescript
import { ref, watch } from 'vue';
const userId = ref(1);
const user = ref<User | null>(null);
watch(userId, async (id, oldId, onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort()); // 매 stale request 의 cancel
user.value = await fetchUser(id, { signal: ctrl.signal });
}, { immediate: true });
```
### watchEffect (auto-track)
```typescript
import { ref, watchEffect } from 'vue';
const query = ref('');
const results = ref<Item[]>([]);
watchEffect(async (onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort());
results.value = await searchAPI(query.value, { signal: ctrl.signal });
});
```
### Deep watch (object/array)
```typescript
const filters = reactive({ q: '', tags: [] });
watch(filters, (next) => {
console.log('filters changed', JSON.parse(JSON.stringify(next)));
}, { deep: true });
```
### Multiple sources
```typescript
const x = ref(0), y = ref(0);
watch([x, y], ([nx, ny], [ox, oy]) => {
console.log(`(${ox},${oy}) → (${nx},${ny})`);
});
```
### Flush timing — DOM 접근
```typescript
const list = ref<string[]>([]);
const containerRef = ref<HTMLElement>();
watch(list, () => {
// 매 DOM 의 update 후 scrollTop 의 read
containerRef.value!.scrollTop = containerRef.value!.scrollHeight;
}, { flush: 'post' });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 derived value (template render) | `computed` |
| 매 expensive computation + cache | `computed` |
| 매 external side-effect (fetch, DOM) | `watch` / `watchEffect` |
| 매 conditional dep tracking | `watch` (explicit source) |
| 매 모든 reactive read 의 react | `watchEffect` |
**기본값**: 매 derive 는 `computed`, 매 effect 는 `watch` with explicit source.
## 🔗 Graph
- 부모: [[Composition API]] · [[Vue_Single-File_Components_SFC]]
- 변형: [[Composables]] · [[Options API]]
- 응용: [[Pinia]] · [[Server_State_Management]]
- Adjacent: [[Reactive_Programming]] · [[State_Management]]
## 🤖 LLM 활용
**언제**: 매 Vue 3 component 의 derived data 정의, 매 async data fetch 의 dependency 변경 추적, 매 form-validation reactive chain.
**언제 X**: 매 React/Solid 의 코드 (각 framework 의 hook/signal 사용), 매 single-shot computation (그냥 함수).
## ❌ 안티패턴
- **매 computed side-effect**: 매 getter 안에서 mutation/fetch — 매 cache invalidation 의 chaos.
- **매 watch deep 의 남용**: 매 large object deep watch — 매 expensive equality check.
- **매 immediate + cleanup 누락**: 매 첫 fetch 의 race — 매 onCleanup 의 mandatory.
- **매 watchEffect 의 conditional dep**: 매 첫 run 에서 안 읽힌 ref 의 untracked.
## 🧪 검증 / 중복
- Verified (Vue 3.5 docs vuejs.org/api/reactivity-core, Evan You blog 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — computed/watch 의 timing/cleanup 패턴 정리 |
+165 -96
View File
@@ -1,124 +1,193 @@
---
id: wiki-2026-0508-concurrent-features
title: Concurrent Features
title: Concurrent Features (React 18+)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [React Concurrent Mode, useTransition, useDeferredValue]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [react, concurrent, performance, frontend]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React 19
---
# [[Concurrent Features|Concurrent Features]]
# Concurrent Features (React 18+)
## 📌 한 줄 통찰 (The Karpathy Summary)
Concurrent Features는 React 18부터 도입된 기능으로, 렌더링 작업을 일시 중지(pause), 중단(interrupt), 재개(resume)할 수 있게 해주는 기능입니다 [1]. 이를 통해 중요한 사용자 상호작용(클릭, 타이핑 등)의 우선순위를 높이고, 상대적으로 느린 업데이트(대용량 필터링 등)를 지연시킬 수 있습니다 [1]. 결과적으로 앱의 실제 연산 속도 자체를 마법처럼 빠르게 만드는 것은 아니지만, 인지되는 속도(perceived speed)를 최적화하여 사용자 인터페이스를 반응성 있게 유지합니다 [2].
## 한 줄
> **"매 render 매 interruptible 하다"**. React 18 부터 매 concurrent renderer — `useTransition`, `useDeferredValue`, `Suspense`, automatic batching, streaming SSR 매 모두 매 high-priority update 가 low-priority 를 preempt 가능한 architecture 위에 build.
## 📖 구조화된 지식 (Synthesized Content)
* **동시성 렌더링(Concurrent Rendering)의 원리:** 최신 버전의 React에서 기본적으로 동작하는 방식으로, 렌더링 작업의 우선순위를 지정하여 중요도가 높은 상호작용이 렌더링에 의해 차단(block)되지 않고 즉시 반응하도록 돕습니다 [1].
* **`useTransition`을 통한 우선순위 제어:** 특정 상태 업데이트를 '긴급하지 않은(non-urgent)' 것으로 표시하여 지연시키는 훅(Hook)입니다 [3]. 실시간 검색 결과나 대용량 데이터 필터링 시, 사용자의 타이핑 같은 입력은 즉각적으로 반응하게 하면서 무거운 렌더링 처리는 뒤로 미룰 수 있습니다 [3]. 또한 `isPending` 상태를 활용해 입력 즉각성을 막지 않고 로딩 스피너나 스켈레톤 UI를 표시할 수도 있습니다 [3].
* **`useDeferredValue`를 통한 값 참조 지연:** `useTransition`이 업데이트를 언제 발생시킬지를 관리한다면, `useDeferredValue`는 무거운 값을 언제 '읽을지'를 제어합니다 [4]. 입력과 같은 UI 변경은 즉시 반영하면서, 파생되는 무거운 로직 적용은 살짝 지연시켜 실시간 폼(form) 등에서 발생하는 끊김 현상(jank)을 줄여줍니다 [4].
* **프레임워크 지원 환경:** 2025년 기준 Next.js(App Router), Remix, Vite + React 18+ 환경 등 대부분의 풀스택 및 번들러 프레임워크에서 기본적으로 동시성 렌더링 기능이 통합되어 지원됩니다 [2].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **성능 향상의 본질적 한계:** 이 기능들은 앱의 실제 연산 속도를 물리적으로 높여주는 것이 아니라 "인지되는 속도(perceived speed)"를 우선시하는 기능입니다 [2]. 백그라운드 작업이 계속 진행되는 동안 UI의 반응성을 유지할 뿐, 실행해야 할 연산량 자체가 줄어드는 것은 아닙니다 [2].
* **선별적 사용 요구:** 모든 컴포넌트에 전역적으로 사용해서는 안 되며, 주로 '상호작용이 많은 뷰(interactive views)'에 선별적으로 적용해야 합니다 [4].
* **호환성 문제:** 렌더링을 차단하는(render-blocking) 구식 패턴(가드가 없는 클래스 컴포넌트 등)이나 오래된 상태 관리 라이브러리와 섞어서 사용하면 정상적으로 동작하지 않거나 성능 문제를 야기할 수 있습니다 [4].
### 매 핵심 features
- **Automatic batching**: promise / setTimeout / native event 모두 batch.
- **`startTransition` / `useTransition`**: 매 non-urgent state update marking.
- **`useDeferredValue`**: input 매 lag 없이 expensive list 매 deferred.
- **`Suspense`**: data fetching boundary, fallback UI.
- **Streaming SSR**: `renderToPipeableStream` (Node), `renderToReadableStream` (Edge).
- **`useId`**: SSR-safe unique id.
- **`use()` hook (React 19)**: unwrap promise/context inside render.
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 priority levels
1. Sync / urgent (user input).
2. Default (most state updates).
3. Transition (`startTransition`).
4. Idle.
#### [관계 유형 A: 아키텍처/기반 기술]
- [[useTransition|useTransition]]
- 연결 이유: 상태 업데이트를 긴급하지 않은 것으로 표시하여 지연시킬 수 있는 Concurrent Feature의 핵심 요소입니다 [3].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: React가 렌더링 우선순위를 조정하여 사용자 입력 반응성을 잃지 않게 유지하는 구체적인 메커니즘.
### 매 응용
1. 매 typeahead search — input snappy + results deferred.
2. Tab switching — 매 stale UI keeps interactive.
3. Streaming page render — 매 fastest paint then progressively fill.
- [[useDeferredValue|useDeferredValue]]
- 연결 이유: 비용이 큰 파생 데이터의 렌더링 반영 시점을 지연시켜 UI 끊김을 막는 또 다른 주요 요소입니다 [4].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상태의 업데이트 시점이 아닌, 계산된 값을 읽어 들이는 시점을 분리하는 최적화 전략.
## 💻 패턴
#### [관계 유형 B: 구현/활용 도구]
- Suspense
- 연결 이유: Concurrent Feature(특히 `useTransition`)와 결합하여 무거운 렌더링이나 데이터가 로드되는 동안 Fallback UI를 유연하게 표시하는 데 사용됩니다 [4].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비동기 로딩 상태에서 사용자 경험(UX)을 부드럽게 설계하는 선언적 UI 패턴.
### useTransition for non-urgent updates
```tsx
import { useState, useTransition } from 'react';
### Deeper Research Questions
- Concurrent Rendering이 동작할 때 브라우저의 메인 스레드는 내부적으로 어떻게 작업을 일시 중지하고 재개(pause, interrupt, resume)하는가?
- `useTransition``useDeferredValue`는 구체적으로 어떤 상황에서 각각 선택적으로 사용되어야 하며, 두 가지를 함께 사용할 때 발생하는 제약 사항은 없는가?
- 구식 상태 관리 라이브러리(outdated state libraries)가 Concurrent Features와 섞였을 때 충돌이 발생하는 기술적 원리는 무엇인가?
- 인지되는 속도(perceived speed)를 개선하기 위해 Concurrent 기능을 과도하게 사용했을 때 발생하는 메모리나 스케줄링 오버헤드는 어느 정도인가?
- Next.js나 Remix 같은 최신 프레임워크는 내부적으로 Concurrent Features를 어떻게 활용하여 스트리밍(streaming) 업데이트와 같은 성능 향상을 이끌어내는가?
function Filter({ items }: { items: Item[] }) {
const [query, setQuery] = useState('');
const [filtered, setFiltered] = useState(items);
const [isPending, startTransition] = useTransition();
### Practical Application Contexts
- **Implementation:** 실시간 검색창, 타입어헤드(Typeahead) 입력기, 복잡한 데이터 그리드 필터링 등 사용자 입력이 발생할 때마다 무거운 UI를 다시 그려야 하는 곳에 구현하여 입력이 버벅이지 않도록 만듭니다 [3, 4].
- **System Design:** 사용자의 즉각적인 피드백이 필요한 뷰와, 백그라운드에서 지연 렌더링되어도 무방한 컴포넌트를 분리하여 시스템 구조 및 우선순위를 기획합니다 [4].
- **Operation / Maintenance:** 애플리케이션 프로파일링 중 입력 지연(Input Lag)이 빈번하게 보고되는 부분을 찾아내고, 해당 부분에 렌더링 차단 패턴이 없는지 점검하여 Concurrent 기능을 점진적으로 도입합니다 [4, 5].
- **Learning Path:** 단순한 React Hook(`useState`, `useEffect`)의 렌더링 과정을 이해한 후, 메모이제이션 최적화(`React.memo`, `useCallback`)를 배우고, 최종적으로 렌더링의 우선순위를 제어하는 고급 최적화 과정으로 Concurrent 기능을 학습합니다.
- **My Project Relevance:** 검색 필터가 많은 대시보드나 실시간 데이터 시각화 차트를 구축할 때 UI 스레드가 멈추는 것을 방지하여 사용자 경험을 크게 개선하는 데 직접적으로 적용될 수 있습니다.
const onChange = (v: string) => {
setQuery(v); // urgent — input responds immediately
startTransition(() => {
setFiltered(items.filter((i) => i.name.includes(v))); // non-urgent
});
};
### Adjacent Topics
- [[Server Components|Server Components]]
- 확장 방향: 클라이언트에서 렌더링을 지연시키거나 최적화하는 것을 넘어, 무거운 렌더링 작업 자체를 서버로 완전히 옮겨 클라이언트의 자바스크립트 번들 크기와 실행 부담을 근본적으로 줄이는 방법론 탐구 [6, 7].
- Code Splitting & Lazy Loading
- 확장 방향: 화면의 렌더링 과정을 매끄럽게 하는 것을 넘어, 초기 애플리케이션 로딩 시 네트워크를 통해 다운로드하는 코드의 양 자체를 분할하여 초기 응답성(Time to Interactive)을 향상시키는 전략 탐구 [8, 9].
---
*Last updated: 2026-04-30*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
return (
<>
<input value={query} onChange={(e) => onChange(e.target.value)} />
{isPending && <Spinner />}
<List items={filtered} />
</>
);
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### useDeferredValue
```tsx
import { useState, useDeferredValue, memo } from 'react';
**선택 A를 써야 할 때:**
- *(TODO)*
function Search({ items }: { items: Item[] }) {
const [query, setQuery] = useState('');
const deferred = useDeferredValue(query);
return (
<>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<SlowList items={items} query={deferred} />
</>
);
}
**선택 B를 써야 할 때:**
- *(TODO)*
const SlowList = memo(({ items, query }: { items: Item[]; query: string }) => {
return <ul>{items.filter((i) => i.name.includes(query)).map((i) => <li key={i.id}>{i.name}</li>)}</ul>;
});
```
**기본값:**
> *(TODO)*
### Suspense boundary
```tsx
import { Suspense } from 'react';
## ❌ 안티패턴 (Anti-Patterns)
function App() {
return (
<Suspense fallback={<Skeleton />}>
<UserProfile id={42} />
<Suspense fallback={<PostsSkeleton />}>
<Posts userId={42} />
</Suspense>
</Suspense>
);
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### use() hook (React 19)
```tsx
import { use, Suspense } from 'react';
function Profile({ promise }: { promise: Promise<User> }) {
const user = use(promise); // 매 unwrap inside render
return <h1>{user.name}</h1>;
}
// caller
<Suspense fallback={<Spinner />}>
<Profile promise={fetchUser(42)} />
</Suspense>
```
### Streaming SSR (Node)
```ts
import { renderToPipeableStream } from 'react-dom/server';
server.get('/', (req, res) => {
const { pipe } = renderToPipeableStream(<App />, {
bootstrapScripts: ['/main.js'],
onShellReady() { res.statusCode = 200; pipe(res); },
onError(err) { console.error(err); },
});
});
```
### Automatic batching across async
```tsx
function handleClick() {
// React 18+: 매 둘 다 single render
setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
}, 0);
}
```
### flushSync for opt-out
```tsx
import { flushSync } from 'react-dom';
flushSync(() => setItems(next)); // 매 sync flush — DOM ready
scrollToBottom(); // 매 새 item 매 already mounted
```
## 매 결정 기준
| 상황 | Feature |
|---|---|
| Slow filter blocks input | `useTransition` or `useDeferredValue` |
| Async data in component tree | `Suspense` + `use()` |
| Need DOM after update | `flushSync` |
| SSR slow first byte | streaming SSR |
| Pre-React-18 codebase | upgrade first |
**기본값**: input UI 매 lag → `useDeferredValue`. Bigger state cascade → `useTransition`.
## 🔗 Graph
- 부모: [[React]] · [[Performance]]
- 변형: [[Suspense]] · [[Server-Components]] · [[Streaming-SSR]]
- 응용: [[Next.js-App-Router]] · [[Remix]]
- Adjacent: [[Code-Splitting]] · [[React-Hooks]]
## 🤖 LLM 활용
**언제**: 매 input lag, expensive list, async-heavy tree, SSR perf.
**언제 X**: 매 trivial UI, 매 add-only sync state.
## ❌ 안티패턴
- **`startTransition` for urgent input**: 매 input 매 still feel laggy.
- **No `Suspense` boundary 위 `use()`**: 매 throws 매 above-tree fallback 까지 propagate.
- **Mixing `flushSync` everywhere**: 매 defeats concurrent benefits.
## 🧪 검증 / 중복
- Verified (react.dev official docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — React 18/19 concurrent features + patterns |
+24 -15
View File
@@ -1,25 +1,34 @@
---
id: wiki-20260508-concurrent-rendering-redir
id: wiki-2026-0508-concurrent-rendering-redir
title: Concurrent Rendering
category: Frontend
status: merged
redirect_to: Concurrent_Rendering
canonical_id: Concurrent_Rendering
category: 10_Wiki/Topics
status: duplicate
canonical_id: concurrent-rendering
duplicate_of: "[[Concurrent Features]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [redirect]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, react, concurrent]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-merge 2026-05-08)
---
# Concurrent Rendering
> [!IMPORTANT]
> 이 문서는 P-Reinforce Phase 2 자동 MERGE에 의해 **[[Concurrent_Rendering]]**로 통합되었습니다.
> **이 문서는 [[Concurrent Features]] 의 중복본입니다.** Canonical 문서로 redirect.
---
*Redirected to: [[Concurrent_Rendering]]*
## 핵심 요약
- 매 React 18+ 의 interruptible render — Lane model.
- 매 startTransition / useDeferredValue / Suspense 의 unlock.
- 매 priority-based scheduling — 매 user input 의 우선.
## 🔗 Graph
- 부모: [[Concurrent Features]] (canonical)
- Adjacent: [[Lane Model]] · [[Time Slicing]] · [[Fiber Architecture]]
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+23 -15
View File
@@ -1,25 +1,33 @@
---
id: wiki-20260508-container-queries-redir
id: wiki-2026-0508-container-queries-redir
title: Container Queries
category: Frontend
status: merged
redirect_to: Container_Queries
canonical_id: Container_Queries
category: 10_Wiki/Topics
status: duplicate
canonical_id: container-queries
duplicate_of: "[[컨테이너 쿼리(Container Queries)]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [redirect]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, css, responsive]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-merge 2026-05-08)
---
# Container Queries
> [!IMPORTANT]
> 이 문서는 P-Reinforce Phase 2 자동 MERGE에 의해 **[[Container_Queries]]**로 통합되었습니다.
> **이 문서는 [[컨테이너 쿼리(Container Queries)]] 의 중복본입니다.** Canonical 문서로 redirect.
---
*Redirected to: [[Container_Queries]]*
## 핵심 요약
- 매 viewport 가 아닌 parent container 의 size 기반 styling.
-`@container` rule + `container-type: inline-size`.
- 매 모든 evergreen browser (2023+) 에서 baseline.
## 🔗 Graph
- 부모: [[컨테이너 쿼리(Container Queries)]] (canonical)
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+19 -79
View File
@@ -2,91 +2,31 @@
id: wiki-2026-0508-core-web-vitals
title: Core Web Vitals
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: core-web-vitals
duplicate_of: "[[Core-Web-Vitals]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, web-vitals, performance]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[Core Web Vitals]]
# Core Web Vitals
## 📌 한 줄 통찰 (The Karpathy Summary)
Core Web Vitals(코어 웹 바이탈)은 웹사이트의 실제 성능과 사용자 경험을 평가하는 필수 지표로, 로딩 속도, 레이아웃의 안정성, 사용자 입력에 대한 반응 속도를 측정합니다 [1]. 핵심 지표로는 LCP(Largest Contentful Paint), CLS(Cumulative Layout [[Shift]]), INP(Interaction to Next Paint)가 있으며, 이는 구글의 검색 순위(Ranking signal)와 모바일 우선 인덱싱에 직접적인 영향을 미칩니다 [2, 3].
> **이 문서는 [[Core-Web-Vitals]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **핵심 지표와 목표치**: Core Web Vitals는 크게 세 가지 주요 지표로 구성됩니다. LCP(Largest Contentful Paint)는 주요 콘텐츠의 로딩 속도를 의미하며 2.5초 미만을 유지해야 하고, CLS(Cumulative Layout Shift)는 레이아웃의 시각적 안정성을 나타내며 0.1 미만이어야 하며, INP(Interaction to Next Paint)는 사용자의 입력에 대한 반응성을 측정하여 200밀리초 미만을 목표로 최적화해야 합니다 [4].
* **CSS 및 반응형 디자인과의 연관성**: 잘못된 이미지 크기 지정, 너비(width) 및 높이(height) 속성 누락, 최적화되지 않은 폰트 등은 모바일 환경에서 Core Web Vitals 점수 하락의 가장 흔한 원인이 됩니다 [2, 3]. 잘 구축된 반응형 레이아웃은 불필요한 레이아웃 이동(Layout shift)을 줄이고 로딩 시간을 개선하며 사용자 상호작용을 민첩하게 만듭니다 [1].
* **성능 최적화 기법**: CLS를 방지하기 위해 컨테이너에 `aspect-ratio` 속성을 적용하거나 명시적인 너비와 높이를 지정해야 합니다 [5, 6]. LCP 향상을 위해서는 LCP 요소(주로 히어로 이미지)에 `fetchpriority="high"`를 설정하고 폴드(fold) 아래의 이미지는 지연 로딩(lazy-load) 처리하며, WebP나 AVIF 같은 압축률이 높은 차세대 포맷을 사용하는 방법이 있습니다 [5-7].
* **SEO 및 비즈니스 영향**: 구글은 페이지 경험 신호의 일부로 Core Web Vitals를 활용하므로, 로딩이 느리고 레이아웃 이동이 잦은 비반응형 웹사이트는 검색 결과에서 성능이 저하될 수 있습니다 [3, 4]. 따라서 이 지표들을 지속적으로 모니터링하고 최적화하는 것은 2026년 현재 반응형 웹 디자인의 핵심 요구 사항입니다 [4, 8].
## 핵심 요약
- LCP / INP / CLS — 2024+ 현재 Google 의 official metrics.
- INP (Interaction to Next Paint) 가 FID 를 대체 (2024-03).
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Responsive Web Design]], [[CSS Performance Optimization]]
- **Projects/Contexts:** [[Search Engine [[Optimization]] (SEO)]]
- **Contradictions/Notes:** 소스 전반에 걸쳐 CSS 및 반응형 디자인의 최적화가 Core Web Vitals 지표 개선으로 직결된다고 강조하고 있으며, 소스 간 상충되는 의견은 존재하지 않습니다.
## 🔗 Graph
- 부모: [[Core-Web-Vitals]] (canonical)
---
*Last updated: 2026-04-26*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -2,93 +2,157 @@
id: wiki-2026-0508-critical-rendering-path-crp
title: Critical Rendering Path (CRP)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [CRP, Browser Render Pipeline]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [browser, rendering, performance, web-vitals]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: HTML/CSS/JS
framework: Browser
---
# [[Critical Rendering Path (CRP)|Critical Rendering Path (CRP]]
# Critical Rendering Path (CRP)
## 📌 한 줄 통찰 (The Karpathy Summary)
[[Critical Rendering Path|Critical Rendering Path]] (CRP)는 웹 브라우저가 HTML, CSS, JavaScript 코드를 수신하여 화면의 픽셀로 변환하기 위해 실행하는 일련의 단계입니다 [1, 2]. 이 경로는 DOM(문서 객체 모델) 및 [[CSSOM|CSSOM]](CSS 객체 모델) 구축, 렌더 트리 생성, 레이아웃 계산, 화면 페인팅 등의 핵심 과정으로 구성됩니다 [2]. CRP를 최적화하면 최초 렌더링(Time to First Render) 시간을 단축하고, 초당 60프레임의 원활한 상호작용을 보장하며, 성능 저하나 끊김(Jank)을 방지할 수 있습니다 [2, 3].
## 한 줄
> **"매 CRP = HTML/CSS/JS → pixel 의 매 변환 단계 sequence."**. 매 단계: DOM 구축 → CSSOM 구축 → Render Tree → Layout (reflow) → Paint → Composite. 매 단계마다 매 blocking resource 의 latency가 매 LCP / FCP 의 결정. 매 2026 perspective는 INP / Core Web Vitals + speculation rules + View Transitions API.
## 📖 구조화된 지식 (Synthesized Content)
- **[[DOM (Document Object Model)|DOM(Document Object Model]] 구축:** 브라우저는 HTML 데이터를 수신하면 점진적 파싱(incremental parsing)을 시작합니다 [3, 4]. 수신된 바이트를 문자, 토큰, 노드로 변환한 뒤 계층적인 DOM 트리를 구축합니다 [3, 4].
- **[[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]] 구축:** CSS는 HTML과 달리 점진적으로 처리되지 않으며 렌더링 차단(render-[[Blocking|Blocking]]) 리소스로 작동합니다 [5, 6]. 브라우저는 화면에 스타일이 지정되지 않은 콘텐츠가 깜빡이는 현상(FOUC)을 막기 위해 렌더 트리를 만들기 전 모든 연결된 스타일시트를 다운로드하고 구문 분석하여 CSSOM을 완성해야 합니다 [5, 6].
- **렌더 트리([[Render Tree|Render Tree]]) 생성:** DOM과 CSSOM 트리가 준비되면 이를 결합하여 렌더 트리를 합성합니다 [7, 8]. 이 트리에는 화면 렌더링에 필요한 가시적 노드만 포함되며, `<script>`, `<meta>` 요소나 `display: none` 처리된 요소 등 시각적 레이아웃에 영향을 주지 않는 노드는 제외됩니다 [7-9].
- **레이아웃(Layout / Reflow):** 렌더 트리가 구축되면 브라우저는 뷰포트 크기와 박스 모델을 기반으로 각 요소의 정확한 화면 상 위치(x, y)와 치수(너비, 높이)를 계산합니다 [10-12].
- **페인트(Paint / Repaint) 및 합성(Compositing):** 페인트 단계에서는 계산된 기하학적 구조와 스타일(색상, 그림자, 텍스트 등)을 바탕으로 요소를 실제 픽셀로 화면에 그립니다 [13-15]. 마지막으로 합성 단계에서는 여러 레이어를 하나의 최종 이미지로 결합하며, 최신 브라우저에서는 성능을 위해 이 과정을 GPU에 오프로드하여 처리합니다 [13, 16].
- **성능 최적화 전략:** CRP 최적화를 위해서는 다운로드해야 하는 렌더링 차단 리소스(`<head>` 내부의 CSS 및 동기식 JavaScript)의 크기와 개수를 최소화해야 합니다 [17-19]. 중요하지 않은 리소스의 로드를 지연시키거나 비동기로 처리하여 브라우저의 렌더링 파이프라인이 멈추지 않도록 구성하는 것이 핵심입니다 [17, 20].
## 매 핵심
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[DOM (Document Object Model)|DOM (Document Object Model]], CSSOM (CSS Object Model), [[Render Tree|Render Tree]], Reflow, Repaint
- **Projects/Contexts:** 최신 프론트엔드 개발의 기초 구조 설계, 코어 웹 바이탈([[Core Web Vitals|Core Web Vitals]]) 성능 개선, React의 [[Virtual DOM|Virtual DOM]] 도입을 통한 렌더링 병목 현상 해결 컨텍스트 [1, 2, 21].
- **Contradictions/Notes:** CSS 선택자의 구체성(specificity)을 높게 작성할 경우 파싱 비용이 증가하지만, 현대 브라우저 엔진은 구문 분석 속도가 매우 빠르기 때문에 이러한 선택자 최적화가 CRP 전체 성능에 미치는 영향은 마이크로초(microseconds) 수준에 불과하여 최적화의 주된 우선순위로 삼기에는 실효성이 부족할 수 있습니다 [22].
### 매 단계
1. **DOM**: HTML parse → Document Object Model.
2. **CSSOM**: CSS parse → CSS Object Model (매 render-blocking).
3. **Render Tree**: DOM + CSSOM merge — 매 visible nodes only.
4. **Layout (Reflow)**: geometry 계산 — 매 viewport relative position/size.
5. **Paint**: 매 pixel 의 fill — layer별.
6. **Composite**: GPU 의 layer 의 final 합성.
---
*Last updated: 2026-04-25*
### 매 blocking
- CSS = 매 render-blocking — `<link rel="stylesheet">` HEAD 안에서 매 parse 차단.
- JS = 매 parser-blocking — `<script>` 매 DOM build 차단 (async/defer 외).
- Font = 매 paint-blocking (FOIT) — `font-display: swap` 권장.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Above-the-fold critical CSS inline.
2. JS `defer` / `type="module"` — 매 default async.
3. Preload key resources — `<link rel="preload" as="font">`.
4. Speculation Rules API (Chrome 122+) — prerender next nav.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 1. Critical CSS inline
```html
<head>
<style>
/* above-the-fold only */
body { margin: 0; font: 16px/1.5 system-ui; }
.hero { min-height: 60vh; }
</style>
<link rel="preload" href="/main.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/main.css"></noscript>
</head>
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Defer + module scripts
```html
<script src="/app.js" defer></script>
<script type="module" src="/app.mjs"></script>
<!-- module = defer by default -->
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. Resource hints
```html
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://api.example.com">
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="modulepreload" href="/chunks/router.js">
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 4. font-display swap
```css
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap; /* avoid FOIT */
}
```
**기본값:**
> *(TODO)*
### 5. Speculation Rules (Chrome 122+, 2024-)
```html
<script type="speculationrules">
{
"prerender": [{ "where": { "href_matches": "/*" }, "eagerness": "moderate" }]
}
</script>
```
## ❌ 안티패턴 (Anti-Patterns)
### 6. Avoid layout thrash
```javascript
// BAD — read/write/read/write triggers reflow each time
elements.forEach((el) => {
el.style.width = el.offsetWidth + 10 + 'px';
});
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// GOOD — batch reads then writes
const widths = elements.map((el) => el.offsetWidth);
elements.forEach((el, i) => { el.style.width = widths[i] + 10 + 'px'; });
```
### 7. CSS containment
```css
.card {
contain: layout paint style;
content-visibility: auto;
contain-intrinsic-size: 0 200px;
}
```
### 8. View Transitions API (2024-)
```javascript
document.startViewTransition(() => {
updateDOM();
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| LCP > 2.5s | Critical CSS inline + preload hero image. |
| INP > 200ms | 매 long task 의 break — `scheduler.yield()`. |
| CLS > 0.1 | 매 fixed dimensions, font-display swap + size-adjust. |
| 매 deep tree | `content-visibility: auto`. |
| Next nav predict | Speculation Rules. |
**기본값**: 매 Web Vitals 측정 → 매 bottleneck 식별 → targeted optimization.
## 🔗 Graph
- 부모: [[Browser Rendering]] · [[Web Performance]]
- 변형: [[Server-Side Rendering]] · [[Streaming SSR]]
- 응용: [[Core Web Vitals]] · [[LCP Optimization]]
- Adjacent: [[DOM]] · [[CSSOM]] · [[Layout Thrashing]]
## 🤖 LLM 활용
**언제**: 매 resource hint 매 selection, critical CSS extraction script.
**언제 X**: 매 actual measurement (Lighthouse, WebPageTest) — 매 LLM 추측 X.
## ❌ 안티패턴
- **@import in CSS**: 매 serial download — `<link>` 사용.
- **`<script>` in head w/o defer**: 매 DOM 파싱 차단.
- **Sync XHR**: 매 deprecated — 매 fetch async.
- **Forced sync layout**: 매 read-write-read pattern — batch.
## 🧪 검증 / 중복
- Verified (web.dev, Chrome DevRel docs 2024-2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CRP + Speculation Rules + View Transitions |
@@ -1,42 +1,158 @@
---
category: Other
tags: [auto-wikified, technical-documentation, other]
id: wiki-2026-0508-cross-platform-mobile-development-frameworks
title: Cross-platform Mobile Development Frameworks
description: "크로스 플랫폼 모바일 개발 프레임워크는 단일 코드베이스를 사용하여 iOS 및 Android와 같은 다수의 플랫폼에서 실행되는 애플리케이션을 구축할 수 있게 해주는 도구입니다 [1-3]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [RN vs Flutter vs KMP, hybrid mobile]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [mobile, react-native, flutter, kmp, capacitor]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: multi
framework: multi
---
# Cross-platform Mobile Development Frameworks
## 📌 Brief Summary
크로스 플랫폼 모바일 개발 프레임워크는 단일 코드베이스를 사용하여 iOS 및 Android와 같은 다수의 플랫폼에서 실행되는 애플리케이션을 구축할 수 있게 해주는 도구입니다 [1-3]. 2025년 현재 시장을 주도하는 두 가지 주요 프레임워크는 Meta가 지원하는 **React Native**와 Google이 지원하는 **Flutter**입니다 [4-6]. 이 기술들은 플랫폼별로 따로 코드를 작성하는 기존 네이티브 개발 방식에 비해 개발 시간과 비용을 크게 줄이면서도 네이티브에 준하는 뛰어난 성능과 사용자 경험을 제공합니다 [1, 7, 8].
## 매 한 줄
> **"매 single codebase → multiple OS targets — runtime tradeoff 의 spectrum"**. 매 2026 landscape 는 RN(JS+native), Flutter(Skia/Impeller), Kotlin Multiplatform(shared logic + native UI), Capacitor(WebView) 의 4 축. 매 native parity vs dev velocity vs binary size 의 결정.
## 📖 Core Content
**1. 렌더링 철학과 아키텍처**
* **Flutter (자체 렌더링 엔진):** Dart 언어를 기반으로 하며, Skia 또는 최신 Impeller 렌더링 엔진을 통해 화면의 모든 픽셀을 직접 그립니다 [8-11]. 이는 플랫폼의 네이티브 UI 컴포넌트에 의존하지 않으므로, 모든 디바이스와 OS에서 "픽셀 퍼펙트(Pixel-perfect)"한 일관된 브랜드 경험을 제공합니다 [9, 10, 12].
* **React Native (네이티브 브릿지 및 JSI):** JavaScript/TypeScript를 사용하며 코드를 실제 플랫폼의 네이티브 UI 컴포넌트(iOS의 UIView, Android의 View)로 변환하여 렌더링합니다 [10, 13, 14]. 최근에는 비동기 브릿지(Bridge) 방식의 병목을 해결하기 위해 '새로운 아키텍처(New Architecture)'를 도입했습니다. JSI(JavaScript Interface), Fabric, TurboModules를 통해 JavaScript와 네이티브 레이어 간의 동기식 직접 통신을 가능하게 하여 성능을 극대화했습니다 [12, 15-20].
## 매 핵심
**2. 개발 경험(DX) 및 에코시스템**
* **React Native:** 세계에서 가장 널리 쓰이는 JavaScript 생태계를 그대로 활용할 수 있어 인재 확보와 코드 공유(웹/모바일) 측면에서 압도적인 전략적 우위를 가집니다 [21-23]. 특히 EAS(Expo Application Services), Expo Router 등을 제공하는 **Expo 에코시스템**은 복잡한 네이티브 빌드 구성을 추상화하여 프로덕션 수준의 워크플로우를 극도로 단순화시킵니다 [24-27].
* **Flutter:** 고도로 통합된 자체 도구 모음을 제공합니다 [25]. 상태 보존 핫 리로드(Hot Reload), 광범위한 내장 위젯 시스템, 통합된 DevTools(UI 검사기, 성능 프로파일러 등)를 통해 매우 빠른 UI 개발 주기를 보장합니다 [28-31].
### 매 4 가지 architectural model
1. **Embedded JS runtime + native widgets**: React Native (Hermes/JSC + UIKit/Android View).
2. **Embedded engine + own renderer**: Flutter (Dart AOT + Impeller GPU).
3. **Shared logic + native UI**: Kotlin Multiplatform (KMP) — UI 는 SwiftUI/Compose.
4. **WebView wrapper**: Capacitor / Tauri Mobile / PWA — 매 web stack 그대로.
**3. 성능 및 최신 발전**
* 두 프레임워크 모두 최적화 시 60fps 이상의 부드러운 성능을 제공합니다 [32].
* Flutter는 '셰이더 컴파일 정크(Shader compilation jank)' 문제를 해결하기 위해 런타임이 아닌 빌드 타임에 셰이더를 사전 컴파일하는 **Impeller 엔진**을 도입하여 첫 프레임부터 매끄러운 성능을 보장합니다 [11, 33].
* React Native 역시 브릿지를 제거한 새로운 아키텍처를 통해 Flutter와의 성능 격차를 사실상 없앴으며, 고도화된 인터랙션에서도 네이티브와 구분하기 힘든 성능을 냅니다 [34-36].
### 매 2026 의 maturity 비교
| 축 | RN 0.76+ | Flutter 3.27 | KMP 2.1 | Capacitor 7 |
|---|---|---|---|---|
| native look | 매 high | 매 own widgets | 매 native | 매 medium |
| perf | 매 JSI direct | 매 Impeller GPU | 매 native | 매 WebView |
| binary | ~25MB | ~20MB | ~8MB | ~10MB |
| hot reload | 매 fast | 매 fastest | 매 medium | 매 instant |
**4. AI 및 머신러닝 통합**
* Flutter는 Google 생태계의 이점을 살려 Firebase AI Logic(Gemini) 및 TensorFlow Lite와의 깊고 원활한 자사(First-party) 통합을 제공합니다 [37, 38].
* React Native는 광범위한 커뮤니티 기반 아래 `react-native-fast-tflite`, `react-native-ai` 등 다양한 서드파티 라이브러리를 통해 LLM 및 온디바이스 ML 통합에 있어 유연하고 폭넓은 선택지를 제공합니다 [37, 39].
### 매 선택의 실제 driver
- 매 dev team 의 existing skill (TS vs Dart vs Kotlin).
- 매 design 의 brand-custom 정도 (Flutter 우세).
- 매 native API depth (RN 의 거대 ecosystem).
- 매 backend 와의 code share (KMP 우세).
## ⚖️ Trade-offs & Caveats
**React Native의 제약 및 트레이드오프:**
* **유지보수 비용 및 플랫폼 파편화:** 실제 네이티브 UI 컴포넌트에 의존하기 때문에, iOS나 Android OS가 업데이트되면서 기본 모듈이 독자적으로 진화할 경우 플랫폼별 수정 사항이 발생할 수 있습니다 [40]. 이는 시간이 지남에 따라 유지보수 비용을 증가시키는 요인이 됩니다 [41, 42].
* **서드파티 의존성:** JavaScript 생태계의 방대한 라이브러리를 사용할 수 있지만, 품질이 고르지 않고 OS 업데이트에 따른 호환성 문제가 발생할 수 있어 지속적인 종속성 관리(Dependency Management)가 요구됩니다 [43-45].
## 💻 패턴
**Flutter의 제약 및 트레이드오프:**
* **네이티브 동작의 모방:** 네이티브 UI 컴포넌트를 사용하지 않고 자체 엔진으로 화면을 그리기 때문에, 스크롤 물리 효과나 텍스트 선택 등 운영체제 특유의 미묘한 동작이나 접근성(Accessibility) 의미를 100% 동일하게 구현하려면 추가적인 세밀한 조정이 필요합니다 [10, 46-48].
* **앱 크기 및 인재 풀:** Dart 런타임과 Impeller 렌더링 엔진을 앱과 함께 배포해야 하므로, React Native에 비해 앱의 기본 번들(APK 등) 크기가 더 큽니다 [9, 32, 49]. 또한, Dart 언어를 사용하는 개발자 풀이 JavaScript에 비해 작기 때문에 초기 인력 채용 및 팀 확장에 어려움이 따를 수 있습니다 [21, 50, 51].
### React Native (Bridgeless)
```typescript
// App.tsx
import { View, Text, Pressable } from 'react-native';
---
*Last updated: 2026-05-03*
export default function App() {
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
<Pressable onPress={() => console.log('tap')}>
<Text>Hello RN 0.76</Text>
</Pressable>
</View>
);
}
```
### Flutter (Material 3)
```dart
// main.dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext c) => MaterialApp(
home: Scaffold(
body: Center(child: FilledButton(
onPressed: () => debugPrint('tap'),
child: const Text('Hello Flutter'),
)),
),
);
}
```
### Kotlin Multiplatform (shared module)
```kotlin
// shared/src/commonMain/kotlin/Greeting.kt
class Greeting {
fun greet(): String = "Hello from ${Platform().name}"
}
expect class Platform() {
val name: String
}
// androidMain: actual class Platform { actual val name = "Android" }
// iosMain: actual class Platform { actual val name = UIDevice.currentDevice.systemName() }
```
### Capacitor (web → native shell)
```typescript
import { Camera, CameraResultType } from '@capacitor/camera';
const photo = await Camera.getPhoto({
resultType: CameraResultType.Uri,
quality: 90,
});
console.log(photo.webPath);
```
### 매 platform-specific code split (RN)
```typescript
// Button.ios.tsx / Button.android.tsx — Metro 의 자동 resolve
import { Platform } from 'react-native';
const haptic = Platform.select({
ios: () => require('react-native-haptic-feedback').trigger('impactMedium'),
android: () => require('react-native-vibration').vibrate(50),
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 web team 의 mobile 진입 | React Native |
| 매 brand-custom UI + 60fps animation | Flutter |
| 매 existing Android/iOS app 의 logic share | Kotlin Multiplatform |
| 매 enterprise content app + minimal native | Capacitor / PWA |
| 매 highest native parity 필요 | 매 native (Swift+Kotlin) |
**기본값**: 매 startup MVP 는 RN, 매 design-driven product 는 Flutter, 매 brownfield enterprise 는 KMP.
## 🔗 Graph
- 부모: [[Frontend]]
- 변형: [[React_Native]] · [[Flutter]] · [[Bridgeless_New_Architecture]]
- 응용: [[Expo_Router]] · [[Hermes]] · [[Impeller]]
- Adjacent: [[Dart]] · [[JavaScriptCore]] · [[Skia]]
## 🤖 LLM 활용
**언제**: 매 framework 선택 의 decision 지원, 매 platform-specific limitation (image picker, BLE) lookup, 매 perf trade-off 의 정량 비교.
**언제 X**: 매 native-only API (CarPlay, Vision Pro full) 가 critical 한 경우 — 매 native 의 권장.
## ❌ 안티패턴
- **매 framework hopping**: 매 1년마다 RN→Flutter→KMP — 매 sunk cost 의 누적.
- **매 WebView 로 모든 것**: 매 perf-critical screen 의 WebView 내장 — 매 jank 의 발생.
- **매 native module 의 abandon**: 매 unmaintained community module 의 prod 배포.
- **매 platform divergence 무시**: 매 iOS HIG vs Material 의 cross-paste — 매 user 위화감.
## 🧪 검증 / 중복
- Verified (RN 0.76 release 2024-10, Flutter 3.27 docs, KMP Stable 2023-11, Capacitor 7 release).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — RN/Flutter/KMP/Capacitor 의 4-axis comparison |
+191 -65
View File
@@ -2,91 +2,217 @@
id: wiki-2026-0508-custom-hooks-patterns
title: Custom Hooks Patterns
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [FE-REACT-CUSTOM-HOOK-001]
aliases: [React Custom Hooks, useXxx Patterns]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [react, Frontend, custom-hooks, dry, refactoring, separation-of-concerns, business-Logic]
confidence_score: 0.9
verification_status: applied
tags: [react, hooks, patterns]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React 19
---
# Custom Hooks Patterns (커스텀 훅 패턴)
# Custom Hooks Patterns
## 📌 한 줄 통찰 (The Karpathy Summary)
> "UI 렌더링과 비즈니스 로직을 날카롭게 분리하고, 반복되는 로직을 독립적인 함수로 캡슐화하여 컴포넌트의 가독성과 테스트 가능성을 극대화하라" — React에서 로직 재사용의 가장 강력하고 유연한 표준 방식.
## 한 줄
> **"매 custom hook = stateful logic 의 재사용 unit, JSX 의 X."**. React 19 (2024) `use()` + Server Components 시대에는 custom hook이 매 client-side state machine + side effect orchestration 의 primary abstraction. 매 naming은 `useXxx` — 매 ESLint react-hooks rule 의 enforce.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Logic Decoupling and Reusable Abstraction" — 데이터 패칭, 상태 관리, 이벤트 리스너 등록 등의 횡단 관심사를 컴포넌트 밖으로 추출하여 `useX`라는 이름의 커스텀 인터페이스로 추상화하는 패턴.
- **주요 적용 사례:**
- **Data Fetching:** `useFetch`, `useQuery` 등을 통해 로딩/에러 상태와 데이터 처리 로직 공유.
- **Form [[Management|Management]]:** `useForm`을 통해 입력값 바인딩 및 유효성 검사 로직 재사용.
- **Global [[State|State]] / [[Storage|Storage]]:** `useLocalStorage`, `useAuth` 등을 통해 외부 상태와의 동기화.
- **설계 원칙:**
- **Naming:** 반드시 `use` 접두사로 시작하여 훅임을 명시.
- **Co-location:** 특정 도메인에 국한된 훅은 해당 도메인 폴더에, 범용 훅은 `src/hooks`에 배치.
- **의의:** 중복 코드를 제거(DRY)하고, 복잡한 컴포넌트의 인지적 부하를 줄여 유지보수 비용을 획기적으로 낮춤.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거에는 로직 재사용을 위해 고차 컴포넌트(HOC)나 [[Render Props|Render Props]]를 사용했으나, 훅 도입 이후 이러한 방식은 'Wrapper Hell'을 유발하는 지양해야 할 정책으로 간주됨.
- **정책 변화:** Antigravity 프로젝트는 30라인 이상의 비즈니스 로직을 포함하는 컴포넌트 개발 시 반드시 커스텀 훅으로의 분리를 검토하도록 강제하며, 훅 내부에서 사이드 이펙트(Effect) 발생 시 명확한 클린업 로직을 포함하는 것을 정책화함.
### 매 규칙 (Rules of Hooks)
- Top-level 만 호출 — 매 conditional / loop X.
- React function / 매 다른 hook 안에서 만 — 매 일반 function X.
- Naming `useXxx` — 매 lint 가 의존.
## 🔗 지식 연결 (Graph)
- [[React-Hooks|React-Hooks]], [[Dry-Principle|DRY-Principle]], [[Clean-Code-Principles|Clean-Code-Principles]], [[Component-Composition|Component-Composition]]
- **Raw Source:** 00_Raw/Custom Hooks.md
### 매 composition
- Hook = 매 다른 hook 의 조합 — `useMutation``useState` + `useCallback` + `useRef`.
- 매 stateful logic 의 분리 + 매 testable 단위.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Data fetching — `useQuery`, `useSWR`.
2. DOM observation — `useIntersectionObserver`, `useResizeObserver`.
3. State machines — `useToggle`, `useReducer` wrapper.
4. Browser API — `useLocalStorage`, `useMediaQuery`, `useGeolocation`.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### 1. useToggle (state primitive)
```typescript
import { useState, useCallback } from 'react';
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export function useToggle(initial = false) {
const [on, setOn] = useState(initial);
const toggle = useCallback(() => setOn((v) => !v), []);
const setOnTrue = useCallback(() => setOn(true), []);
const setOnFalse = useCallback(() => setOn(false), []);
return { on, toggle, setOnTrue, setOnFalse };
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. useDebouncedValue
```typescript
import { useEffect, useState } from 'react';
**선택 A를 써야 할 때:**
- *(TODO)*
export function useDebouncedValue<T>(value: T, delayMs = 300): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => setDebounced(value), delayMs);
return () => clearTimeout(id);
}, [value, delayMs]);
return debounced;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 3. useEventListener (typed)
```typescript
import { useEffect, useRef } from 'react';
**기본값:**
> *(TODO)*
export function useEventListener<K extends keyof WindowEventMap>(
type: K,
handler: (e: WindowEventMap[K]) => void,
target: Window | HTMLElement = window,
) {
const handlerRef = useRef(handler);
useEffect(() => { handlerRef.current = handler; });
useEffect(() => {
const listener = (e: Event) => handlerRef.current(e as WindowEventMap[K]);
target.addEventListener(type, listener);
return () => target.removeEventListener(type, listener);
}, [type, target]);
}
```
## ❌ 안티패턴 (Anti-Patterns)
### 4. useIntersectionObserver
```typescript
import { useEffect, useRef, useState } from 'react';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export function useIntersectionObserver<T extends Element>(
options: IntersectionObserverInit = {},
) {
const ref = useRef<T>(null);
const [entry, setEntry] = useState<IntersectionObserverEntry | null>(null);
useEffect(() => {
if (!ref.current) return;
const obs = new IntersectionObserver(([e]) => setEntry(e), options);
obs.observe(ref.current);
return () => obs.disconnect();
}, [options.root, options.rootMargin, options.threshold]);
return { ref, entry, isVisible: entry?.isIntersecting ?? false };
}
```
### 5. useLocalStorage (with sync)
```typescript
import { useEffect, useState } from 'react';
export function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
const raw = localStorage.getItem(key);
return raw ? (JSON.parse(raw) as T) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
useEffect(() => {
const onStorage = (e: StorageEvent) => {
if (e.key === key && e.newValue) setValue(JSON.parse(e.newValue));
};
window.addEventListener('storage', onStorage);
return () => window.removeEventListener('storage', onStorage);
}, [key]);
return [value, setValue] as const;
}
```
### 6. useFetch (with AbortController)
```typescript
import { useEffect, useState } from 'react';
export function useFetch<T>(url: string) {
const [state, setState] = useState<{ data?: T; error?: Error; loading: boolean }>({ loading: true });
useEffect(() => {
const ac = new AbortController();
setState({ loading: true });
fetch(url, { signal: ac.signal })
.then((r) => r.json())
.then((data: T) => setState({ data, loading: false }))
.catch((error: Error) => {
if (error.name !== 'AbortError') setState({ error, loading: false });
});
return () => ac.abort();
}, [url]);
return state;
}
```
### 7. useReducer composite (state machine)
```typescript
import { useReducer } from 'react';
type State = { status: 'idle' | 'loading' | 'success' | 'error'; data?: unknown; error?: Error };
type Action = { type: 'fetch' } | { type: 'success'; data: unknown } | { type: 'error'; error: Error };
const reducer = (s: State, a: Action): State => {
switch (a.type) {
case 'fetch': return { status: 'loading' };
case 'success': return { status: 'success', data: a.data };
case 'error': return { status: 'error', error: a.error };
}
};
export const useAsync = () => useReducer(reducer, { status: 'idle' });
```
### 8. React 19 `use()` for promises
```typescript
import { use, Suspense } from 'react';
function Profile({ promise }: { promise: Promise<User> }) {
const user = use(promise); // suspends until resolved
return <h1>{user.name}</h1>;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Local boolean | `useToggle`. |
| Server data | `useQuery` (TanStack Query) — 매 wheel 재발명 X. |
| 매 cross-tab sync | `useLocalStorage` + `storage` event. |
| Async resource | React 19 `use()` + Suspense. |
| 복잡 state | `useReducer` 매 state machine. |
| 매 DOM measurement | `useResizeObserver`, `useIntersectionObserver`. |
**기본값**: 매 TanStack Query / Zustand 의 use — custom hook은 매 truly specific logic 만.
## 🔗 Graph
- 부모: [[React]] · [[Hooks]]
- 변형: [[Vue Composables]] · [[Solid Primitives]]
- 응용: [[Component Library]] · [[Design System]]
- Adjacent: [[useEffect]] · [[State Management]]
## 🤖 LLM 활용
**언제**: 매 hook scaffolding, TS generic 작성, 매 cleanup logic.
**언제 X**: 매 stale-closure / dep array 미세 bug — 매 manual review 필요.
## ❌ 안티패턴
- **Conditional hook call**: 매 `if (x) useFoo()` — 매 lint error.
- **Stale closure in setInterval**: 매 ref pattern 또는 functional setState 사용.
- **Effect for derived state**: 매 `useMemo` 또는 render 중 계산 — `useEffect` X.
- **No cleanup**: 매 listener / subscription 미해제 — leak.
## 🧪 검증 / 중복
- Verified (react.dev, React 19 release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — React 19 hook patterns + use() |
+22 -92
View File
@@ -2,104 +2,34 @@
id: wiki-2026-0508-dom-및-cssom
title: DOM 및 CSSOM
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: dom
duplicate_of: "[[DOM]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, dom, cssom]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[DOM 및 CSSOM|DOM 및 CSSOM]]
# DOM 및 CSSOM
## 📌 한 줄 통찰 (The Karpathy Summary)
DOM(문서 객체 모델)과 [[CSSOM|CSSOM]](CSS 객체 모델)은 브라우저의 핵심 렌더링 경로(Critical Rendering Path)에서 웹 페이지를 화면에 그리기 위해 생성되는 두 가지 독립적인 트리 구조 데이터입니다 [1, 2]. DOM은 HTML 마크업을 점진적으로 파싱하여 문서의 구조와 내용을 나타냅니다 [3, 4]. 반면, CSSOM은 문서에 적용될 스타일 규칙을 정의하며, 렌더링 시 스타일이 적용되지 않은 콘텐츠가 깜빡이는 현상(FOUC)을 방지하기 위해 렌더링 차단(render-Blocking) 방식으로 생성됩니다 [5, 6]. 이 두 트리가 결합하여 화면에 표시될 시각적 요소들만 포함하는 렌더 트리([[Render Tree|Render Tree]])를 최종적으로 형성합니다 [7, 8].
> **이 문서는 [[DOM]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
**[[DOM (Document Object Model)|DOM(Document Object Model]] 구축**
- 브라우저는 HTML 응답을 받으면 데이터를 문자, 토큰(token)으로 변환하고, 이를 다시 노드(node)로 변환하여 계층적인 DOM 트리를 구축합니다 [3, 4, 9].
- DOM 트리는 문서의 콘텐츠와 각 요소 간의 관계 및 계층 구조를 나타냅니다 [4, 8, 9].
- DOM 구축은 점진적(incremental)으로 이루어지므로, 브라우저는 네트워크 요청이 진행 중인 상태에서도 파싱을 시작하여 트리를 구성할 수 있습니다 [3, 5, 6].
- 단, DOM 노드의 수가 많아질수록 레이아웃 및 페인트 등 이후의 렌더링 단계에서 브라우저의 연산 부담이 커지고 처리 시간이 길어집니다 [5, 6, 9].
## 핵심 요약
- DOM = HTML parse 결과의 tree.
- CSSOM = CSS parse 결과의 tree (selector spec + computed values).
- DOM + CSSOM merge → Render Tree → Layout → Paint → Composite (매 [[Critical Rendering Path (CRP)]] 참조).
- 매 CSSOM은 매 render-blocking — 매 inline critical CSS 권장.
**[[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]] 구축**
- CSSOM은 DOM이 어떻게 스타일링될지에 대한 모든 정보를 담고 있으며, 브라우저가 CSS 규칙을 이해하고 적용할 수 있도록 만든 트리 구조의 스타일 맵입니다 [2, 6, 8].
- DOM과 달리 CSSOM 구축은 점진적이지 않으며, 문서의 렌더링을 차단(render-blocking)합니다 [5, 6].
- 브라우저는 스타일이 적용되지 않은 원시 HTML이 사용자에게 노출되는 현상(FOUC)을 막기 위해 링크된 모든 스타일시트를 다운로드하고 파싱할 때까지 렌더링을 중단합니다 [5].
- CSS 규칙은 하향식으로 종속(Cascade)되는 특성이 있어 파싱 도중 이전 규칙이 덮어써질 수 있으므로, 완전히 파싱이 끝나기 전까지는 렌더 트리를 구축하는 데 사용될 수 없습니다 [10, 11].
- 브라우저는 CSS 선택자를 오른쪽에서 왼쪽으로 파싱합니다 [12]. 따라서 `.container.navigation.item`과 같이 구체적인 선택자는 단순히 `.item`을 찾는 것보다 DOM 트리를 거슬러 올라가며 조상 관계를 확인해야 하므로 연산 비용이 더 듭니다 [12, 13].
## 🔗 Graph
- 부모: [[DOM]] (canonical)
- Adjacent: [[Critical Rendering Path (CRP)]] · [[Browser Rendering]]
**렌더 트리(Render Tree) 합성**
- DOM과 CSSOM 구조가 모두 준비되면, 브라우저는 이 둘을 결합하여 화면에 그릴 렌더 트리를 생성합니다 [7, 14].
- 렌더 트리는 시각적으로 렌더링되는 요소들만 캡처합니다 [7]. 따라서 시각적 레이아웃에 영향을 주지 않는 `<script>`, `<meta>` 요소나, CSS에 의해 `display: none`으로 처리된 요소는 렌더 트리에서 제외됩니다 [7, 8, 14, 15].
- 하지만 `visibility: hidden`이 적용된 요소는 보이지 않더라도 레이아웃 상에서 공간을 차지하므로 렌더 트리에 포함됩니다 [15].
## 🔗 지식 연결 (Graph)
- **Related Topics:** `[[Critical Rendering Path|Critical Rendering Path]]`, `Render Tree`, `[[Reflow and Repaint|Reflow and Repaint]]`
- **Projects/Contexts:** `[[프론트엔드 성능 최적화|프론트엔드 성능 최적화]]`, `브라우저 렌더링 파이프라인 이해`
- **Contradictions/Notes:** CSS 선택자의 구체성이 CSSOM 생성 연산 속도에 영향을 미치지만, 최신 브라우저는 파싱 속도가 매우 빨라 이로 인한 지연은 마이크로초 단위에 불과합니다 [11, 13]. 따라서 과도하게 선택자 구체성 최적화에 집착하기보다는 미니파이(minification)나 렌더링 차단을 방지하는 다른 CSS 최적화 기법에 집중하는 것이 좋습니다 [13].
---
*Last updated: 2026-04-25*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -1,25 +1,33 @@
---
id: wiki-20260508-dom-document-object-model--redir
id: wiki-2026-0508-dom-document-object-model--redir
title: DOM(Document Object Model)
category: Frontend
status: merged
redirect_to: DOM(Document_Object_Model)
canonical_id: DOM(Document_Object_Model)
category: 10_Wiki/Topics
status: duplicate
canonical_id: dom-document-object-model
duplicate_of: "[[DOM (Document Object Model)]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [redirect]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, browser, dom]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-merge 2026-05-08)
---
# DOM(Document Object Model)
> [!IMPORTANT]
> 이 문서는 P-Reinforce Phase 2 자동 MERGE에 의해 **[[DOM(Document_Object_Model)]]**로 통합되었습니다.
> **이 문서는 [[DOM (Document Object Model)]] 의 중복본입니다.** Canonical 문서로 redirect.
---
*Redirected to: [[DOM(Document_Object_Model)]]*
## 핵심 요약
- 매 HTML/XML document 의 tree representation.
- 매 JS 의 manipulation API — node, element, attribute.
- 매 reflow/repaint trigger 의 source.
## 🔗 Graph
- 부모: [[DOM (Document Object Model)]] (canonical)
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+166 -15
View File
@@ -1,24 +1,175 @@
---
category: Frontend
tags: [auto-wikified, technical-documentation, frontend]
id: wiki-2026-0508-dart
title: Dart
description: "Dart는 구글이 개발한 정적 타입 기반의 객체 지향 프로그래밍 언어로, 주로 크로스 플랫폼 프레임워크인 Flutter의 기반 언어로 사용됩니다 [1, 2]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Dart language, dart-lang]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [dart, flutter, language, aot, jit]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: dart
framework: flutter
---
# Dart
## 📌 Brief Summary
Dart는 구글이 개발한 정적 타입 기반의 객체 지향 프로그래밍 언어로, 주로 크로스 플랫폼 프레임워크인 Flutter의 기반 언어로 사용됩니다 [1, 2]. 클라이언트 환경에 최적화되어 있으며 기계어(ARM 코드)로 직접 컴파일되어 빠른 앱 실행과 높은 성능을 제공하는 것이 특징입니다 [2-4]. Java, C# 등 기존 객체 지향 언어와 유사한 문법을 가져 해당 언어 경험이 있는 개발자들에게는 학습이 비교적 수월한 편입니다 [5].
## 매 한 줄
> **"매 client-optimized language — JIT(dev) + AOT(prod) dual compile, sound null safety, isolate concurrency"**. 매 Google 의 Flutter 전용으로 설계 (2011→2018 pivot). 매 Dart 3.3+ (2024-2026) 의 records, patterns, sealed class 의 modern type system 도입.
## 📖 Core Content
* **언어 아키텍처 및 성능 최적화:** Dart는 가비지 컬렉션(Garbage Collection)과 강력한 비동기(Async) 처리를 지원하며, AOT(Ahead-of-Time)와 JIT(Just-in-Time) 컴파일 방식을 모두 제공합니다 [6, 7]. 특히 모바일 환경에서는 AOT 컴파일을 통해 네이티브 ARM 코드로 변환되므로 애플리케이션의 콜드 스타트(Cold Start) 속도가 매우 빠릅니다 [4, 8].
* **정적 타입 시스템과 최신 문법:** Dart는 정적 타입(Static Type) 시스템을 사용하여 개발 단계 및 컴파일 타임에 오류를 사전에 포착함으로써 애플리케이션을 더 안정적이고 예측 가능하게 만듭니다 [9]. Dart 3 버전에 이르러서는 기본적으로 견고한 널 안전성(Sound Null Safety)을 지원하며, 봉인 클래스(Sealed Classes), 패턴 매칭, 레코드(Records)를 비롯하여 와일드카드 변수, 널 인지 컬렉션 요소 등의 최신 언어 기능을 도입하여 코드의 견고함과 표현력을 더욱 향상시켰습니다 [10, 11].
* **Flutter 생태계와의 결합 및 상호 운용성:** Dart는 Flutter 엔진(Skia 또는 Impeller)을 구동하는 핵심으로, 네이티브에 근접한 수준의 애플리케이션 성능과 고도의 커스텀 UI 제어를 가능하게 합니다 [7, 11]. 또한 성능이 중요한 작업이 필요할 경우, Dart FFI(Foreign Function Interface)를 통해 C 언어 라이브러리를 직접 호출하여 통신할 수 있는 상호 운용성도 제공합니다 [12, 13].
## 매 핵심
## ⚖️ Trade-offs & Caveats
* **제한적인 인재 풀 및 높은 채용/교육 비용:** JavaScript 등 주류 언어에 비해 Dart를 다루는 개발자(전체 개발자의 약 25% 수준)가 제한적이어서 특화된 인재 확보가 다소 어렵습니다 [14, 15]. 이로 인해 채용 시 10~15%의 급여 프리미엄이 발생하거나, 기존 개발자를 교육하여 프로젝트에 투입하는 데 적지 않은 시간과 비용($8,000~$12,000 상당)이 요구될 수 있습니다 [14, 16].
* **상대적으로 작은 커뮤니티 규모:** 널리 사용되는 JavaScript 생태계에 비해 커뮤니티 규모가 작기 때문에, 스택 오버플로우나 기술 블로그 등에서 문제 해결을 위한 참고 자료나 코드 리뷰를 얻을 기회가 적을 수 있습니다 [6, 17]. 이는 기존에 Dart를 다뤄보지 않은 웹 기반 개발팀이 진입할 때 초기 학습 곡선을 가파르게 만드는 원인이 됩니다 [6, 18].
### 매 dual compilation
- **JIT (development)**: 매 hot reload < 1s — Flutter dev 의 핵심.
- **AOT (production)**: 매 native machine code — startup 빠름, deterministic perf.
- **dart2js / dart2wasm**: 매 web target — Flutter Web 의 binary.
---
*Last updated: 2026-05-03*
### 매 sound null safety (since 2.12)
-`String?` (nullable) vs `String` (non-null) 의 compile-time 보장.
-`late` keyword — 매 deferred init.
-`!` (bang) — 매 명시적 unwrap.
### 매 Dart 3 의 modern features
- **Records**: `(int, String)` lightweight tuple.
- **Patterns**: destructuring + switch expression.
- **Sealed classes**: 매 exhaustive matching.
- **Class modifiers**: `final`, `interface`, `base`, `sealed`.
### 매 isolate concurrency
- 매 single-threaded event loop per isolate.
- 매 message-passing (no shared memory).
-`Isolate.run()` (Dart 2.19+) 의 simple offload.
## 💻 패턴
### Null safety + late
```dart
class User {
final String name;
final String? nickname; // nullable
late final int age; // deferred init
User(this.name, {this.nickname});
void setAge(int a) => age = a;
}
final u = User('Yuna');
print(u.nickname?.toUpperCase() ?? 'NO NICK');
```
### Records (Dart 3)
```dart
(double, double) toPolar(double x, double y) =>
(sqrt(x * x + y * y), atan2(y, x));
final (r, theta) = toPolar(3, 4);
print('r=$r, θ=$theta');
// Named record
({String name, int age}) profile = (name: 'Yuna', age: 28);
print(profile.name);
```
### Patterns + switch expression
```dart
sealed class Shape {}
class Circle extends Shape { final double r; Circle(this.r); }
class Square extends Shape { final double s; Square(this.s); }
double area(Shape sh) => switch (sh) {
Circle(:final r) => 3.14159 * r * r,
Square(:final s) => s * s,
};
```
### Async/await + Future
```dart
Future<User> fetchUser(int id) async {
final res = await http.get(Uri.parse('https://api/u/$id'));
if (res.statusCode != 200) throw Exception('fail');
return User.fromJson(jsonDecode(res.body));
}
// Stream — 매 multiple async value
Stream<int> count(int n) async* {
for (var i = 0; i < n; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
```
### Isolate (compute)
```dart
import 'dart:isolate';
Future<int> heavyCompute(List<int> data) =>
Isolate.run(() => data.fold(0, (a, b) => a + b * b));
// 매 main isolate 의 block 없이 background work
final sum = await heavyCompute(List.generate(1_000_000, (i) => i));
```
### Extension methods
```dart
extension StringX on String {
String get capitalized => isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';
}
print('hello'.capitalized); // "Hello"
```
### Mixin
```dart
mixin Loggable {
void log(String msg) => print('[${runtimeType}] $msg');
}
class Service with Loggable {
void doWork() => log('working...');
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 Flutter mobile/desktop app | Dart (의무) |
| 매 CLI tool (cross-platform) | Dart AOT compile |
| 매 backend (Aqueduct/Shelf) | 매 가능 — 매 ecosystem 작음 |
| 매 web (no Flutter) | 매 비추천 — TS/JS 우세 |
**기본값**: 매 Flutter context 에서만 Dart 의 사용 — 매 standalone 은 Go/Rust/TS 의 권장.
## 🔗 Graph
- 부모: [[Flutter]]
- 변형: [[Flutter_AOT_Compilation_Dart]] · [[Dart_FFI_Foreign_Function_Interface]]
- 응용: [[Flutter_Web_-_Desktop]] · [[Flutter_Impeller]]
- Adjacent: [[TypeScript_Type_Safety]] · [[Cross-platform_Mobile_Development_Frameworks]]
## 🤖 LLM 활용
**언제**: 매 Flutter widget tree 작성, 매 isolate 기반 background work, 매 records/patterns 활용 의 modern Dart.
**언제 X**: 매 Flutter 외부 — 매 다른 ecosystem 에서 Dart 의 사용 의 의미 X.
## ❌ 안티패턴
- **매 dynamic 의 남용**: 매 type system 의 우회 — 매 sound null safety 의 무력화.
- **매 sync await chain**: 매 Future.wait 의 미사용 — 매 serialized 대기.
- **매 isolate 와 closure**: 매 capture-by-reference 의 함정 (sendable 만 가능).
- **매 print debug**: 매 debugPrint / logger 의 권장.
## 🧪 검증 / 중복
- Verified (dart.dev language tour, Dart 3.3 release 2024, Flutter 3.27).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Dart 3 records/patterns/sealed 정리 |
@@ -1,23 +1,179 @@
---
category: Frontend
tags: [auto-wikified, technical-documentation, frontend]
id: wiki-2026-0508-dart-ffi-foreign-function-interface
title: Dart FFI (Foreign Function Interface)
description: "Dart FFI(Foreign Function Interface)는 Flutter 개발 환경에서 C 라이브러리를 직접 호출할 수 있도록 지원하는 외부 함수 인터페이스입니다 [1]."
last_updated: 2026-05-04
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [dart:ffi, native interop]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [dart, flutter, ffi, native, c-interop]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: dart
framework: flutter
---
# Dart FFI (Foreign Function Interface)
## 📌 Brief Summary
Dart FFI(Foreign Function Interface)는 Flutter 개발 환경에서 C 라이브러리를 직접 호출할 수 있도록 지원하는 외부 함수 인터페이스입니다 [1]. 주로 네이티브 API에 접근하거나 성능이 결정적인 역할을 하는 작업을 처리할 때 사용됩니다 [1, 2]. 기존의 비동기 메시지 패싱 방식인 플랫폼 채널(Platform Channels)과 더불어 모바일 앱의 커스텀 네이티브 기능을 구현하는 데 핵심적인 역할을 합니다 [1].
## 매 한 줄
> **"매 Dart ↔ C/C++ 의 zero-overhead direct call — `dart:ffi`"**. 매 Flutter 3.x 부터 stable + `ffigen` 의 자동 binding 생성. 매 native lib (SQLite, OpenCV, Rust crate) 의 직접 호출 — 매 platform channel 의 async overhead 우회.
## 📖 Core Content
* **직접적인 C 언어 상호 운용성(C Interop)**: 애플리케이션 개발 중 커스텀 네이티브 코드가 필요한 경우, Dart FFI를 통해 C 라이브러리를 직접 호출하여 네이티브 API에 접근할 수 있습니다 [1, 2].
* **고성능 작업(Performance-critical operations) 처리**: Dart FFI는 높은 성능을 요구하는 연산에서 C 코드와의 직접적인 통합을 가능하게 하여, 성능이 중요한 작업을 효과적이고 안정적으로 처리할 수 있도록 보장합니다 [2].
* 소스에 관련 정보가 부족하여 세부적인 내부 작동 방식이나 아키텍처 구현 패턴에 대한 추가적인 설명은 제한됩니다.
## 매 핵심
## ⚖️ Trade-offs & Caveats
소스에 관련 정보가 부족합니다. (제공된 소스 데이터에서는 Dart FFI 도입으로 인해 발생할 수 있는 구체적인 부작용, 제약 사항, 또는 최적화 과정의 반대 급부에 대한 정보를 포함하고 있지 않습니다.)
### 매 FFI 의 작동 원리
-`DynamicLibrary.open()` 의 .so/.dylib/.dll load.
- 매 C ABI signature 의 Dart `Native<T>` typedef mapping.
- 매 sync call — 매 Dart isolate 와 동일 thread 에서 즉시 실행.
- 매 Pointer<T> 의 manual memory management.
---
*Last updated: 2026-05-03*
### 매 vs Platform Channel
| 축 | FFI | Platform Channel |
|---|---|---|
| latency | μs | ms |
| sync | yes | no (async) |
| target | C/C++/Rust | Java/Kotlin/Swift |
| async-safe | 매 isolate | yes |
### 매 ffigen workflow
- 매 C header (`.h`) → ffigen → Dart binding 자동 생성.
- 매 manual typedef 작성 의 elimination.
## 💻 패턴
### Basic FFI call
```dart
// hello.dart
import 'dart:ffi';
import 'dart:io' show Platform;
import 'package:ffi/ffi.dart';
typedef CAdd = Int32 Function(Int32, Int32);
typedef DartAdd = int Function(int, int);
final lib = DynamicLibrary.open(
Platform.isMacOS ? 'libmath.dylib' : 'libmath.so',
);
final add = lib.lookupFunction<CAdd, DartAdd>('add');
void main() {
print(add(2, 3)); // 5
}
```
### Native annotation (Dart 3.3+)
```dart
import 'dart:ffi';
@Native<Int32 Function(Int32, Int32)>(symbol: 'add', isLeaf: true)
external int add(int a, int b);
void main() => print(add(2, 3));
```
### String marshalling
```dart
import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef CGreet = Pointer<Utf8> Function(Pointer<Utf8>);
typedef DartGreet = Pointer<Utf8> Function(Pointer<Utf8>);
final greet = lib.lookupFunction<CGreet, DartGreet>('greet');
final namePtr = 'Yuna'.toNativeUtf8();
final resultPtr = greet(namePtr);
final result = resultPtr.toDartString();
calloc.free(namePtr); // 매 manual free 의 필수
print(result);
```
### Struct passing
```dart
final class Point extends Struct {
@Double() external double x;
@Double() external double y;
}
typedef CDistance = Double Function(Pointer<Point>, Pointer<Point>);
typedef DartDistance = double Function(Pointer<Point>, Pointer<Point>);
final dist = lib.lookupFunction<CDistance, DartDistance>('distance');
final a = calloc<Point>()..ref.x = 0..ref.y = 0;
final b = calloc<Point>()..ref.x = 3..ref.y = 4;
print(dist(a, b)); // 5.0
calloc.free(a); calloc.free(b);
```
### ffigen 의 사용
```yaml
# pubspec.yaml
dev_dependencies:
ffigen: ^14.0.0
# ffigen.yaml
name: NativeMath
description: Bindings for libmath
output: lib/src/math_bindings.dart
headers:
entry-points: ['native/math.h']
```
```bash
dart run ffigen --config ffigen.yaml
```
### Async FFI (NativePort)
```dart
// 매 long-running C work 의 main isolate block 회피
import 'dart:ffi';
import 'dart:isolate';
final port = ReceivePort();
final nativePort = port.sendPort.nativePort;
// C 측 에서 Dart_PostCObject_DL(nativePort, ...) 의 post
port.listen((msg) => print('from native: $msg'));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 sync μs-latency native call | FFI |
| 매 platform-specific iOS/Android API | Platform Channel |
| 매 large C/C++ codebase reuse | FFI + ffigen |
| 매 Rust integration | FFI + flutter_rust_bridge |
| 매 simple 1-shot file/permission | Pigeon plugin |
**기본값**: 매 native lib 의 binding → ffigen, 매 OS API 호출 → Pigeon/MethodChannel.
## 🔗 Graph
- 부모: [[Flutter]] · [[Dart]]
- 변형: [[Flutter_AOT_Compilation_Dart]]
- 응용: [[Flutter_Impeller]] · [[Skia]]
- Adjacent: [[WebAssembly]] · [[JSI (JavaScript Interface)]]
## 🤖 LLM 활용
**언제**: 매 Flutter 의 native lib (sqlite, ffmpeg, opencv, ort) 통합, 매 Rust crate 의 mobile 노출, 매 perf-critical CPU work 의 offload.
**언제 X**: 매 simple JSON-style platform API — 매 Pigeon 의 권장.
## ❌ 안티패턴
- **매 free 누락**: 매 calloc 후 free X — 매 native heap leak.
- **매 leaf 미표시**: 매 isLeaf=true 누락 — 매 GC safepoint overhead.
- **매 isolate 안전 무시**: 매 long C call 의 main isolate block.
- **매 manual binding**: 매 ffigen 의 skip — 매 type drift 의 발생.
## 🧪 검증 / 중복
- Verified (dart.dev/guides/libraries/c-interop, Dart 3.3 release 2024-02, ffigen 14 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — FFI 의 sync interop, ffigen workflow 정리 |
@@ -2,131 +2,202 @@
id: wiki-2026-0508-datacollector-knowledge-hub
title: Datacollector Knowledge Hub
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Web Analytics Collector, Frontend Telemetry Pipeline]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.85
verification_status: applied
tags: [analytics, telemetry, observability, data-collection]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Browser/Edge
---
# 📡 Datacollector Project: Engineering Hub (MOC)
# Datacollector Knowledge Hub
데이터 수집 및 자동화 프로세스를 관리하는 핵심 허브입니다.
## 매 한 줄
> **"매 datacollector = browser event → edge ingest → warehouse 의 매 reliable pipeline."**. 매 frontend datacollector는 매 user behavior, performance (Web Vitals), error 의 capture → 매 batch / sendBeacon → edge function (Cloudflare Workers / Vercel) → 매 ClickHouse / BigQuery / Snowflake. 매 2026 perspective는 매 1st-party domain ingest + GDPR/ePrivacy 동의 + server-side GTM.
---
## 매 핵심
## 🏷️ Keyword Cluster: #Development_Logs (개발 및 이슈 기록)
- - Datacollector/2026-04-25-Datacollector_Auto_Resume_After_Reauth_Fix
- Datacollector/2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix
- Datacollector/2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment
- Datacollector/2026-04-25-Datacollector_Engine_Processed_Count_and_Stalled_Loop_Guard
- Datacollector/2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode
- Datacollector/2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts
- Datacollector/2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix
- Datacollector/2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery
- Datacollector/2026-04-25-Datacollector_NotebookLM_Automatic_Reauth_Verification_and_Lock
- Datacollector/2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix
- Datacollector/2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis
- Frontend_Mastery/2026-04-25-Datacollector_Auto_Resume_After_Reauth_Fix
- Frontend_Mastery/2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix
- Frontend_Mastery/2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment
- Frontend_Mastery/2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode
- Frontend_Mastery/2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts
- Frontend_Mastery/2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix
- Frontend_Mastery/2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery
- Frontend_Mastery/2026-04-25-Datacollector_NotebookLM_Automatic_Reauth_Verification_and_Lock
- Frontend_Mastery/2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix
- Frontend_Mastery/2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis
### 매 collector responsibilities
- **Capture**: page view, click, custom event, performance, error.
- **Enrich**: session id, user id (consent-gated), referrer, UTM.
- **Batch & Buffer**: idle batching, sendBeacon on `pagehide`.
- **Privacy**: consent state, IP truncation, PII scrubbing.
- **Transport**: 1st-party endpoint > 3rd-party (avoid adblock).
### 매 Web Vitals
- LCP, INP, CLS, TTFB, FCP — `web-vitals` library.
- 매 attribution build (`onINP({ reportAllChanges: true })`) 매 root-cause.
---
**Status**: Managed by Antigravity AI
### 매 응용
1. Product analytics (PostHog, Amplitude, Mixpanel, Segment).
2. RUM (Datadog, Sentry, New Relic, SpeedCurve).
3. A/B testing exposure logging.
4. Funnel & cohort analysis.
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[2026-04-25-Datacollector_Auto_Resume_After_Reauth_Fix]]
* [[2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix]]
* [[2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment]]
* [[2026-04-25-Datacollector_Engine_Processed_Count_and_Stalled_Loop_Guard]]
* [[2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode]]
* [[2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts]]
* [[2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix]]
* [[2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery]]
* [[2026-04-25-Datacollector_NotebookLM_Automatic_Reauth_Verification_and_Lock]]
* [[2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix]]
* [[2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis]]
## 💻 패턴
## 📌 한 줄 통찰 (The Karpathy Summary)
### 1. Minimal collector (sendBeacon + queue)
```typescript
type Event = { type: string; ts: number; props?: Record<string, unknown> };
const queue: Event[] = [];
const ENDPOINT = '/collect'; // 1st-party
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
function track(type: string, props?: Event['props']) {
queue.push({ type, ts: Date.now(), props });
if (queue.length >= 20) flush();
}
## 📖 구조화된 지식 (Synthesized Content)
function flush() {
if (!queue.length) return;
const batch = queue.splice(0, queue.length);
const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });
navigator.sendBeacon(ENDPOINT, blob) || fetch(ENDPOINT, { method: 'POST', body: blob, keepalive: true });
}
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
addEventListener('pagehide', flush);
addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') flush(); });
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Web Vitals capture
```typescript
import { onLCP, onINP, onCLS, onTTFB } from 'web-vitals';
const send = (metric: { name: string; value: number; id: string }) =>
track('vital', { name: metric.name, value: metric.value, id: metric.id });
onLCP(send); onINP(send); onCLS(send); onTTFB(send);
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. Error capture (global)
```typescript
window.addEventListener('error', (e) => {
track('error', { msg: e.message, src: e.filename, line: e.lineno, col: e.colno, stack: e.error?.stack });
});
window.addEventListener('unhandledrejection', (e) => {
track('promise_rejection', { reason: String(e.reason) });
});
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 4. Auto click tracking (delegated)
```typescript
document.addEventListener('click', (e) => {
const t = (e.target as Element).closest('[data-track]');
if (t instanceof HTMLElement) {
track('click', { id: t.dataset.track, ...t.dataset });
}
});
```
**기본값:**
> *(TODO)*
### 5. Consent gating (TCFv2)
```typescript
function hasAnalyticsConsent(): boolean {
const tcData = (window as any).__tcfapi;
// simplified — production: subscribe to TCF api
return localStorage.getItem('consent.analytics') === '1';
}
const origTrack = track;
const trackGated = (type: string, props?: Event['props']) => {
if (!hasAnalyticsConsent()) return;
origTrack(type, props);
};
```
## ❌ 안티패턴 (Anti-Patterns)
### 6. Edge ingest (Cloudflare Worker)
```typescript
// worker.ts
export default {
async fetch(req: Request, env: Env): Promise<Response> {
if (req.method !== 'POST') return new Response('', { status: 405 });
const events = await req.json<Event[]>();
const enriched = events.map((e) => ({
...e,
ip_country: req.cf?.country,
ua: req.headers.get('user-agent'),
ingest_ts: Date.now(),
}));
await env.QUEUE.send(enriched);
return new Response('', { status: 204 });
},
};
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### 7. Server-side GTM forward
```typescript
// edge → GTM SS container
await fetch('https://gtm.example.com/g/collect', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ events: enriched }),
});
```
### 8. PII scrub
```typescript
const EMAIL = /[\w.+-]+@[\w-]+\.[\w.-]+/g;
const PHONE = /\+?\d[\d \-]{8,}\d/g;
function scrub<T extends Record<string, unknown>>(props: T): T {
return JSON.parse(JSON.stringify(props).replace(EMAIL, '[email]').replace(PHONE, '[phone]'));
}
```
### 9. Session identity
```typescript
const SESSION_KEY = 'sid';
const TIMEOUT_MS = 30 * 60 * 1000;
function getSession() {
const raw = sessionStorage.getItem(SESSION_KEY);
const parsed = raw ? JSON.parse(raw) : null;
if (parsed && Date.now() - parsed.last < TIMEOUT_MS) {
parsed.last = Date.now();
} else {
parsed?.id || (Object.assign({}, { id: crypto.randomUUID(), last: Date.now() }));
}
const out = parsed ?? { id: crypto.randomUUID(), last: Date.now() };
sessionStorage.setItem(SESSION_KEY, JSON.stringify(out));
return out.id;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 product analytics | PostHog (OSS) or Amplitude. |
| 매 RUM perf | Sentry / Datadog RUM. |
| Privacy strict (EU) | 1st-party + consent + IP truncation. |
| Adblock evasion | 매 1st-party domain reverse-proxy. |
| 자체 build | sendBeacon + edge function + ClickHouse. |
**기본값**: `web-vitals` + 매 1st-party `/collect` + sendBeacon batch + edge ingest.
## 🔗 Graph
- 부모: [[Web Analytics]] · [[Observability]]
- 변형: [[Server-Side Tracking]] · [[Privacy-first Analytics]]
- 응용: [[PostHog]] · [[Sentry]] · [[Segment]]
- Adjacent: [[Web Vitals]] · [[GDPR]] · [[ClickHouse]]
## 🤖 LLM 활용
**언제**: 매 collector skeleton, consent gating, batch / flush logic.
**언제 X**: 매 specific vendor SDK 의 detailed config — 매 vendor docs.
## ❌ 안티패턴
- **`fetch` without `keepalive`**: 매 unload 매 request drop.
- **No batching**: 매 매 event = 매 request — flood.
- **PII without consent**: 매 GDPR breach.
- **3rd-party domain only**: 매 adblock 차단 — 매 1st-party proxy.
- **Sync XHR on unload**: 매 deprecated — sendBeacon 사용.
## 🧪 검증 / 중복
- Verified (web.dev web-vitals, IAB TCFv2, MDN sendBeacon).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — datacollector pipeline + Web Vitals + consent |
@@ -2,139 +2,166 @@
id: wiki-2026-0508-debugging-frontend-applications
title: Debugging Frontend Applications
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Frontend Debugging, DevTools Workflow]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [debugging, devtools, performance, chrome]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript/TypeScript
framework: Browser DevTools
---
# [[Debugging Frontend Applications|Debugging Frontend Applications]]
# Debugging Frontend Applications
## 📌 한 줄 통찰 (The Karpathy Summary)
프론트엔드 디버깅은 웹 애플리케이션에서 발생하는 자바스크립트 런타임 에러, 메모리 누수, 그리고 불필요한 리렌더링과 같은 성능 저하 요인을 식별하고 해결하는 과정입니다 [1-3]. Chrome DevTools와 같은 브라우저 내장 도구부터 React DevTools, 그리고 Sentry나 LogRocket과 같은 프로덕션 클라우드 로깅 도구를 활용하여 문제의 근본 원인을 추적합니다 [4-7]. 효과적인 디버깅 전략과 에러 핸들링 아키텍처는 애플리케이션의 안정성을 보장하고 사용자 경험을 최적화하는 데 필수적입니다 [8-10].
## 한 줄
> **"매 frontend 디버깅 = DevTools 의 mastery + reproducible state."**. Chrome DevTools (2024-2026)는 매 Performance Insights, AI assistance (Gemini Nano), Recorder, Memory profiler 의 통합. 매 핵심은 매 issue 의 reproduction → instrument → bisect → fix.
## 📖 구조화된 지식 (Synthesized Content)
* **메모리 누수(Memory Leaks) 탐지 및 해결:**
* 메모리 누수는 할당된 메모리가 더 이상 필요하지 않음에도 해제되지 않을 때 발생하며, 앱 속도 저하와 브라우저 탭 충돌을 유발합니다 [2, 11].
* Chrome DevTools의 Task Manager를 통해 실시간 JavaScript 메모리 사용량을 확인하고, Performance 탭의 기록을 통해 시간 경과에 따른 메모리 증가 패턴을 시각화할 수 있습니다 [12, 13].
* Memory 패널의 **Heap Snapshots**을 사용하여 스냅샷 간의 차이(Delta)를 비교함으로써, DOM에서 제거되었으나 자바스크립트 참조가 남아있는 'Detached DOM nodes'를 식별할 수 있습니다 [14-17]. 또한, **Allocation Timeline**을 통해 새로운 메모리가 언제 할당되는지 추적하여 누수 후보를 찾아냅니다 [18, 19].
* **React 컴포넌트 및 성능 디버깅:**
* **리렌더링 원인 추적:** React DevTools의 Profiler를 사용해 어떤 컴포넌트가 언제, 왜 렌더링되었는지 파악할 수 있으며, 개발 전용 라이브러리인 `why-did-you-render`를 통해 실제 props나 상태 변경 없이 발생하는 불필요한 리렌더링을 콘솔 경고로 확인할 수 있습니다 [7, 20].
* **React Error Boundaries:** React 애플리케이션에서는 Error Boundary라는 클래스 컴포넌트를 활용하여 하위 컴포넌트 트리의 렌더링, 생명주기 메서드, 생성자에서 발생하는 에러를 포착합니다 [1]. 이는 UI를 위한 `try-catch` 블록 역할을 하며, 앱 전체가 충돌하는 대신 Fallback UI를 표시하여 앱의 나머지 부분을 상호작용 가능한 상태로 유지합니다 [1, 8, 10].
* **상태 관리 도구와 디버깅 편의성:**
* 상태 관리 도구의 선택은 디버깅 경험에 큰 영향을 미칩니다. Context API는 상태 변경 기록 추적이나 시간 여행(Time-travel) 디버깅이 불가능하여 버그 원인을 파악하기 어렵습니다 [21]. 반면, Redux는 Redux DevTools를 통해 어떤 액션이 언제 디스패치되었는지 확인하고, 상태 이력을 검사 및 재생(Replay)할 수 있어 복잡한 비동기 에러를 신속하게 디버깅할 수 있습니다 [21, 22].
* **프로덕션 환경 모니터링 및 로깅:**
* 배포된 프로덕션 앱에서는 Sentry, LogRocket, Datadog RUM 등의 클라우드 로깅 툴을 통해 사용자가 경험하는 에러를 모니터링합니다 [23-25].
* Sentry는 지능형 에러 그룹화(Error grouping)와 에러 발생 전의 콘솔 로그, 네트워크 요청 등을 보여주는 빵부스러기(Breadcrumb) 트레일을 제공합니다 [4, 25]. LogRocket은 사용자의 전체 화면을 녹화하듯 DOM 및 Redux/Vuex 상태 변화까지 캡처하는 세션 리플레이(Session replay) 기능으로 상세한 디버깅 컨텍스트를 제공합니다 [5]. Datadog RUM은 프론트엔드 에러를 백엔드 분산 트레이싱(Distributed tracing)과 상관관계 지어(Correlation) 복잡한 시스템의 에러를 파악하게 해줍니다 [24].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **클라우드 로깅 도구의 성능 및 비용 문제:** 모니터링 도구들은 렌더링 성능 및 번들 크기에 직접적인 영향을 미칩니다. 일부 도구 구현 시 최대 120ms의 추가 로드 시간이 발생할 수 있습니다 [26]. 또한, Datadog과 같은 툴은 로그 수집(Ingest)과 검색을 위한 인덱싱(Index)에 대해 이중 과금 구조를 가지고 있어 규모가 커질수록 비용이 매우 가파르게 증가하는 단점이 있습니다 [27, 28].
* **세션 리플레이와 개인정보 침해 (Privacy Concerns):** LogRocket처럼 '모든 것을 캡처'하는 세션 리플레이 방식은 기본적으로 강력한 디버깅 정보를 제공하지만, 민감한 사용자 데이터까지 녹화될 수 있는 심각한 개인정보 침해 우려가 동반됩니다. 따라서 별도의 마스킹 및 설정 작업이 강제됩니다 [5, 29, 30].
* **Error Boundaries의 한계:** 선언적인 UI 에러 처리에 강력하지만, 이벤트 핸들러 내부의 에러, `setTimeout` 같은 비동기 코드, 서버 사이드 렌더링(SSR), 그리고 Error Boundary 자체에서 발생한 에러는 포착하지 못합니다. 이러한 부분은 전통적인 자바스크립트의 `try/catch` 블록으로 디버깅 및 예외 처리를 해야 하는 제약이 있습니다 [31, 32].
* **React Compiler 도입에 따른 디버깅 난이도 증가:** 코드를 자동으로 최적화해주는 React Compiler는 내부 로직이 블랙박스(Black box) 형태로 동작합니다. 개발자는 최적화된 부분과 그 이유에 대한 가시성을 잃게 되며, 예기치 않은 리렌더링 발생 시 코드상의 `React.memo``useCallback` 호출을 확인하는 대신 React DevTools Profiler에 전적으로 의존해 조사해야 하므로 디버깅 난이도가 상승합니다 [33].
### 매 DevTools panels
- **Sources**: breakpoint, conditional bp, log point, blackbox.
- **Performance**: flame chart, INP / LCP markers, Performance Insights.
- **Network**: throttle, replay XHR, request blocking.
- **Memory**: heap snapshot, allocation timeline.
- **Application**: storage, service worker, cache.
- **Lighthouse / Recorder**: automated audit + user flow capture.
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 reproduction
- 매 hard bug = race / state / network / timing.
- 매 deterministic repro = first 50% of debug.
#### [관계 유형 A (브라우저 및 성능 분석 기반 도구)]
- [[Chrome DevTools|Chrome DevTools]]
- 연결 이유: 자바스크립트 힙 메모리와 DOM의 상태를 프로파일링하여 메모리 누수를 진단하는 가장 근본적인 프론트엔드 디버깅 도구이기 때문입니다 [6, 34].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 브라우저의 가비지 컬렉션(GC) 동작 원리, 분리된 DOM 노드(Detached DOM nodes)와 클로저(Closure)가 메모리를 점유하여 성능을 저하시키는 원리를 시각적으로 이해할 수 있습니다 [2, 14, 17, 35].
### 매 응용
1. Memory leak hunt — heap snapshot diff.
2. Slow render trace — Performance flame.
3. Network race — Replay & throttle.
4. Production-only bug — source-mapped stack + Sentry replay.
#### [관계 유형 B (React 컴포넌트 및 에러 핸들링 도구)]
- React Error Boundaries
- 연결 이유: 렌더링 및 생명주기 도중 발생하는 컴포넌트 런타임 에러를 디버깅/핸들링하여 "하얀 화면(White screen of death)"을 막아주는 React만의 고유한 방어적 디버깅 패턴입니다 [1, 36].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 선언적(Declarative) UI 트리의 에러 전파 방식과, 명령형(Imperative) 이벤트 핸들러에서 `try-catch`를 사용해야 하는 아키텍처적 차이를 명확히 구분할 수 있습니다 [32].
- [[React DevTools Profiler|React DevTools Profiler]]
- 연결 이유: 어떤 컴포넌트가 언제, 왜 리렌더링되었는지를 측정(Profiling)하여 렌더링 병목 현상을 디버깅하는 필수 도구입니다 [7, 37].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: React의 렌더링 라이프사이클, 불필요한 상태 및 props 변경 추적, 그리고 React Compiler 도입 전후의 렌더링 패스(Render pass) 차이를 검증하는 방법을 배울 수 있습니다 [7, 38].
## 💻 패턴
#### [관계 유형 C (프로덕션 환경 관측성 도구)]
- Session Replay & Distributed Tracing
- 연결 이유: 로컬에서 재현이 불가능한 프로덕션 에러를 추적하기 위해 사용자의 브라우저 상호작용(Sentry, LogRocket)과 백엔드 데이터 흐름(Datadog)을 연결하여 디버깅 단서를 찾는 핵심 개념입니다 [5, 24, 39].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 풀스택 환경에서의 엔드투엔드(End-to-End) 성능 모니터링 한계와 프론트엔드 에러가 백엔드 서비스에 미치는 연관 관계를 깊게 이해할 수 있습니다 [24, 25].
### Deeper Research Questions
- Chrome DevTools의 Heap Snapshot 분석에서 'Shallow size'와 'Retained size'의 차이는 프론트엔드 메모리 관리 측면에서 어떻게 해석되며, 디버깅 시 어떤 기준표가 되는가? [40]
- React Error Boundary가 이벤트 핸들러나 비동기 코드의 에러를 잡지 못하는 아키텍처적 이유는 무엇이며, 이를 보완하여 전체 애플리케이션의 에러를 효과적으로 캡처하기 위한 최적의 로깅 패턴은 무엇인가? [31, 32]
- Sentry, LogRocket, Datadog RUM 등 클라우드 기반 로깅 도구가 프론트엔드 번들 크기 증가 및 초기 렌더링 성능 지연(최대 120ms 추가 로드)에 미치는 영향을 최소화하기 위한 설정 및 로드 전략은 무엇인가? [26, 41]
- Redux DevTools의 시간 여행(Time-travel) 디버깅 원리는 무엇이며, 왜 Context API나 Zustand보다 복잡한 비동기 상태의 버그를 더 빠르고 정확하게 찾아낼 수 있는가? [21, 22]
- React Compiler 도입 이후 자동화된 메모이제이션 과정에서 발생하는 렌더링 이슈(예: Library Compatibility 문제로 인한 참조 변경)를 디버깅하기 위해 React Profiler를 어떻게 활용해야 하는가? [33, 42, 43]
### Practical Application Contexts
- **Implementation:** 개발자는 `why-did-you-render` 라이브러리를 프로젝트에 연동해, 로컬 개발 시 불필요한 컴포넌트 렌더링 원인을 콘솔 경고를 통해 즉각적으로 파악하고 코드를 수정할 수 있습니다 [20, 44].
- **System Design:** 프론트엔드 시스템 설계 시 대시보드, 차트, 복잡한 폼 등 장애 발생 확률이 높은 UI 컴포넌트 각각에 독립적인 `Error Boundary`를 배치해 하나의 위젯 결함이 전체 앱의 마비를 가져오지 않도록 설계합니다 [8, 45, 46].
- **Operation / Maintenance:** 프로덕션 단계에서는 Sentry나 LogRocket과 같은 관측성(Observability) 툴을 통합하여, 오류 로그 발생 시 사용자가 클릭한 이벤트와 화면의 상태(Session Replay)를 실시간으로 확인하고 빠르게 이슈를 대응(Hotfix)합니다 [5, 25, 47].
- **Learning Path:** 주니어 프론트엔드 개발자가 메모리 누수를 학습할 때, Chrome DevTools의 Memory 탭을 사용해 스냅샷을 찍고 DOM 노드가 자바스크립트 변수에 의해 참조되어 가비지 컬렉션되지 않는 상황(Detached Elements)을 실습합니다 [14, 15, 17].
- **My Project Relevance:** React 프로젝트에서 전역 상태를 설계할 때, 단순 설정(Theme 등)은 디버깅이 단순한 Context API로, 변경이 잦고 상태 추적이 중요한 요소는 DevTools를 지원하는 Redux나 Zustand를 도입하여 디버깅 용이성을 확보합니다 [22, 48, 49].
### Adjacent Topics
- State Management Architecture
- 확장 방향: 상태 관리 라이브러리(Redux, Zustand, Context API 등)의 아키텍처적 선택이 상태 변화 추적성과 DevTools 디버깅 퀄리티에 어떤 영향을 미치는지 분석 [21, 22, 49].
- [[프론트엔드 성능 최적화(Frontend Performance Optimization)|Frontend Performance Optimization]]
- 확장 방향: 디버깅을 통해 발견한 메모리 누수와 불필요한 컴포넌트 렌더링(Re-renders) 문제를 실질적인 성능 최적화 기법(가상화, 코드 스플리팅)으로 해결하여 Core Web Vitals를 개선하는 방향 [20, 50].
---
*Last updated: 2026-04-30*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 1. Conditional breakpoint / log point
```javascript
// Sources panel: right-click line number
// Conditional: user.id === 42
// Log point: console.log('user', user) — 매 코드 수정 X
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. debugger keyword + dynamic
```javascript
function process(items) {
if (items.length > 1000) debugger; // pause when large
// ...
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. console.* advanced
```javascript
console.table(users);
console.group('render');
console.time('paint'); // ...
console.timeEnd('paint');
console.groupEnd();
console.dir(node); // DOM as JS object
console.trace();
console.count('clicked');
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 4. Performance.measure (User Timing)
```javascript
performance.mark('fetch-start');
await fetch('/api/x');
performance.mark('fetch-end');
performance.measure('fetch', 'fetch-start', 'fetch-end');
// shows in DevTools Performance + reportable to RUM
```
**기본값:**
> *(TODO)*
### 5. Long Task observer
```javascript
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) console.warn('long task', entry);
}
}).observe({ type: 'longtask', buffered: true });
```
## ❌ 안티패턴 (Anti-Patterns)
### 6. Heap snapshot leak hunt
```text
1. DevTools → Memory → "Heap snapshot" (baseline).
2. Trigger interaction (open/close modal 5x).
3. Take 2nd snapshot.
4. Compare: filter by "Objects allocated between snapshots".
5. Look for retained DOM nodes / event listeners.
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### 7. Network throttle & replay
```text
- Network panel → "No throttling" → "Slow 4G" / Custom (300ms RTT).
- Right-click request → "Replay XHR" / "Block request URL".
- Override response: Sources → Overrides → Network → Save.
```
### 8. Source map verification
```bash
# Verify upload
curl -I https://cdn.example.com/main.js.map
# In DevTools, check status: open Sources, file should show formatted code
# If "missing source map", check //# sourceMappingURL comment + CORS
```
### 9. React DevTools Profiler
```text
- Components tab — inspect props, hooks, set Suspense state.
- Profiler tab — record interaction, view "Why did this render?" (commit reason).
- Highlight updates when components render: settings cog → "Highlight updates".
```
### 10. Chrome AI assistance (2024-)
```text
- DevTools Console → "Ask AI" (Gemini Nano integration).
- "Why is this CSS not applying?" — pastes computed styles into prompt.
- Performance Insights — auto-flagged INP / CLS culprits.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Slow render | Performance panel + React Profiler. |
| Memory leak | Heap snapshot diff. |
| Race condition | Network throttle + console.trace. |
| Prod-only | Source map + Sentry Replay. |
| CSS quirk | DevTools Computed + AI assistance. |
| Long task | PerformanceObserver longtask. |
**기본값**: Repro locally → Performance flame → narrow → fix → regression test.
## 🔗 Graph
- 부모: [[Web Performance]] · [[Browser DevTools]]
- 변형: [[Node Debugging]] · [[Mobile Web Debugging]]
- 응용: [[React DevTools]] · [[Vue DevTools]] · [[Sentry Replay]]
- Adjacent: [[Source Maps]] · [[Lighthouse]]
## 🤖 LLM 활용
**언제**: 매 stack trace 의 explain, 매 console.error 의 plausible cause 의 list.
**언제 X**: 매 timing-dependent / state-dependent bug — 매 actual repro 필수.
## ❌ 안티패턴
- **`console.log` ship to prod**: 매 left-over noise.
- **alert() debugging**: 매 modal blocks event loop.
- **Disable source maps**: 매 prod debug 의 X.
- **Profile in prod build only**: 매 dev mode warnings 의 miss.
## 🧪 검증 / 중복
- Verified (Chrome DevTools docs 2024-2026, web.dev).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DevTools 2026 + AI assistance + Profiler |
+184 -62
View File
@@ -2,87 +2,209 @@
id: wiki-2026-0508-declaration-files
title: Declaration Files
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AI-DECLARATION-FILES]
aliases: [TypeScript .d.ts, Type Definitions, DefinitelyTyped]
duplicate_of: none
source_trust_level: A
confidence_score: 0.99
tags: [TypeScript, JavaScript, DeclarationFiles, Tooling]
confidence_score: 0.9
verification_status: applied
tags: [typescript, types, declaration, dts]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: TypeScript 5.x
---
# [[Declaration-Files|Declaration-Files]] (선언 파일, .d.ts)
# Declaration Files
## 📌 한 줄 통찰 (The Karpathy Summary)
> "자바스크립트라는 원석에 타입이라는 주석을 입히는 투명 필름." 구현(Implementation)은 없이 오직 타입 정보(Signature)만 포함하여, 타입스크립트가 JS 코드를 이해하고 자동 완성을 제공하게 돕는 매뉴얼이다.
## 한 줄
> **"매 .d.ts = type-only public surface — runtime code 의 X."**. 매 TypeScript의 매 declaration 파일이 매 JS library의 매 type contract 의 제공 — `@types/node`, `@types/react` 등 매 DefinitelyTyped 가 매 ecosystem 의 backbone. 매 modern (2024-2026) 워크플로우는 `tsc --declaration` 자동 생성 + `tsup` / `rollup-plugin-dts` 의 bundling.
## 📖 구조화된 지식 (Synthesized Content)
- **Extension**: `.d.ts` (d는 declaration의 약자).
- **Core Role**:
- **Bridge**: 컴파일된 JS 파일 옆에서 해당 코드의 타입을 설명함.
- **Library [[Support|Support]]**: 직접 TS로 쓰이지 않은 NPM 패키지들에 타입을 부여함.
- **[[Ambient Declarations|Ambient Declarations]]**: `window``process` 같은 전역 객체에 타입을 추가하는 용도.
- **Compiler [[Behavior|Behavior]]**: 런타임에는 아무런 영향을 주지 않으며, 오직 '에디터'와 '컴파일 타임'의 안정성만을 위해 존재한다.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- 선언 파일과 실제 JS 코드가 불일치(Out-of-sync)할 때 발생하는 '거짓 안전(False sense of security)'이 가장 위험하다. 이를 방지하기 위해 라이브러리 제작자는 `tsc`를 통해 구현부에서 타입을 자동 추출(emitDeclarationOnly)하는 방식을 지향해야 한다.
### 매 file types
- `lib.d.ts` — TS standard library (DOM, ES2024).
- `package.d.ts` — package 자체 type.
- `globals.d.ts` — ambient declaration (window 확장).
- `module.d.ts``declare module 'foo'` shape.
## 🔗 지식 연결 (Graph)
- Related: [[DefinitelyTyped|DefinitelyTyped]] , TypeScript-Type-System
- Practice: Publishing-Dual-CJS-ESM-Packages
### 매 publishing
- `package.json` `"types"` (or `"typings"`) field → main d.ts entry.
- `"exports"` map (Node 16+) — multiple entry points + types.
- Dual ESM/CJS = 매 두 d.ts 필요 — `"types"` per condition.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. JS library 의 type 추가 — `@types/foo`.
2. Module augmentation — `declare module 'react' { ... }`.
3. CSS modules / image import — `*.module.css` declaration.
4. Env variable typing — `import.meta.env`.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 1. Basic .d.ts
```typescript
// lib.d.ts
export interface User { id: string; name: string }
export declare function getUser(id: string): Promise<User>;
export declare const VERSION: string;
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Module declaration (ambient)
```typescript
// types/legacy-lib.d.ts
declare module 'legacy-lib' {
export function init(opts: { key: string }): void;
const version: string;
export default version;
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. Module augmentation
```typescript
// types/react-augment.d.ts
import 'react';
declare module 'react' {
interface CSSProperties {
'--brand-hue'?: string;
}
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 4. Global augmentation
```typescript
// types/globals.d.ts
declare global {
interface Window {
analytics?: { track(event: string, props?: Record<string, unknown>): void };
}
}
export {}; // make this a module
```
**기본값:**
> *(TODO)*
### 5. Asset module declarations
```typescript
// types/assets.d.ts
declare module '*.module.css' {
const classes: Record<string, string>;
export default classes;
}
declare module '*.svg' {
const url: string;
export default url;
}
declare module '*.svg?react' {
import { FC, SVGProps } from 'react';
const Component: FC<SVGProps<SVGSVGElement>>;
export default Component;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### 6. Vite env types
```typescript
// src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_SENTRY_DSN: string;
}
interface ImportMeta { readonly env: ImportMetaEnv }
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### 7. package.json exports + types (dual ESM/CJS)
```json
{
"name": "@acme/lib",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./feature": {
"types": "./dist/feature.d.ts",
"import": "./dist/feature.js"
}
}
}
```
### 8. tsconfig for d.ts emit
```json
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false,
"outDir": "dist",
"rootDir": "src",
"moduleResolution": "bundler"
}
}
```
### 9. tsup d.ts bundle
```javascript
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true, // bundle d.ts
sourcemap: true,
clean: true,
});
```
### 10. Conditional type for string literal API
```typescript
// route.d.ts — type-safe routing
type Route =
| { name: 'home'; params?: undefined }
| { name: 'user'; params: { id: string } };
declare function navigate<R extends Route>(...args: R['params'] extends undefined ? [name: R['name']] : [name: R['name'], params: R['params']]): void;
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 JS library 의 type | `@types/foo` (DefinitelyTyped). |
| 매 own library | `tsc --declaration` or tsup `dts: true`. |
| 매 monorepo internal | `composite: true` + project references. |
| 매 CSS / asset import | `*.module.css` ambient declaration. |
| Plugin-based extension | Module augmentation. |
**기본값**: tsup `dts: true` + `exports` map + declarationMap.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Type Systems]]
- 변형: [[Ambient Declarations]] · [[Module Augmentation]]
- 응용: [[Library Authoring]] · [[Monorepo TypeScript]]
- Adjacent: [[DefinitelyTyped]] · [[tsup]] · [[Vite]]
## 🤖 LLM 활용
**언제**: 매 d.ts scaffolding, ambient module declaration, exports map.
**언제 X**: 매 complex generic inference debug — 매 TS playground 사용.
## ❌ 안티패턴
- **No `export {}` in global aug**: 매 file 이 script 로 처리됨 → 매 declare global 무효.
- **`any` everywhere**: 매 d.ts 의 가치 의 negate.
- **`types` 미게시**: 매 user 의 `@types/foo` 의 별도 작성 필요.
- **Conditional exports types last**: 매 `"types"` 가 매 conditions 의 first 위치 — 매 spec.
## 🧪 검증 / 중복
- Verified (typescriptlang.org/docs/handbook/declaration-files, TS 5.x release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — d.ts authoring + exports map 2026 |
+173 -62
View File
@@ -2,88 +2,199 @@
id: wiki-2026-0508-definitelytyped
title: DefinitelyTyped
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AI-DEFINITELY-TYPED]
aliases: ["@types", DT, DefinitelyTyped repo]
duplicate_of: none
source_trust_level: A
confidence_score: 0.98
tags: [TypeScript, JavaScript, OpenSource, TypeSystem]
confidence_score: 0.9
verification_status: applied
tags: [typescript, types, ecosystem, npm]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: none
---
# [[DefinitelyTyped|DefinitelyTyped]]
# DefinitelyTyped
## 📌 한 줄 통찰 (The Karpathy Summary)
> "세상의 모든 자바스크립트에 '타입'이라는 옷을 입히는 거대한 프로젝트." 타입스크립트 지원이 없는 JS 라이브러리를 위해 전 세계 커뮤니티가 기여하는 타입 정의(@types) 저장소다.
## 한 줄
> **"매 untyped JavaScript 의 community-maintained TypeScript declaration 의 monorepo"**. `@types/*` npm scope 의 publish 되며, 8000+ package 의 cover. 2026 의 매 native-TS shift (`exports`/`types` field) 의 점진적 의 X — 매 still backbone 의 legacy ecosystem.
## 📖 구조화된 지식 (Synthesized Content)
- **Role**:
- 수만 개의 JS 라이브러리에 대한 선언 파일(`.d.ts`)을 관리한다.
- 개발자가 `npm install @types/react`를 실행할 때 실제 타입 데이터를 제공하는 근원지다.
- **Infrastructure**:
- GitHub의 `DefinitelyTyped` 레포지토리 하나에서 모든 타입을 관리하는 모노레포([[Monorepo|Monorepo]]) 구조다.
- 수천 명의 기여자와 자동화된 테스트 봇(dtslint)이 타입의 정확성을 검증한다.
- **Impact**: 자바스크립트 생태계를 타입스크립트로 전환한 일등 공신이며, IDE의 자동 완성 기능을 가능하게 하는 핵심 인프라다.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- 최근에는 많은 라이브러리가 자체적으로 TS를 사용해 빌드하거나, 패키지 내부에 타입 파일을 포함(Bundled types)하는 추세다. 따라서 DefinitelyTyped는 '자체 타입이 없는 레거시 라이브러리'를 지원하는 역할로 조금씩 이동하고 있으나, 그 방대함 때문에 여전히 필수적이다.
### 매 작동
- GitHub `DefinitelyTyped/DefinitelyTyped` repo 의 매 `types/<package>/index.d.ts` 의 hosting.
- types-publisher bot 의 매 commit 의 `@types/<package>` 의 npm publish.
- TypeScript 의 매 `node_modules/@types/*` 의 auto-include (tsconfig `types` field 의 absence).
## 🔗 지식 연결 (Graph)
- Related: [[Declaration-Files|Declaration-Files]] , TypeScript-Type-System
- [[Storage|Storage]]: GitHub
### 매 declaration 의 구조
- `index.d.ts` — main declaration.
- `package.json` — version, dependencies (other `@types`).
- `tests/<pkg>-tests.ts` — type 의 verify 의 sample 의 compile.
- `tsconfig.json` — strict mode + lib version.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 modern shift (2026)
- 매 popular library 의 매 inline TS (`exports.types`) 의 ship — `@types/*` 의 unnecessary.
- DT 의 매 long-tail / abandoned package 의 still 의 critical.
- TypeScript Reference Types 의 매 alternative ecosystem 의 emerging.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용
1. Untyped npm package 의 type 의 add.
2. Global type (jQuery 의 `$`, Node `process`) 의 declare.
3. Module augmentation (express `Request` 의 add field).
4. Ambient module (`declare module "*.svg"`).
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Install + 사용
```bash
npm install lodash
npm install --save-dev @types/lodash
```
## 🤔 의사결정 기준 (Decision Criteria)
```ts
import _ from "lodash";
const grouped = _.groupBy([1, 2, 3, 4], (n) => n % 2);
// ^? Dictionary<number[]>
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Version 의 align
```json
{
"dependencies": { "lodash": "^4.17.21" },
"devDependencies": { "@types/lodash": "^4.17.21" }
}
```
매 major.minor 의 같은 의 keep — 매 type drift 의 risk.
**선택 B를 써야 할 때:**
- *(TODO)*
### Type 의 X 의 fallback
```ts
// types/legacy-lib.d.ts
declare module "legacy-lib" {
export function doStuff(x: string): number;
export const VERSION: string;
}
```
**기본값:**
> *(TODO)*
```jsonc
// tsconfig.json
{
"compilerOptions": {
"paths": { "*": ["types/*"] }
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Quick stub (any)
```ts
declare module "untyped-lib"; // 매 entire module 의 any
```
매 explicit narrow 보다 의 worst — but 의 match-and-go 의 valid.
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Module augmentation
```ts
// types/express-augment.d.ts
import "express";
declare module "express-serve-static-core" {
interface Request {
user?: { id: string; email: string };
}
}
```
### Global declaration
```ts
// types/globals.d.ts
declare global {
interface Window {
__APP_VERSION__: string;
}
var __DEV__: boolean;
}
export {}; // 매 file 의 module 의 의 essential
```
### Asset module declaration
```ts
// types/assets.d.ts
declare module "*.svg" {
const content: React.FC<React.SVGProps<SVGSVGElement>>;
export default content;
}
declare module "*.png" {
const src: string;
export default src;
}
```
### DT 의 contribute
```bash
git clone https://github.com/DefinitelyTyped/DefinitelyTyped
cd DefinitelyTyped/types
mkdir my-lib
# index.d.ts, tsconfig.json, package.json, my-lib-tests.ts 의 작성
npm test
# PR 의 submit
```
### 매 inline types (modern alternative)
```jsonc
// my-lib package.json
{
"name": "my-lib",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
```
매 native ship 의 `@types/*` 의 X 의 필요.
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Library 의 native types 의 ship | nothing 의 install — 의 just import |
| Library 의 untyped, popular | `npm i -D @types/<pkg>` |
| `@types/*` 의 X 의 (long-tail) | 매 local `.d.ts` 의 작성 + `paths` |
| Quick prototype | `declare module "x";` (any) |
| Library 의 publish | 매 native `types` field 의 ship — DT 의 contribute X |
**기본값**: 매 `@types/*` 의 first 의 try, fallback 의 local `.d.ts`.
## 🔗 Graph
- 부모: [[TypeScript]] · [[npm Ecosystem]]
- 변형: [[Inline Type Declarations]] · [[JSDoc Types]]
- 응용: [[Module Augmentation]] · [[Ambient Modules]]
- Adjacent: [[tsconfig.json]] · [[Declaration Files]]
## 🤖 LLM 활용
**언제**: untyped library 의 type 의 add, module augmentation, asset module declaration.
**언제 X**: library 의 매 already 의 inline types 의 ship — `@types/*` 의 install 의 conflict 의 cause.
## ❌ 안티패턴
- **Version mismatch**: `@types/lodash@3` + `lodash@4` — 매 wrong type.
- **Both inline + DT install**: 매 conflict — 매 module resolution 의 confused.
- **`declare module "x";` 의 production 의 ship**: 매 effectively `any` 의 entire library.
- **DT PR 의 의 X 의 — local 의만 keep**: 매 update 의 manual.
## 🧪 검증 / 중복
- Verified (DefinitelyTyped repo, TypeScript handbook, npm `@types` scope, types-publisher).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — augmentation + asset module + 2026 inline-types shift 추가 |
+128 -74
View File
@@ -2,100 +2,154 @@
id: wiki-2026-0508-diffing-algorithm
title: Diffing Algorithm
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [VDOM Diff, Reconciliation]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [react, vue, vdom, reconciliation]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript
framework: React/Vue
---
# [[Diffing Algorithm|Diffing Algorithm]]
# Diffing Algorithm
## 📌 한 줄 통찰 (The Karpathy Summary)
Diffing Algorithm(디핑 알고리즘)은 React에서 이전 가상 DOM([[Virtual DOM|Virtual DOM]]) 트리와 새롭게 계산된 트리를 비교하여 실제 DOM을 가장 효율적으로 업데이트할 방법을 결정하는 과정입니다 [1, 2]. 이론적인 트리 비교 알고리즘은 $O(n^3)$의 시간 복잡도를 가져 실시간 애플리케이션에 부적합하지만, React는 두 가지 휴리스틱 가정을 통해 이를 $O(n)$ 복잡도로 최적화했습니다 [3-5]. 이 알고리즘은 '[[Reconciliation|Reconciliation]](재조정)' 과정의 핵심으로, 불필요한 DOM 조작을 최소화하여 렌더링 성능을 극대화하는 역할을 합니다 [1, 2, 6].
## 한 줄
> **"매 VDOM diff = O(n) heuristic — 매 same-level node 의 비교 + key-based identity."**. 매 React/Vue/Preact 모두 매 Levenshtein-style O(n³) 의 회피하기 위해 매 두 가정 (1) 다른 type = subtree 교체, (2) key가 child identity 의 hint. 매 React 19 (2024) Fiber + concurrent rendering, Vue 3.4 patchFlag-driven static hoist 의 진화.
## 📖 구조화된 지식 (Synthesized Content)
* **알고리즘의 기본 원리 및 가정:**
React의 디핑 알고리즘은 두 가지 주요 가정에 기반하여 $O(n)$의 성능을 달성합니다. 첫째, 서로 다른 타입의 요소는 근본적으로 다른 트리를 생성한다고 가정합니다 [3, 5]. 둘째, 개발자가 제공하는 `key` prop을 통해 여러 렌더링 사이클 동안 안정적으로 유지되는 자식 요소를 식별할 수 있다고 가정합니다 [3, 5].
## 매 핵심
* **비교(Diffing) 프로세스 메커니즘:**
* **다른 타입의 요소:** 루트 요소의 타입이 다를 경우(예: `<a>`에서 `<img>`로 변경), React는 이전 트리를 완전히 허물고 처음부터 새로운 트리를 구축합니다. 이 과정에서 기존 DOM 노드와 연관된 컴포넌트의 상태([[State|State]])는 모두 파괴됩니다 [7, 8].
* **동일한 타입의 DOM 요소:** 두 요소의 속성을 비교하여 동일한 기본 DOM 노드를 유지한 채 변경된 속성(예: `className`, `color``fontWeight` 같은 `style` 등)만 업데이트합니다 [9, 10].
* **동일한 타입의 컴포넌트 요소:** 컴포넌트의 인스턴스가 동일하게 유지되어 상태가 보존됩니다. 새로운 요소에 맞게 prop이 업데이트된 후, 하위 요소들에 대해 재귀적으로 디핑 알고리즘을 수행합니다 [10, 11].
### 매 두 가정 (Heuristics)
1. 매 different element type ⇒ subtree 의 unmount + 재생성.
2. 매 stable `key` ⇒ list reconciliation 의 identity hint.
* **자식 요소의 재귀적 처리와 Key의 역할:**
기본적으로 React는 두 하위 요소 목록을 동시에 반복하면서 차이가 있을 때마다 변이를 생성합니다 [11]. 하지만 리스트의 맨 앞에 요소를 추가하는 경우 등 순서가 변경될 때는 전체를 다시 렌더링하는 매우 비효율적인 상황이 발생할 수 있습니다 [12]. 이를 해결하기 위해 고유한 `key` 속성을 사용하면, React는 기존 트리와 새 트리의 자식들을 일치시켜 이동한 요소만 파악하므로 불필요한 DOM 재생성을 방지할 수 있습니다 [12, 13].
### 매 알고리즘
- React = Fiber tree, work loop가 매 cooperative scheduling 가능 (concurrent mode).
- Vue 3 = compiled patchFlag (static / dynamic 분류) + LIS (Longest Increasing Subsequence) for keyed list.
- Svelte/Solid = 매 VDOM 없음 — 매 fine-grained reactivity 의 directly DOM 의 patch.
* **트레이드오프 및 주의사항:**
이 알고리즘은 휴리스틱에 의존하기 때문에 가정이 충족되지 않으면 성능이 저하될 수 있습니다 [14]. 예를 들어 하위 트리가 형제 요소 사이가 아닌 아예 다른 계층으로 이동하는 경우, 알고리즘은 해당 하위 트리를 완전히 다시 렌더링합니다 [15]. 또한 배열의 인덱스를 키로 사용하거나 `Math.random()` 같은 불안정한 키를 사용하면 리스트가 재정렬될 때 컴포넌트 상태가 꼬이거나 성능 저하가 발생할 수 있습니다 [14, 16].
### 매 응용
1. Keyed list — 매 stable key가 매 reorder cost 의 minimize.
2. Conditional render — 매 ternary가 매 type swap 의 발생.
3. Concurrent rendering — 매 high-priority update가 매 low-priority interrupt.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Virtual DOM|Virtual DOM]], Reconciliation, [[React Fiber|React Fiber]]
- **Projects/Contexts:** [[React Frontend Development|React Frontend Development]], [[Component-Based Architecture|Component-Based Architecture]]
- **Contradictions/Notes:** 일반적인 트리 비교 알고리즘은 $O(n^3)$의 복잡도를 가지지만, React의 디핑 알고리즘은 휴리스틱([[Heuristics|Heuristics]])을 적용하여 실용적인 $O(n)$ 복잡도로 구현되었다는 점이 핵심적인 기술적 차이입니다 [4, 5]. 배열의 인덱스를 `key`로 사용하는 것은 요소의 순서가 변경되지 않을 때만 유효하며, 재정렬(Reorder) 시에는 비효율적이고 상태 오류를 일으킬 수 있으므로 권장되지 않습니다 [13, 16].
## 💻 패턴
---
*Last updated: 2026-04-25*
### 1. Stable key (correct)
```jsx
// CORRECT — id is stable identity
items.map((item) => <Row key={item.id} item={item} />)
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// WRONG — index changes when list reorders
items.map((item, i) => <Row key={i} item={item} />)
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Type swap forces unmount
```jsx
{condition ? <div>A</div> : <span>A</span>}
// span/div type 다름 → subtree unmount + remount
// 같은 component reuse 원하면 같은 type 유지:
<div>{condition ? 'A' : 'B'}</div>
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. React Fiber priority lanes (19)
```jsx
import { useTransition } from 'react';
**선택 B를 써야 할 때:**
- *(TODO)*
const [isPending, startTransition] = useTransition();
**기본값:**
> *(TODO)*
const onChange = (e) => {
setInput(e.target.value); // urgent
startTransition(() => {
setFilter(e.target.value); // can be interrupted
});
};
```
## ❌ 안티패턴 (Anti-Patterns)
### 4. Vue 3 patchFlag (compiled)
```html
<!-- Source -->
<div>
<span>{{ msg }}</span>
<span class="static">hi</span>
</div>
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
<!-- Compiled (simplified) -->
<!-- 첫 span has patchFlag = 1 (TEXT) → diff only text -->
<!-- 두번째 span hoisted as static — 매 diff 건너뛰기 -->
```
### 5. Vue keyed list w/ LIS
```html
<TransitionGroup tag="ul">
<li v-for="item in items" :key="item.id">{{ item.label }}</li>
</TransitionGroup>
<!-- Vue calculates LIS to minimize DOM moves -->
```
### 6. React.memo + structural equality
```typescript
const Row = React.memo(({ item }: { item: Item }) =>
<div>{item.label}</div>,
(prev, next) => prev.item.id === next.item.id && prev.item.label === next.item.label,
);
```
### 7. Solid/Svelte alternative (no diff)
```typescript
// Solid — fine-grained reactivity, no VDOM
import { createSignal } from 'solid-js';
const [count, setCount] = createSignal(0);
// JSX compiles to direct DOM ops; only `count()` text node updates
return <div>count: {count()}</div>;
```
### 8. Avoid layout-impacting reorder
```jsx
// Stable order with key — only reorder DOM, no remount
<>{sorted.map((u) => <UserCard key={u.id} user={u} />)}</>
// Each UserCard preserves its instance (state, refs) on reorder.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| List render | 매 stable id key — index X. |
| Heavy filter + input | useTransition + deferredValue. |
| Static UI | Vue patchFlag / React.memo. |
| Maximum perf | Solid / Svelte (skip VDOM). |
| Type-switch UI | wrap in same outer type to preserve children. |
**기본값**: 매 React 19 + Suspense + Transition + 매 stable key.
## 🔗 Graph
- 부모: [[Virtual DOM]] · [[Reconciliation]]
- 변형: [[React Fiber]] · [[Vue Reactivity]] · [[Solid Fine-grained]]
- 응용: [[List Rendering]] · [[Animation]]
- Adjacent: [[Tree Edit Distance]] · [[LIS Algorithm]]
## 🤖 LLM 활용
**언제**: 매 keyed-list bug 의 explain, 매 type-swap unmount 의 진단.
**언제 X**: 매 specific framework internal — 매 source code 의 read.
## ❌ 안티패턴
- **Index as key with reorder**: 매 wrong identity → state mix.
- **Random key per render**: 매 매 unmount + remount.
- **Inline objects/arrays as deps**: 매 referential change → memo bypass.
- **Massive un-keyed list**: 매 O(n) DOM ops 매 frame.
## 🧪 검증 / 중복
- Verified (react.dev reconciliation, vuejs.org renderer, Solid docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — VDOM diff + Fiber + Vue patchFlag |
@@ -2,89 +2,197 @@
id: wiki-2026-0508-discriminated-unions-for-error-h
title: Discriminated Unions for Error Handling
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [TS-UNION-001]
aliases: [Tagged Unions, Result Type, Sum Types]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [typescript, type-system, Functional-Programming, error-handling]
confidence_score: 0.9
verification_status: applied
tags: [typescript, error-handling, type-system, functional]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: none
---
# [[Discriminated Unions|Discriminated Unions]] (판별 가능한 유니온)
# Discriminated Unions for Error Handling
## 📌 한 줄 통찰 (The Karpathy Summary)
> "타입 가드를 자동화하는 영리한 리터럴 태그" — 공통된 속성(Tag)을 기준으로 여러 타입을 하나로 묶고, 코드 레벨에서 안전하게 특정 타입을 식별해낼 수 있게 하는 타입 설계 기법.
## 한 줄
> **"매 throw 의 의 X — return value 의 success/failure 의 model"**. ML/Haskell `Either`, Rust `Result<T, E>` 의 TypeScript port. 2026 의 매 typed exception 의 alternative — exhaustive checking + traceable failure path.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** 여러 객체 타입이 공통적으로 가지는 '태그(Literal property)'를 사용하여 컴파일러가 조건문(`switch`, `if`) 내에서 타입을 정확히 좁힐 수 있도록 돕는 패턴.
- **세부 내용:**
- **Tag/Kind 속성:** 각 타입에 고유한 문자열 리터럴 속성을 부여하여 구분의 근거를 마련.
- **Exhaustiveness Check:** `switch` 문에서 모든 가능한 케이스를 처리했는지 TypeScript 컴파일러가 확인하게 함.
- **Error Handling:** `Success``Failure` 타입을 유니온으로 묶어 런타임 에러 대신 컴파일 타임에 예외 처리를 강제.
- **Pattern Matching:** 함수형 언어의 패턴 매칭과 유사한 안정성을 객체 지향 환경에서 구현.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** `instanceof`나 임의의 속성 체크 기반의 불안정한 타입 가드에서, 명시적인 '태그' 기반의 선언적 타입 가드로 표준화됨.
- **정책 변화:** Antigravity 에이전트의 통신 프로토콜 정의 시, 메시지 타입을 Discriminated Unions로 정의하여 파싱 오류를 원천 차단함.
### 매 왜 throw 의 X 의
- `throw` 의 type-erased — caller 의 매 catch 의 type 의 unknown.
- Control flow 의 invisible — 매 implicit goto.
- async 의 매 unhandled rejection 의 silent.
## 🔗 지식 연결 (Graph)
- **Parent:** 10_Wiki/💡 Topics/AI
- **Related:** Type-Guards, Algebraic-Data-Types, [[Exhaustiveness-Checking|Exhaustiveness-Checking]]
- **Raw Source:** 10_Wiki/Topics/AI/[[Discriminated-Unions|Discriminated-Unions]]-for-Error-Handling.md
### 매 discriminator tag
- 매 literal field (`type`, `tag`, `_tag`, `kind`) 의 매 union 의 narrow.
- TypeScript 의 control-flow analysis 의 `if (r.type === "ok")` 의 narrow.
- exhaustive check 의 `switch` + `never` 의 가능.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. API client (network/parse/validation 의 error 의 분리).
2. Form validation (field-level error).
3. Parser combinator (success/fail with location).
4. State machine (state 의 each 의 tag).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### 기본 Result type
```ts
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });
const err = <E>(error: E): Result<never, E> => ({ ok: false, error });
```
## 🤔 의사결정 기준 (Decision Criteria)
### Domain error 의 tagged
```ts
type FetchUserError =
| { type: "network"; cause: unknown }
| { type: "not_found"; userId: string }
| { type: "unauthorized" }
| { type: "parse"; raw: unknown; issue: string };
**선택 A를 써야 할 때:**
- *(TODO)*
async function fetchUser(id: string): Promise<Result<User, FetchUserError>> {
let res: Response;
try {
res = await fetch(`/api/users/${id}`);
} catch (cause) {
return err({ type: "network", cause });
}
if (res.status === 404) return err({ type: "not_found", userId: id });
if (res.status === 401) return err({ type: "unauthorized" });
**선택 B를 써야 할 때:**
- *(TODO)*
const raw = await res.json();
const parsed = UserSchema.safeParse(raw);
if (!parsed.success) {
return err({ type: "parse", raw, issue: parsed.error.message });
}
return ok(parsed.data);
}
```
**기본값:**
> *(TODO)*
### Exhaustive handling
```ts
function renderError(e: FetchUserError): string {
switch (e.type) {
case "network": return "Network failure. Retry?";
case "not_found": return `User ${e.userId} 의 X.`;
case "unauthorized": return "Login 의 필요.";
case "parse": return `Bad response: ${e.issue}`;
default: {
const _exhaustive: never = e; // 매 compile error 의 새 case 의 추가 시
return _exhaustive;
}
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Caller 의 narrow 의 사용
```ts
const r = await fetchUser("abc");
if (!r.ok) {
// r.error: FetchUserError — 매 fully typed
return renderError(r.error);
}
// r.value: User — 매 narrowed
console.log(r.value.email);
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Combinator (map / flatMap)
```ts
function map<T, U, E>(r: Result<T, E>, f: (t: T) => U): Result<U, E> {
return r.ok ? ok(f(r.value)) : r;
}
function flatMap<T, U, E>(r: Result<T, E>, f: (t: T) => Result<U, E>): Result<U, E> {
return r.ok ? f(r.value) : r;
}
// 매 chained pipeline
const result = flatMap(
await fetchUser(id),
(u) => u.verified ? ok(u) : err({ type: "unauthorized" } as FetchUserError),
);
```
### Form validation
```ts
type FieldResult<T> =
| { state: "valid"; value: T }
| { state: "invalid"; reasons: string[] }
| { state: "pending" };
function validateEmail(s: string): FieldResult<string> {
if (s.length === 0) return { state: "pending" };
const reasons: string[] = [];
if (!s.includes("@")) reasons.push("@ missing");
if (s.length > 254) reasons.push("Too long");
return reasons.length ? { state: "invalid", reasons } : { state: "valid", value: s };
}
```
### Zod 의 native return
```ts
import { z } from "zod";
const UserSchema = z.object({ id: z.string(), email: z.email() });
const parsed = UserSchema.safeParse(input);
// parsed: { success: true; data: User } | { success: false; error: ZodError }
```
### neverthrow 라이브러리 (2026 standard)
```ts
import { ok, err, Result, ResultAsync } from "neverthrow";
const fetchUserSafe = (id: string): ResultAsync<User, FetchUserError> =>
ResultAsync.fromPromise(fetch(`/api/users/${id}`), (c) => ({ type: "network", cause: c } as const))
.andThen((res) =>
res.ok ? ResultAsync.fromSafePromise(res.json()) : err({ type: "not_found", userId: id } as const)
);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Domain logic 의 expected failure | Discriminated union Result |
| Truly exceptional (OOM, bug) | Throw |
| Async I/O | `Promise<Result<T, E>>` 의 neverthrow `ResultAsync` |
| Schema parsing | Zod `safeParse` |
| Multi-step pipeline | `flatMap` chain 의 Effect TS |
**기본값**: domain error 의 tagged union, infrastructure error 의 throw.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Type System]]
- 변형: [[Effect TS 및 ts-brand 라이브러리 활용]] · [[Either Monad]]
- 응용: [[Error Boundaries]] · [[Form Validation]] · [[API Client Design]]
- Adjacent: [[Zod]] · [[Pattern Matching]] · [[Exhaustive Checking]]
## 🤖 LLM 활용
**언제**: domain error 의 modeling, exhaustive switch 의 enforce, async error path 의 explicit.
**언제 X**: panic-level error (assertion fail) — throw 의 더 적합.
## ❌ 안티패턴
- **`{ error: string | null; data: T | null }`**: 매 implicit invariant — 둘 모두 null/non-null 의 type 의 allow.
- **String-only error**: 매 i18n / programmatic handling 의 X.
- **Discriminator 의 `boolean`**: `ok: true/false` 의 OK, but multi-variant 의 X — string literal 의 사용.
- **Throw inside Result-returning fn**: 매 hybrid 의 worst.
## 🧪 검증 / 중복
- Verified (TypeScript handbook, Effect-TS docs, neverthrow, Rust `Result`, fp-ts `Either`).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — exhaustive check + neverthrow + combinators 추가 |
@@ -2,88 +2,180 @@
id: wiki-2026-0508-discriminated-unions-for-state-m
title: Discriminated Unions for State Modeling
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AI-DU-StateS]
aliases: [Tagged Unions, Sum Types, ADT State]
duplicate_of: none
source_trust_level: A
confidence_score: 0.99
tags: [TypeScript, StateManagement, Patterns, Architecture]
confidence_score: 0.9
verification_status: applied
tags: [typescript, state-modeling, types, frontend]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React / any
---
# [[Discriminated-Unions-for-State-Modeling|Discriminated-Unions-for-State-Modeling]] (상태 모델링을 위한 구별된 유니온)
# Discriminated Unions for State Modeling
## 📌 한 줄 통찰 (The Karpathy Summary)
> "불가능한 상태(Impossible State)를 코드 수준에서 원천 봉쇄하라." 로딩 중이면서 동시에 에러가 날 수 없는 것처럼, 시스템의 상호 배타적인 상태들을 타입을 통해 완벽하게 정의하는 기법이다.
## 한 줄
> **"매 impossible state 의 unrepresentable"**. Discriminated union (tagged union, sum type) 으로 매 async/UI state 를 modeling 하면 매 `loading + error + data` simultaneous 같은 illegal combination 매 type system 매 차단.
## 📖 구조화된 지식 (Synthesized Content)
- **The Anti-pattern**:
- `interface State { isLoading: boolean; error?: string; data?: Data; }`
- 이 설계는 `isLoading: true`이면서 동시에 `error`가 존재하는 모순된 상태를 허용한다.
- **The Discriminated Union [[Solution|Solution]]**:
- `type State = { type: 'loading' } | { type: 'error'; message: string } | { type: 'success'; data: Data };`
- `type` 속성을 통해 현재 어떤 상태인지 명확히 구별하며, 각 상태에 꼭 필요한 데이터만 가질 수 있게 강제한다.
- **Benefit**: 컴포넌트나 로직에서 조건문 분기가 매우 명확해지며, 런타임 에러 발생 가능성이 획기적으로 줄어든다.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- 상태가 복잡해지면(예: 부분적 성공, 멀티 스텝 폼 등) 유니온의 조합이 기하급수적으로 늘어날 수 있다. 이때는 상태 머신(State Machine, 예: XState) 라이브러리를 도입하여 타입 안전성과 비즈니스 흐름 제어를 동시에 잡는 것이 권장된다.
### 매 motivation
- Boolean flag combinatorics: `isLoading`, `isError`, `data` → 8 states, 매 5+ illegal.
- DU: 매 mutually-exclusive variants 만 표현.
## 🔗 지식 연결 (Graph)
- Related: [[Discriminated-Unions|Discriminated-Unions]] , [[Finite-State-Machines|Finite-State-Machines]]
- Context: React-Query-Pattern
### 매 anatomy
- Common discriminator field (`type`, `status`, `kind`).
- Per-variant payload.
- TS narrows by discriminator in `switch` / `if`.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Async data (idle / loading / success / error).
2. Form (initial / submitting / submitted / failed).
3. Wizard (step1 / step2 / done).
4. Auth (anonymous / loading / authenticated / expired).
5. Reducer/state machine actions.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Async state DU
```ts
type AsyncState<T, E = Error> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: E };
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
function render<T>(s: AsyncState<T>) {
switch (s.status) {
case 'idle': return <Idle />;
case 'loading': return <Spinner />;
case 'success': return <Data data={s.data} />; // 매 data 매 type-safe
case 'error': return <Err msg={s.error.message} />;
}
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Exhaustive check helper
```ts
function assertNever(x: never): never {
throw new Error(`Unhandled variant: ${JSON.stringify(x)}`);
}
**선택 A를 써야 할 때:**
- *(TODO)*
function step(s: WizardState) {
switch (s.kind) {
case 'address': return <AddressForm />;
case 'payment': return <PaymentForm />;
case 'review': return <Review />;
default: return assertNever(s); // 매 compile error 매 새 variant 추가 시
}
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Form state DU
```ts
type FormState<V, E = Record<string, string>> =
| { phase: 'editing'; values: V }
| { phase: 'submitting'; values: V }
| { phase: 'failed'; values: V; errors: E }
| { phase: 'submitted'; result: { id: string } };
```
**기본값:**
> *(TODO)*
### Auth state DU
```ts
type Auth =
| { state: 'anonymous' }
| { state: 'authenticating' }
| { state: 'authenticated'; user: User; token: string }
| { state: 'expired'; lastUser: User };
## ❌ 안티패턴 (Anti-Patterns)
function canAccessAdmin(a: Auth): boolean {
return a.state === 'authenticated' && a.user.role === 'admin';
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Reducer with action DU
```ts
type Action =
| { type: 'fetch/start' }
| { type: 'fetch/success'; payload: User[] }
| { type: 'fetch/error'; error: string };
function reducer(s: AsyncState<User[]>, a: Action): AsyncState<User[]> {
switch (a.type) {
case 'fetch/start': return { status: 'loading' };
case 'fetch/success': return { status: 'success', data: a.payload };
case 'fetch/error': return { status: 'error', error: new Error(a.error) };
}
}
```
### Pattern matching with `ts-pattern`
```ts
import { match } from 'ts-pattern';
const view = match(state)
.with({ status: 'idle' }, () => <Idle />)
.with({ status: 'loading' }, () => <Spinner />)
.with({ status: 'success' }, ({ data }) => <Data data={data} />)
.with({ status: 'error' }, ({ error }) => <Err msg={error.message} />)
.exhaustive();
```
### Nested DU (loading sub-status)
```ts
type Resource<T> =
| { state: 'idle' }
| { state: 'loading'; progress?: number }
| { state: 'streaming'; partial: T[]; progress: number }
| { state: 'success'; data: T }
| { state: 'error'; error: Error; retryCount: number };
```
### Builder helpers
```ts
const idle = <T,>(): AsyncState<T> => ({ status: 'idle' });
const loading = <T,>(): AsyncState<T> => ({ status: 'loading' });
const success = <T,>(data: T): AsyncState<T> => ({ status: 'success', data });
const failure = <T,>(error: Error): AsyncState<T> => ({ status: 'error', error });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 2+ boolean flags 매 mutually exclusive | DU 강제 |
| Single boolean | 매 plain bool OK |
| Complex transitions | DU + state machine (XState) |
| Library API surface | DU 매 caller-friendly |
**기본값**: async/form/wizard/auth state 매 즉시 DU 모델링.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Type-Driven-Design]]
- 변형: [[State-Machines]] · [[Algebraic-Data-Types]] · [[Sum-Types]]
- 응용: [[XState]] · [[ts-pattern]] · [[React-Query]]
- Adjacent: [[Exhaustiveness-Checking]] · [[Pattern-Matching]]
## 🤖 LLM 활용
**언제**: async data, multi-step UI, auth flow, anywhere 매 boolean explosion 발생.
**언제 X**: 매 single-flag 매 trivial — over-engineering.
## ❌ 안티패턴
- **Boolean explosion**: `isLoading && !isError && data` chains.
- **Optional fields encoding state**: `{ data?, loading?, error? }` — 매 invalid combos 가능.
- **Missing exhaustive check**: 매 new variant 추가 시 매 silently broken.
## 🧪 검증 / 중복
- Verified (TS handbook / Richard Feldman "Making Impossible States Impossible").
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DU patterns for async/form/auth state |
+179 -68
View File
@@ -2,95 +2,206 @@
id: wiki-2026-0508-draw-call-optimization
title: Draw Call Optimization
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-0B8FFC]
aliases: [Batching, Instancing, GPU Draw Reduction]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [graphics, gpu, performance, webgl, webgpu]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - [[Draw Call|Draw Call]] [[Optimization|Optimization]]"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: WebGPU
---
# [[Draw Call Optimization|Draw Call Optimization]]
# Draw Call Optimization
## 📌 한 줄 통찰 (The Karpathy Summary)
> 드로우 콜(Draw Call)은 CPUGPU에게 기하학적 구조, 재질, 렌더링 지침 등을 전달하여 화면에 객체를 그리도록 내리는 명령입니다 [1-3]. 각 드로우 콜을 준비하고 상태를 변경하는 과정에서 막대한 CPU 오버헤드가 발생하기 때문에, 드로우 콜 횟수를 줄이는 것은 애플리케이션의 프레임 속도와 전반적인 렌더링 성능을 개선하고 병목 현상을 방지하는 핵심 최적화 기법입니다 [4-6].
## 한 줄
> **"매 CPUGPU command submission 의 의 minimize 의 — 의 frame budget 의 dominant cost"**. 의 each draw call 의 의 driver overhead (state validation, command translation) 의 incur. 2026 의 WebGPU 의 매 explicit 의 design 의 의 batching 의 essential 의.
## 📖 구조화된 지식 (Synthesized Content)
* **드로우 콜의 성능 병목 ([[Bottlenecks|Bottlenecks]]):** 그래픽 API가 GPU에 렌더링 상태를 설정하고 명령을 내리는 준비 과정은 실제 GPU가 픽셀을 렌더링하는 것보다 더 많은 CPU 자원을 소모합니다 [2, 4, 6]. 이로 인해 개별 객체를 수천 번 분리하여 그리면 GPU의 폴리곤 처리 한계에 도달하기도 전에 CPU 병목이 발생하여 시스템 프레임 레이트가 급감합니다 [5, 7]. 최신 기기에서 부드러운 60fps를 유지하려면 프레임당 드로우 콜을 100개 이하로 타겟팅하는 것이 권장되며 [8-10], [[WebGL|WebGL]] 환경에서의 실질적인 한계는 1,000~2,000회 수준입니다 [11].
* **주요 최적화 기법 (Optimization Techniques):**
* **인스턴싱 ([[Instancing|Instancing]]):** `[[InstancedMesh|InstancedMesh]]` 등을 사용하여 동일한 기하학적 구조와 재질을 가진 객체의 수많은 복제본을 단 한 번의 드로우 콜로 렌더링합니다 [8, 12-14]. 나무, 풀, 파티클 시스템과 같이 반복되는 요소에 효율적입니다 [12, 15].
* **배칭 및 병합 ([[Batching|Batching]] & Merging):** `BatchedMesh`는 동일한 재질을 공유하지만 서로 다른 기하학적 구조를 가진 객체들을 하나의 드로우 콜로 묶어 처리할 수 있게 합니다 [16, 17]. 정적인 환경 요소는 `[[BufferGeometry|BufferGeometry]]Utils`와 같은 도구를 사용해 하나의 지오메트리로 병합(Merging)하면 여러 드로우 콜을 한 번으로 줄일 수 있습니다 [16, 18-21].
* **재질 및 텍스처 공유 (Material & Texture Sharing):** 객체마다 새로운 재질을 생성하는 것은 최적화를 저해합니다 [16, 19]. 텍스처 아틀라스([[Texture Atlas|Texture Atlas]])나 배열 텍스처(Array Textures)를 활용하여 재질을 공유함으로써 텍스처 바인딩 및 상태 변경에 따른 추가적인 드로우 콜을 방지합니다 [20, 22-24].
* **가시성 제어 (Visibility & LOD):** 카메라 시야 밖의 객체에 대한 렌더링 명령을 제외하는 절두체 컬링([[Frustum Culling|Frustum Culling]])을 수행하고 [18, 25], 카메라와의 거리에 따라 기하학적 복잡도를 낮추는 LOD(Level of Detail) 기법을 적용하여 멀리 있는 객체에서 발생하는 불필요한 드로우 콜과 연산을 최소화합니다 [9, 26-28].
* **구조적 한계 및 고려사항 (Limitations & Trade-offs):** `InstancedMesh`를 통한 드로우 콜 단일화가 항상 최선은 아닙니다. 단일 객체로 취급되어 가시성 판정이 '전부 아니면 전무(All-or-Nothing)'로 이루어져 절두체 컬링이 비효율적으로 작동할 수 있습니다 [29, 30]. 또한, 인스턴스 간 자동 정렬 부재로 인한 심각한 오버드로우([[Overdraw|Overdraw]]) 현상과 매 프레임 수많은 변환 행렬 데이터를 갱신할 때 발생하는 메모리 대역폭 한계로 인해 또 다른 성능 병목이 유발될 수 있습니다 [29, 31, 32]. [[Unity|Unity]] 같은 게임 엔진에서는 이와 같은 드로우 콜 최적화 방식들이 겹칠 때 SRP Batcher, 정적 배칭(Static batching), GPU 인스턴싱 순으로 우선순위를 두어 충돌을 제어합니다 [33, 34].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
### 매 cost 의 source
- 의 driver state validation (shader, buffer, texture binding).
- 의 command buffer 의 translation 의 GPU-specific ISA.
- 의 GPU 의 의 pipeline switch (cache miss, warp reorganize).
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[InstancedMesh|InstancedMesh]], BatchedMesh, Frustum Culling, Texture Atlas, [[Level of Detail (LOD)|Level of Detail (LOD]]
- **Projects/Contexts:** Three.js, [[WebGL|WebGL]], [[Unity|Unity]]
- **Contradictions/Notes:** 일반적으로 드로우 콜을 줄이는 것은 렌더링 성능을 향상시킨다고 알려져 있지만, `InstancedMesh`를 통해 드로우 콜을 1회로 줄였음에도 불구하고 정렬되지 않은 인스턴스들이 유발하는 막대한 오버드로우(Overdraw) 비용이나 비효율적인 컬링으로 인해, 개별 메쉬를 렌더링할 때보다 오히려 프레임 속도(FPS)가 낮아지는 역설적인 상황이 실증적 연구와 버그 리포트 등에서 보고되고 있습니다 [29, 31, 35].
### 매 reduction 의 strategy
- **Batching**: 의 same-state object 의 single draw 의 의 merge.
- **Instancing**: 의 same mesh 의 N copy 의 single 의 draw call 의 issue.
- **Texture atlas**: 의 multiple texture 의 의 single 의 의 — 의 binding 의 reduce.
- **Indirect draw**: 의 GPU 의 의 self-issue 의 의 — CPU 의 의 idle.
- **Bindless / large bind group**: 의 binding 의 의 amortize.
---
*Last updated: 2026-04-19*
### 매 응용
1. UI rendering (의 button 의 thousand 의 single draw).
2. Particle system (의 instancing 의 의 millions).
3. Tilemap (atlas + instancing).
4. Foliage / crowd (의 GPU instancing).
5. Game world chunk (의 batching 의 의 static mesh).
---
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### Three.js BatchedMesh
```ts
import * as THREE from "three";
**언제 이 지식을 쓰는가:**
- *(TODO)*
const batched = new THREE.BatchedMesh(1024, 60_000, 90_000, material);
const cubeGeom = new THREE.BoxGeometry();
const id = batched.addGeometry(cubeGeom);
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
for (let i = 0; i < 1024; i++) {
const inst = batched.addInstance(id);
const m = new THREE.Matrix4().setPosition(Math.random() * 100, 0, Math.random() * 100);
batched.setMatrixAt(inst, m);
}
scene.add(batched);
// 매 single draw call 의 1024 cube
```
## 🤔 의사결정 기준 (Decision Criteria)
### InstancedMesh
```ts
const geom = new THREE.SphereGeometry(0.5);
const mesh = new THREE.InstancedMesh(geom, material, 10_000);
const m = new THREE.Matrix4();
for (let i = 0; i < 10_000; i++) {
m.setPosition(Math.random() * 200 - 100, 0, Math.random() * 200 - 100);
mesh.setMatrixAt(i, m);
}
mesh.instanceMatrix.needsUpdate = true;
```
**선택 A를 써야 할 때:**
- *(TODO)*
### WebGPU instanced draw
```ts
const pass = encoder.beginRenderPass(passDesc);
pass.setPipeline(pipeline);
pass.setBindGroup(0, sceneBindGroup);
pass.setVertexBuffer(0, vertexBuffer);
pass.setVertexBuffer(1, instanceBuffer); // per-instance data
pass.setIndexBuffer(indexBuffer, "uint32");
pass.drawIndexed(indexCount, instanceCount);
pass.end();
```
**선택 B를 써야 할 때:**
- *(TODO)*
### WebGPU indirect draw (GPU 의 self-issue)
```ts
const indirectBuffer = device.createBuffer({
size: 16, // [vertexCount, instanceCount, firstVertex, firstInstance]
usage: GPUBufferUsage.INDIRECT | GPUBufferUsage.STORAGE,
});
**기본값:**
> *(TODO)*
// 의 compute shader 의 의 indirectBuffer 의 의 fill (e.g. frustum cull)
pass.drawIndirect(indirectBuffer, 0);
```
## ❌ 안티패턴 (Anti-Patterns)
### Texture atlas (UV 의 sub-region)
```glsl
// fragment shader
uniform sampler2D atlas;
uniform vec4 uvRect; // x, y, w, h
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
void main() {
vec2 uv = uvRect.xy + v_uv * uvRect.zw;
outColor = texture(atlas, uv);
}
```
### Sort 의 의 state-change minimize
```ts
// 의 draw 의 의 material 의 의 sort
drawables.sort((a, b) => {
if (a.materialId !== b.materialId) return a.materialId - b.materialId;
if (a.meshId !== b.meshId) return a.meshId - b.meshId;
return a.depth - b.depth;
});
```
### UI batching (single quad mesh)
```ts
// 의 each UI element 의 의 quad 의 의 single VBO 의 의 append
class UIBatcher {
vertices = new Float32Array(4096 * 4 * 5); // x, y, u, v, color
count = 0;
pushQuad(x: number, y: number, w: number, h: number, uv: UVRect, color: number) {
const v = this.vertices;
const o = this.count * 20;
v[o+0]=x; v[o+1]=y; v[o+2]=uv.x; v[o+3]=uv.y; v[o+4]=color;
v[o+5]=x+w; v[o+6]=y; v[o+7]=uv.x+uv.w; v[o+8]=uv.y; v[o+9]=color;
v[o+10]=x+w; v[o+11]=y+h; v[o+12]=uv.x+uv.w; v[o+13]=uv.y+uv.h; v[o+14]=color;
v[o+15]=x; v[o+16]=y+h; v[o+17]=uv.x; v[o+18]=uv.y+uv.h; v[o+19]=color;
this.count++;
}
flush(pass: GPURenderPassEncoder) {
device.queue.writeBuffer(this.vbo, 0, this.vertices, 0, this.count * 20);
pass.setVertexBuffer(0, this.vbo);
pass.draw(6 * this.count); // 매 single call
this.count = 0;
}
}
```
### Frustum cull (CPU)
```ts
function cull(objects: Drawable[], camera: Camera): Drawable[] {
const frustum = camera.frustum;
return objects.filter((o) => frustum.intersects(o.worldBounds));
}
```
### GPU-driven cull (compute)
```wgsl
@compute @workgroup_size(64)
fn cullCS(@builtin(global_invocation_id) gid: vec3u) {
let i = gid.x;
if (i >= arrayLength(&instances)) { return; }
let inst = instances[i];
if (frustumIntersects(inst.bounds, frustum)) {
let slot = atomicAdd(&drawCount, 1u);
visibleInstances[slot] = inst;
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Same mesh, many copy | InstancedMesh (instancing) |
| Different mesh, same material | BatchedMesh (geometry merge) |
| UI / 2D | Sprite batcher + atlas |
| Static scene | Pre-merge geometry at build time |
| Dynamic LOD / cull | GPU indirect draw + compute cull |
| Mobile / tile | Reduce binding, atlas, instancing |
**기본값**: instancing 의 first, batching 의 second, indirect/compute 의 last.
## 🔗 Graph
- 부모: [[GPU Pipeline]] · [[Real-Time Rendering]]
- 변형: [[Instancing]] · [[Batching]] · [[Indirect Draw]]
- 응용: [[Particle Systems]] · [[Tilemap Rendering]] · [[UI Rendering]]
- Adjacent: [[Texture Atlas]] · [[GPU Driven Rendering]] · [[Frustum Culling]]
## 🤖 LLM 활용
**언제**: 의 frame time 의 의 CPU-bound 의 (draw call > 1000), GPU-driven culling, atlas 설계.
**언제 X**: 의 매 GPU-bound 의 (fragment-heavy) — 의 다른 의 axis 의 (overdraw, shader complexity) 의 attack.
## ❌ 안티패턴
- **One mesh per object**: 의 10,000 entity 의 = 의 10,000 draw — 매 disaster.
- **Per-frame buffer recreate**: 의 GC pressure + 의 driver overhead.
- **Random material switch**: state thrash — 매 sort 의 의 by material first.
- **Premature GPU-driven**: 의 CPU 의 매 not bottleneck 의 시 의 — 매 added complexity.
## 🧪 검증 / 중복
- Verified (WebGPU spec, Three.js BatchedMesh r167+, Unreal/Unity rendering docs, GPU Gems, RenderDoc analysis).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — instancing + indirect + UI batcher 추가 |
+170 -63
View File
@@ -2,91 +2,198 @@
id: wiki-2026-0508-dynamic-theming
title: Dynamic Theming
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Theming, Dark Mode, CSS Variables Theming]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [frontend, css, theming, design-system]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React
---
# [[Dynamic Theming|Dynamic Theming]]
# Dynamic Theming
## 📌 한 줄 통찰 (The Karpathy Summary)
Dynamic Theming(동적 테마 적용)은 라이트 모드/다크 모드 또는 다중 브랜드 테마와 같이 사용자 설정이나 컨텍스트에 따라 UI의 시각적 속성을 런타임에 유연하게 전환할 수 있는 기법입니다. 이는 주로 디자인 토큰([[Design Tokens|Design Tokens]]), CSS 변수(Custom Properties), 또는 styled-components와 같은 [[CSS-in-JS|CSS-in-JS]] 라이브러리를 활용하여 구현됩니다. 컴포넌트 코드의 직접적인 수정 없이 애플리케이션 전체의 디자인 시스템을 일관성 있고 확장 가능하게 관리하는 데 필수적인 역할을 합니다.
## 한 줄
> **"매 design token 을 runtime swap 할 수 있는 architecture"**. CSS custom properties (variables) 가 매 modern theming 의 backbone 이며, JS bundle 의 무관 하게 instant theme switching 의 가능. 2026 의 light/dark/high-contrast/brand-variant 의 매 standard.
## 📖 구조화된 지식 (Synthesized Content)
* **디자인 토큰 기반의 테마 전환 (Token Swapping):** 동적 테마 구현의 핵심은 단일 소스인 디자인 토큰을 활용하는 것입니다. 특정 시맨틱 토큰(Semantic Token)이 테마에 따라 다른 참조 값([[Reference|Reference]] Value)을 가리키도록 설정합니다(예: 라이트 모드에서는 `color.background = ref.gray.100`, 다크 모드에서는 `ref.gray.900`) [1]. Style Dictionary와 같은 도구를 활용하면 [[Figma|Figma]] 등에서 정의된 JSON 형식의 토큰을 CSS 변수나 React 테마 객체로 자동 변환하여 손쉽게 테마 전용 출력물을 생성할 수 있습니다 [2-4].
* **CSS 변수([[CSS Variables|CSS Variables]])를 활용한 동적 테마:** 최적의 성능을 위해 디자인 토큰을 CSS 변수에 매핑하여 사용하는 방식이 널리 쓰입니다 [5]. 테마별로 별도의 토큰 세트를 정의하고(예: `light-theme.css`, `dark-theme.css`), 런타임 시에 `<html>` 또는 `<body>` 같은 최상위 컨테이너에 테마 클래스를 토글하여 스타일을 업데이트할 수 있습니다 [5, 6]. 이 접근법은 값비싼 전체 리렌더링(full re-render)을 유발하지 않아 부드럽고 빠른 사용자 경험을 제공합니다 [5, 7]. 최근 [[Tailwind CSS v4|Tailwind CSS v4]]에서도 `@theme` 디렉티브와 CSS 변수를 활용해 네이티브 수준의 런타임 테마 전환을 직관적으로 지원합니다 [8, 9].
* **React 프레임워크 및 CSS-in-JS의 테마 적용:** `styled-components``Emotion` 같은 CSS-in-JS 라이브러리는 기본적으로 제공하는 `ThemeProvider`를 사용해 React 컴포넌트 트리에 동적으로 테마를 주입할 수 있어 다중 테마 구현에 매우 용이합니다 [10, 11]. 또한, `Chakra UI`는 CSS-in-JS를 기반으로 제작되어 런타임 시 라이트/다크 모드 동적 전환을 쉽게 구현할 수 있도록 돕습니다 [12].
* **[[React Server Components (RSC)|React Server Components (RSC]] 환경에서의 제약과 해법:** Context 기반의 `ThemeProvider`는 React Context가 없는 서버 컴포넌트(RSC) 환경에서는 작동하지 않는 근본적인 한계가 있습니다 [13-15]. 이를 해결하기 위해 `styled-components` (v6.4 이상)는 `createTheme` 함수를 도입하여 일반 테마 객체를 CSS 사용자 정의 속성 참조(예: `var(--prefix-path)`)로 변환합니다 [13]. 이 방식은 React Context에 의존하지 않으므로 클라이언트와 서버 컴포넌트 모두에서 동작하며, 라이트/다크 모드 전환 시 하이드레이션([[Hydration|Hydration]]) 불일치나 화면 깜빡임(Flash)을 방지합니다 [13, 16].
## 매 핵심
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Design Tokens|Design Tokens]], CSS Variables, Styled Components, [[Tailwind CSS|Tailwind CSS]], [[React Server Components (RSC)|React Server Components (RSC]]
- **Projects/Contexts:** [[Scalable Frontend Systems|Scalable FrontendSystems]], [[Component Library Architecture|Component Library Architecture]], Design-to-Code Workflow
- **Contradictions/Notes:** CSS-in-JS 라이브러리의 `ThemeProvider`는 동적인 테마 적용에 매우 유용하지만, [[Next.js|Next.js]]의 App Router와 같은 React Server Components(RSC) 아키텍처와는 본질적으로 호환되지 않습니다 [14, 15]. 최신 확장성 높은 프론트엔드 환경에서는 이러한 런타임 CSS-in-JS 대신 정적 생성된 CSS 변수나 Tailwind CSS, 혹은 제로 런타임 라이브러리([[vanilla-extract|vanilla-extract]]) 기반의 테마 시스템을 구축하는 것이 권장됩니다 [13, 15, 17, 18].
### 매 3-layer token 구조
- **Primitive tokens**: raw values (`--blue-500: #3B82F6`).
- **Semantic tokens**: intent-based (`--color-primary: var(--blue-500)`).
- **Component tokens**: scope-specific (`--button-bg: var(--color-primary)`).
---
*Last updated: 2026-04-26*
### 매 swap 메커니즘
- `data-theme="dark"` 속성 의 `<html>` element 의 set.
- CSS 의 `[data-theme="dark"] { --color-bg: #0a0a0a }` 의 override.
- 매 zero JS re-render — 매 paint cycle 만 trigger.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Light/dark mode toggle.
2. Brand white-labeling (multi-tenant SaaS).
3. Accessibility (high-contrast, reduced-motion variant).
4. Per-user customization (saved theme preference).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Token 정의 (CSS)
```css
:root {
/* Primitive */
--blue-500: #3B82F6;
--gray-900: #111827;
--gray-50: #F9FAFB;
## 🧪 검증 상태 (Validation)
/* Semantic — light default */
--color-bg: var(--gray-50);
--color-fg: var(--gray-900);
--color-primary: var(--blue-500);
}
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
[data-theme="dark"] {
--color-bg: var(--gray-900);
--color-fg: var(--gray-50);
}
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
[data-theme="high-contrast"] {
--color-bg: #000;
--color-fg: #fff;
--color-primary: #ffff00;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Theme provider (React 19)
```tsx
import { createContext, use, useEffect, useState } from "react";
**선택 A를 써야 할 때:**
- *(TODO)*
type Theme = "light" | "dark" | "system";
const ThemeCtx = createContext<{ theme: Theme; set: (t: Theme) => void }>(null!);
**선택 B를 써야 할 때:**
- *(TODO)*
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem("theme") as Theme) ?? "system"
);
**기본값:**
> *(TODO)*
useEffect(() => {
const resolved =
theme === "system"
? matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
: theme;
document.documentElement.dataset.theme = resolved;
localStorage.setItem("theme", theme);
}, [theme]);
## ❌ 안티패턴 (Anti-Patterns)
return <ThemeCtx value={{ theme, set: setTheme }}>{children}</ThemeCtx>;
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export const useTheme = () => use(ThemeCtx);
```
### FOUC 방지 (inline script)
```html
<!-- <head> 의 first script — render-blocking 의 의도적 -->
<script>
(function () {
const t = localStorage.getItem("theme") || "system";
const resolved = t === "system"
? (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
: t;
document.documentElement.dataset.theme = resolved;
})();
</script>
```
### Tailwind 4 의 통합
```css
@import "tailwindcss";
@theme {
--color-bg: var(--bg);
--color-fg: var(--fg);
}
:root { --bg: #fff; --fg: #111; }
[data-theme="dark"] { --bg: #0a0a0a; --fg: #f5f5f5; }
```
```tsx
<div className="bg-bg text-fg"> theme-aware</div>
```
### System preference 의 listen
```ts
const mq = matchMedia("(prefers-color-scheme: dark)");
mq.addEventListener("change", (e) => {
if (localStorage.getItem("theme") === "system") {
document.documentElement.dataset.theme = e.matches ? "dark" : "light";
}
});
```
### View Transitions API (smooth swap)
```ts
function toggleTheme() {
if (!document.startViewTransition) {
flipTheme();
return;
}
document.startViewTransition(() => flipTheme());
}
```
```css
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 250ms;
}
```
### Brand variant (multi-tenant)
```css
[data-brand="acme"] { --color-primary: #FF6B35; }
[data-brand="globex"] { --color-primary: #2EB872; }
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Static site / blog | CSS variable + `data-theme` |
| SaaS multi-tenant | CSS variable + brand attribute layer |
| RN / Native | Theme context + StyleSheet (no CSS vars) |
| Tailwind 의 사용 | Tailwind 4 `@theme` + CSS variable |
| Email template | Inline styles + `prefers-color-scheme` media query |
**기본값**: CSS custom properties + `data-theme` attribute + inline FOUC script.
## 🔗 Graph
- 부모: [[CSS Architecture]] · [[Design Tokens]]
- 변형: [[Tailwind CSS 4]] · [[CSS-in-JS]]
- 응용: [[Dark Mode]] · [[Accessibility (a11y)]] · [[White Labeling]]
- Adjacent: [[CSS Custom Properties]] · [[View Transitions API]]
## 🤖 LLM 활용
**언제**: design token system 의 설계, dark mode 구현, multi-brand theming.
**언제 X**: simple 의 single-color brand 의 — 매 over-engineering.
## ❌ 안티패턴
- **JS-only theme**: setState 의 모든 component re-render — 매 slow 의.
- **Hard-coded color in component**: token 의 bypass — 매 swap 불가능.
- **No FOUC script**: hydration 전 wrong theme flash — 매 jarring UX.
- **Theme 의 localStorage 의만 의존**: SSR 의 server-render mismatch.
## 🧪 검증 / 중복
- Verified (MDN, web.dev, Tailwind CSS docs, Adobe Spectrum 의 token system).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 3-layer token + FOUC + View Transitions 추가 |
@@ -2,91 +2,221 @@
id: wiki-2026-0508-eslint-plugin-development
title: ESLint Plugin Development
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-ESPL-001]
aliases: [ESLint Custom Rules, ESLint Plugin Authoring]
duplicate_of: none
source_trust_level: A
confidence_score: 0.96
tags: [auto-reinforced, ESLint, plugin-development, static-Analysis, ast, JavaScript, dev-tooling, automation]
confidence_score: 0.9
verification_status: applied
tags: [eslint, plugin, ast, linting]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JavaScript/TypeScript
framework: ESLint 9
---
# [[ESLint-Plugin-Development|ESLint-Plugin-Development]]
# ESLint Plugin Development
## 📌 한 줄 통찰 (The Karpathy Summary)
> "우리 팀만의 보안 필터: 단순한 규칙 사용을 넘어, 프로젝트 고유의 설계 원칙이나 보안 취약점 정책을 감지하는 커스텀 로직을 플러그인 형태로 패키징하여 전사적으로 배포하고 코드 품질을 수평 전개하는 도구 제작기."
## 한 줄
> **"매 ESLint plugin은 AST visitor + RuleTester."**. ESLint 9 (2024-) Flat config 시대에는 plugin = `{rules, configs, processors}` object 의 export. 매 rule = `meta` (docs, fixable, schema) + `create(context)` returning visitor map (e.g., `CallExpression(node) { ... }`).
## 📖 구조화된 지식 (Synthesized Content)
ESLint 플러그인 개발(ESLint-Plugin-Development)은 여러 ESLint 규칙(Rules)과 설정(Configs)을 하나의 모듈로 묶어 다른 프로젝트에서 재사용할 수 있게 만드는 과정입니다.
## 매 핵심
1. **구조 요소**:
* **Rules**: 실제 코드를 검사하는 로직 (AST 방문 주체). ([[Custom-ESLint-Rules|Custom-ESLint-Rules]]와 연결)
* **Configs**: 권장되는 규칙 설정 세트 (예: `plugin:my-plugin/recommended`).
* **Processors**: `.md``.vue` 같은 비 JS 파일에서 JS 코드를 추출하는 전처리기.
2. **왜 중요한가?**:
* 대규모 조직에서 매번 각 프로젝트의 린트 설정을 복사-붙여넣기 할 필요 없이, 중앙 관리형 플러그인 정책을 통해 코드 표준 정책을 일회성으로 전파할 수 있기 때문임. ([[Efficiency|Efficiency]]와 연결)
### 매 AST 기반
- ESLint = ESTree spec (espree parser default; @typescript-eslint/parser for TS).
- 매 rule visitor가 specific node type 방문 — `Identifier`, `CallExpression`, `JSXElement`.
- `context.report({node, message, fix})` 으로 violation 보고.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거에는 단순한 정규표현식 정책 검사에 가까웠으나, 현대 정책은 강력한 '타입 정보 정책(Type-aware linting)'을 활용하여 타입스크립트의 타입 관계 정책까지 검증하는 고수준 플러그인 정책으로 발전함(RL Update).
- **정책 변화(RL Update)**: 이제는 단순 에러 감지 정책을 넘어, 복잡한 리팩토링 정책을 코드가 써진 순간 자동으로 수행(Fixer)해 주는 보좌진 역할을 수행함. ([[Quality-Control|Quality-Control]]와 연결)
### 매 Plugin shape (Flat config)
- ESLint 9+ deprecated `.eslintrc` 형식 — 매 `eslint.config.js` flat config.
- Plugin export = `{meta, rules, configs, processors}` — meta에 `name/version` 명시.
## 🔗 지식 연결 (Graph)
- [[Custom-ESLint-Rules|Custom-ESLint-Rules]], [[Efficiency|Efficiency]], [[Quality-Control|Quality-Control]], [[Technical-Architecture|Technical-Architecture]], Standard-Operating-Procedure, Automation
- **Key Tools**: Yeoman generator-eslint, AST Explorer.
---
### 매 응용
1. Internal style guide — 매 monorepo 의 component naming, import order.
2. Framework rules — `eslint-plugin-react`, `eslint-plugin-vue` 처럼 framework-specific.
3. Security lint — 매 dangerous API (eval, innerHTML) 금지.
4. Migration codemod — 매 deprecated API 의 자동 fixer.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 1. Minimal rule skeleton
```javascript
// rules/no-foo.js
export default {
meta: {
type: 'problem',
docs: { description: 'disallow Foo identifier', recommended: true },
fixable: 'code',
schema: [],
messages: { unexpected: "'{{name}}' is not allowed." },
},
create(context) {
return {
Identifier(node) {
if (node.name === 'Foo') {
context.report({
node,
messageId: 'unexpected',
data: { name: node.name },
fix: (fixer) => fixer.replaceText(node, 'Bar'),
});
}
},
};
},
};
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Plugin entry (ESM, ESLint 9 flat)
```javascript
// index.js
import noFoo from './rules/no-foo.js';
**선택 A를 써야 할 때:**
- *(TODO)*
const plugin = {
meta: { name: 'eslint-plugin-acme', version: '1.0.0' },
rules: { 'no-foo': noFoo },
};
**선택 B를 써야 할 때:**
- *(TODO)*
plugin.configs = {
recommended: {
plugins: { acme: plugin },
rules: { 'acme/no-foo': 'error' },
},
};
**기본값:**
> *(TODO)*
export default plugin;
```
## ❌ 안티패턴 (Anti-Patterns)
### 3. Consumer flat config
```javascript
// eslint.config.js
import acme from 'eslint-plugin-acme';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default [
acme.configs.recommended,
{ rules: { 'acme/no-foo': ['error'] } },
];
```
### 4. RuleTester (built-in test)
```javascript
import { RuleTester } from 'eslint';
import rule from '../rules/no-foo.js';
const tester = new RuleTester({
languageOptions: { ecmaVersion: 2024, sourceType: 'module' },
});
tester.run('no-foo', rule, {
valid: ['const Bar = 1;'],
invalid: [{
code: 'const Foo = 1;',
errors: [{ messageId: 'unexpected' }],
output: 'const Bar = 1;',
}],
});
```
### 5. TypeScript rule with @typescript-eslint
```typescript
import { ESLintUtils } from '@typescript-eslint/utils';
const createRule = ESLintUtils.RuleCreator(
(name) => `https://acme.dev/rules/${name}`,
);
export default createRule({
name: 'no-any',
meta: {
type: 'suggestion',
docs: { description: 'disallow any' },
schema: [],
messages: { noAny: 'Avoid any; use unknown.' },
},
defaultOptions: [],
create(context) {
return {
TSAnyKeyword(node) {
context.report({ node, messageId: 'noAny' });
},
};
},
});
```
### 6. Suggestions (non-auto fix)
```javascript
context.report({
node,
messageId: 'considerRename',
suggest: [{
messageId: 'renameToBar',
fix: (fixer) => fixer.replaceText(node, 'Bar'),
}],
});
```
### 7. AST exploration (astexplorer.net)
```javascript
// Visitor pattern — leverage selector strings
return {
'CallExpression[callee.name="eval"]'(node) {
context.report({ node, message: 'eval disallowed' });
},
};
```
### 8. Scope / variable analysis
```javascript
create(context) {
return {
Identifier(node) {
const scope = context.sourceCode.getScope(node);
const variable = scope.references.find((r) => r.identifier === node);
if (variable?.resolved?.defs[0]?.type === 'ImportBinding') {
// imported identifier
}
},
};
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Codebase-specific 매 규칙 | Internal plugin (private npm). |
| OSS 공유 | Publish `eslint-plugin-foo`. |
| TS-only | `@typescript-eslint/utils` `RuleCreator`. |
| 매 codemod 용 | jscodeshift / ts-morph (ESLint fix 보다 more powerful). |
| 매 단순 ban API | `no-restricted-syntax` config — plugin 불필요. |
**기본값**: 매 ESLint 9 flat config + `@typescript-eslint/utils` RuleCreator.
## 🔗 Graph
- 부모: [[ESLint]] · [[AST]]
- 변형: [[Stylelint Plugin]] · [[Biome]]
- 응용: [[Code Review Automation]] · [[Monorepo Tooling]]
- Adjacent: [[Prettier]] · [[TypeScript]]
## 🤖 LLM 활용
**언제**: AST visitor 작성, RuleTester case 생성, 매 selector string 의 작성.
**언제 X**: 매 cross-file 분석 (ESLint = single-file) — 매 ts-morph / lsif 사용.
## ❌ 안티패턴
- **Regex on source**: 매 source string regex 의 X — 매 AST 사용.
- **No tests**: 매 RuleTester 없는 rule 의 X — false positive 의 즉시 발생.
- **Auto-fix without safety**: 매 fix가 매 semantics 변경 시 `suggest` 사용.
- **`.eslintrc` in 2026**: 매 flat config 으로 migrate.
## 🧪 검증 / 중복
- Verified (ESLint 9 docs, eslint.org/docs/latest/extend).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — ESLint 9 flat config plugin authoring 패턴 |
@@ -1,98 +1,229 @@
---
id: wiki-2026-0508-effect-ts-및-ts-brand-라이브러리-활용
title: Effect TS 및 ts brand 라이브러리 활용
title: Effect TS 및 ts-brand 라이브러리 활용
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-C0B018]
aliases: [Effect-TS, ts-brand, Branded Types, Effect.gen]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [typescript, functional, effect-system, branded-types]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - [[Effect TS|Effect TS]] 및 [[ts-brand|ts-brand]] 라이브러리 활용"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: Effect
---
# [[Effect TS 및 ts-brand 라이브러리 활용|Effect TS 및 ts-brand 라이브러리 활용]]
# Effect TS 및 ts-brand 라이브러리 활용
## 📌 한 줄 통찰 (The Karpathy Summary)
> Effect TS와 ts-brand는 TypeScript에서 구조적으로 동일해 보이는 타입들을 서로 구별하기 위해 고안된 '브랜드 타입(Branded Types)' 패턴의 적용을 돕는 인기 있는 커뮤니티 라이브러리입니다 [1, 2]. TypeScript는 기본적으로 구조적 타이핑([[Structural Typing|Structural Typing]])을 따르지만, 이 라이브러리들을 활용하면 명목적(Nominal) 타이핑과 유사한 안전장치를 마련할 수 있습니다 [2, 3]. 이를 통해 개발자는 단순한 원시 타입(Primitive Type)을 넘어, 비즈니스 규칙이 검증된 안전하고 정교한 타입을 코드 전반에 강제할 수 있습니다 [1, 2].
## 한 줄
> **"매 typed effect system + nominal type 의 — TypeScript 의 의 ZIO/Cats 의 imported"**. Effect 의 의 async/error/dependency 의 의 single 의 `Effect<A, E, R>` 의 의 unify, ts-brand 의 의 structural type 의 의 nominal flavor 의 의 add. 2026 의 매 enterprise TS codebase 의 의 fast 의 emerging.
## 📖 구조화된 지식 (Synthesized Content)
- **ts-brand 라이브러리의 기능과 활용**
- `ts-brand`는 타입 브랜드(Type Brands)를 위한 사전 작성된 코드를 제공하여 개발자가 쉽게 브랜디드 타입을 사용할 수 있게 해주는 커뮤니티 패키지입니다 [2].
- 브랜딩을 위한 고급 기능을 제공하며 [4], 제네릭 `Brand` 타입을 내보내어 고유한 브랜드 타입들을 생성하는 데 활용됩니다 [2].
## 매 핵심
- **Effect TS 프레임워크의 브랜디드 타입 지원**
- Effect는 타입이 풍부한 TypeScript 애플리케이션을 구축하기 위한 범용 프레임워크로, 타입 브랜드를 다루기 위한 전용 `Brand` 유틸리티를 제공합니다 [5].
- 주요 유틸리티로 타입 내에서 브랜드 역할을 하는 제네릭 타입인 `Brand.Brand`와, 타입 브랜드 식별 함수를 반환하는 제네릭 함수인 `Brand.nominal`이 있으며, 이 둘을 결합하여 `ts-brand`와 유사한 브랜드 타입을 생성할 수 있습니다 [5].
- **단언(Assertion) 함수의 차별화**: `ts-brand``make`와 달리, Effect는 타입 브랜드 단언 함수를 만들기 위해 `Brand.refined`라는 별도의 함수를 제공합니다 [5]. 이 함수는 값이 제약 조건을 충족하는지 판별하는 함수와, 충족하지 않을 경우 에러를 던지는 함수 등 두 가지 매개변수를 받아 작동합니다 [5, 6].
- **메타데이터 활용**: Effect TS는 에러 처리나 내부 제어 흐름을 명확히 구분하기 위해 `_tag`와 같은 메타데이터 속성을 활용하는 패턴을 제공하며, 이는 복잡한 로직에서 일관된 에러 처리와 내부 로직 판별을 돕습니다 [7, 8].
### 매 Effect 의 type
- `Effect<A, E, R>` — 의 success `A`, 의 failure `E`, 의 requirement `R`.
- 매 lazy — 매 `Effect.runPromise` / `Effect.runSync` 의 의 actual 의 execute.
- 의 composable — `pipe`, `Effect.gen` 의 의 chain.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
### 매 ts-brand 의 nominal type
- 의 TypeScript structural — `string === string` 의 의 distinguishable X.
- Brand 의 의 `string & { __brand: "UserId" }` 의 의 phantom tag.
- 의 runtime cost zero — type-level only.
## 🔗 지식 연결 (Graph)
- **Related Topics:** Branded Types, Opaque Types, Nominal Typing, [[Structural Typing|Structural Typing]]
- **Projects/Contexts:** [[TypeScript_Type_Safety|TypeScript Type Safety]]
- **Contradictions/Notes:** 두 라이브러리는 모두 타입 안정성을 높이는 데 기여하지만, 타입 브랜드 단언 함수를 다루는 방식에서 차이를 보입니다. `ts-brand``make`를 활용하는 반면, `Effect TS`는 유효성 검사 함수와 에러 처리 함수를 분리하여 입력받는 `Brand.refined`를 사용하도록 설계되었습니다 [5, 6].
### 매 응용
1. Domain ID (UserId, OrderId 의 의 mix-up 의 prevent).
2. Validated value (Email, NonEmptyString).
3. Async pipeline 의 typed error.
4. Dependency injection (Effect Layer).
5. Retry/timeout/concurrency 의 declarative.
---
*Last updated: 2026-04-18*
## 💻 패턴
---
### ts-brand 기본
```ts
import type { Brand } from "ts-brand";
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
**언제 이 지식을 쓰는가:**
- *(TODO)*
const makeUserId = (s: string): UserId => s as UserId;
**언제 쓰면 안 되는가:**
- *(TODO)*
function getUser(id: UserId) { /* ... */ }
## 🧪 검증 상태 (Validation)
const uid = makeUserId("u_123");
const oid = "o_456" as OrderId;
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
getUser(uid);
// getUser(oid); // 매 compile error — UserId 의 X
// getUser("u_123"); // 매 compile error — raw string
```
## 🤔 의사결정 기준 (Decision Criteria)
### Validated brand (smart constructor)
```ts
type Email = Brand<string, "Email">;
**선택 A를 써야 할 때:**
- *(TODO)*
function parseEmail(s: string): Email | null {
return /^[^@]+@[^@]+\.[^@]+$/.test(s) ? (s as Email) : null;
}
**선택 B를 써야 할 때:**
- *(TODO)*
function sendMail(to: Email, subject: string) { /* ... */ }
**기본값:**
> *(TODO)*
const e = parseEmail(input);
if (e) sendMail(e, "hi"); // 매 type-narrowed 의 valid 의 only
```
## ❌ 안티패턴 (Anti-Patterns)
### Effect 기본
```ts
import { Effect, pipe } from "effect";
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
const fetchUser = (id: UserId): Effect.Effect<User, NetworkError | NotFoundError> =>
Effect.tryPromise({
try: () => fetch(`/api/users/${id}`).then((r) => {
if (r.status === 404) throw new NotFoundError(id);
return r.json();
}),
catch: (e) => e instanceof NotFoundError ? e : new NetworkError(e),
});
const program = pipe(
fetchUser(uid),
Effect.map((u) => u.email),
Effect.tap((email) => Effect.log(`Got: ${email}`)),
);
Effect.runPromise(program).then(console.log);
```
### Effect.gen (do-notation)
```ts
import { Effect } from "effect";
const program = Effect.gen(function* () {
const user = yield* fetchUser(uid);
const orders = yield* fetchOrders(user.id);
const valid = orders.filter((o) => o.status === "paid");
return { user, orderCount: valid.length };
});
```
### Typed retry / timeout
```ts
import { Effect, Schedule, Duration } from "effect";
const robust = pipe(
fetchUser(uid),
Effect.retry(Schedule.exponential(Duration.millis(100)).pipe(Schedule.compose(Schedule.recurs(3)))),
Effect.timeout(Duration.seconds(5)),
);
```
### Layer / dependency injection
```ts
import { Context, Effect, Layer } from "effect";
class Database extends Context.Tag("Database")<Database, {
query: (sql: string) => Effect.Effect<unknown[], DBError>;
}>() {}
const DatabaseLive = Layer.succeed(Database, {
query: (sql) => Effect.tryPromise({ try: () => pool.query(sql), catch: (e) => new DBError(e) }),
});
const program = Effect.gen(function* () {
const db = yield* Database;
const rows = yield* db.query("SELECT * FROM users");
return rows;
});
Effect.runPromise(program.pipe(Effect.provide(DatabaseLive)));
```
### Schema (Effect's Zod-equivalent)
```ts
import { Schema } from "effect";
const User = Schema.Struct({
id: Schema.String.pipe(Schema.brand("UserId")),
email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+$/), Schema.brand("Email")),
age: Schema.Number.pipe(Schema.int(), Schema.between(0, 150)),
});
type User = Schema.Schema.Type<typeof User>;
const decoded = Schema.decodeUnknownSync(User)(input);
```
### 의 Concurrency
```ts
import { Effect } from "effect";
const fetchAll = Effect.all(
[fetchUser(u1), fetchUser(u2), fetchUser(u3)],
{ concurrency: 2 },
);
```
### 의 Either (sync error)
```ts
import { Either } from "effect";
const safeParse = (s: string): Either.Either<number, "not_a_number"> => {
const n = Number(s);
return Number.isNaN(n) ? Either.left("not_a_number") : Either.right(n);
};
```
### Effect 의 React (effect-rx)
```tsx
import { useRxSuspense } from "@effect-rx/rx-react";
const userRx = Rx.make((get) => fetchUser(get(userIdRx)));
function UserProfile() {
const user = useRxSuspense(userRx);
return <div>{user.email}</div>;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Domain ID 의 의 mix-up 의 prevent | ts-brand 의만 |
| Validated value (email, URL) | ts-brand 의 + smart constructor |
| Complex async pipeline | Effect TS |
| Typed error + retry + timeout | Effect TS |
| DI 의 의 typed | Effect Layer |
| Simple fetch + try/catch | 매 plain async — Effect 의 X |
**기본값**: ts-brand 의 의 always, Effect 의 의 의 complex pipeline 의만.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Functional Programming]]
- 변형: [[fp-ts]] · [[ZIO]] · [[neverthrow]]
- 응용: [[Discriminated Unions for Error Handling]] · [[Dependency Injection]]
- Adjacent: [[Zod]] · [[Branded Types]] · [[Schema Validation]]
## 🤖 LLM 활용
**언제**: typed pipeline 의 design, domain ID safety, layer-based DI, schema-driven decode.
**언제 X**: 의 매 simple CRUD — 매 Effect 의 learning curve 의 의 not worth.
## ❌ 안티패턴
- **`as UserId` 의 의 raw string 의 의 cast**: 의 brand 의 의 bypass — 의 smart constructor 의 의 always.
- **Effect 의 의 entire codebase 의 의 force**: 의 team 의 의 buy-in 의 X 의 시 의 — 매 friction.
- **`Effect.runSync` 의 의 async 의**: 의 throw 의 의 — runPromise 의 의 사용.
- **Mutable state 의 의 Effect 의**: 의 referential transparency 의 의 violation — Ref/Layer 의 의 사용.
- **Brand 의 의 nested 의 reuse**: `Brand<Brand<string, "A">, "B">` 의 의 confusing — 매 single brand 의 keep.
## 🧪 검증 / 중복
- Verified (Effect-TS docs effect.website, ts-brand npm, ZIO inspiration, Effect Schema docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Effect.gen + Layer + Schema + ts-brand smart constructor 추가 |
@@ -2,119 +2,229 @@
id: wiki-2026-0508-equipment-crafting-and-synthesis
title: Equipment Crafting and Synthesis Engine
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Crafting System, Item Synthesis, Forge System]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.85
verification_status: applied
tags: [game-dev, frontend, ui, crafting, gameplay]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React
---
# Equipment Crafting and Synthesis Engine
Skybound의 장비 시스템은 전장에서의 획득을 넘어, 기지(Hangar)에서의 합성 및 연성을 통해 종결급 스펙에 도달하는 **Meta-game Loop**를 구성합니다.
## 매 한 줄
> **"매 input item 의 set 의 의 output item 의 deterministic/stochastic 의 transformation 의 system"**. Diablo, Path of Exile, Genshin Impact 의 의 matter 의 core loop. 2026 의 frontend 의 의 reactive preview + server-authoritative resolution 의 standard pattern.
## 1. Synthesis Logic: Triple Merge (트리플 머지)
`CraftingSystem`은 동일한 종류와 등급의 장비 3개를 소모하여 상위 단계의 장비 1개를 연성하는 방식을 채택합니다.
## 매 핵심
- **Required Count**: 반드시 동일 아이템 3개가 필요합니다.
- **Progression Flow**: `NORMAL``GOOD``BETTER``EXCELLENT``EPIC``LEGEND``ETERNAL` (최종)
- **Stat Spike**: 등급 상승 시 베이스 스탯(`Attack`, `HP`)이 이전 단계 대비 약 **1.5배(50%)** 강력해지며, 이동 속도가 소폭 보정됩니다.
### 매 architecture layer
- **Recipe 의 catalog**: input pattern → output spec (data-driven JSON).
- **Resolver**: input 의 match 의 recipe 의 find 의 — pattern matching engine.
- **Roller**: stochastic 의 modifier roll (affix, stat range).
- **Preview UI**: reactive 의 — input 의 change 의 의 result 의 의 live recompute.
- **Server commit**: 의 authoritative 의 final roll — 매 client 의 prediction 의 의 validate.
## 2. Disassembly: Resource Extraction (분해 및 추출)
불필요하거나 전략적으로 가치가 낮은 고등급 장비를 파괴하여 특수 재화를 획득할 수 있습니다.
### 매 stochastic 의 vs 의 deterministic
- **Deterministic**: 의 fixed output (e.g. base item + recipe → fixed legendary).
- **Stochastic**: 의 random affix (rarity tier, stat range, modifier pool).
- **Hybrid**: deterministic base + stochastic affix.
- **Standard Scrap**: 일반 장비 분해 시 기본 강화 재료(Materials)를 획득합니다.
- **Eternal Core Extraction**: `S_CLASS` 이상의 장비를 분해할 경우, SS급 장비 연성에 필요한 핵심 재료인 `Core`를 추출할 수 있습니다.
- S-Class: Core 1개
- SS-Class: Void Core 5개
### 매 응용
1. RPG forge (sword + 의 gem → enchanted sword).
2. Gacha synthesis (3-star × 3 → 4-star upgrade).
3. Crafting MMORPG (pattern + 의 material → gear).
4. Auto-battler item merge (3 의 의 same → upgraded).
## 3. Visual & UI Integration (Hangar UI)
장비 제작 시스템은 `HangarUI.css`에 정의된 등급별 고유 색상 및 글로우 이펙트(`shadowBlur`)와 연동되어 시각적 희귀도를 직관적으로 전달합니다.
## 💻 패턴
## 4. Key Implementation References
- `src/features/game/systems/CraftingSystem.ts`: 합성 및 분해 코어 엔진.
- `src/features/game/model/equipment.ts`: 등급 체계 및 합성 규칙 상수 정의.
### Recipe 의 schema
```ts
type Recipe = {
id: string;
inputs: ItemPattern[]; // ordered or set
ordered: boolean;
output: OutputSpec;
cost?: { gold?: number; energy?: number };
unlockLevel?: number;
};
---
**Status**: Managed by Skybound Protocol
**Context**: Meta-Game Economy / Progression Engineering
**Tags**: #Growth_Loop #Mechanics #Progression
type ItemPattern =
| { kind: "exact"; itemId: string; qty: number }
| { kind: "tag"; tag: string; rarity?: Rarity; qty: number };
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[Logic]]
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
type OutputSpec =
| { kind: "fixed"; itemId: string }
| { kind: "rolled"; baseItemId: string; affixPools: AffixPool[] };
```
## 🤔 의사결정 기준 (Decision Criteria)
### Resolver (pattern match)
```ts
function findRecipe(inputs: Item[], catalog: Recipe[]): Recipe | null {
return catalog.find((r) => matches(r, inputs)) ?? null;
}
**선택 A를 써야 할 때:**
- *(TODO)*
function matches(recipe: Recipe, inputs: Item[]): boolean {
const remaining = [...inputs];
for (const pat of recipe.inputs) {
const idx = remaining.findIndex((it) => itemMatchesPattern(it, pat));
if (idx === -1) return false;
remaining.splice(idx, 1);
}
return remaining.length === 0;
}
**선택 B를 써야 할 때:**
- *(TODO)*
function itemMatchesPattern(item: Item, pat: ItemPattern): boolean {
if (pat.kind === "exact") return item.itemId === pat.itemId;
return item.tags.includes(pat.tag) && (!pat.rarity || item.rarity === pat.rarity);
}
```
**기본값:**
> *(TODO)*
### Affix roller (seeded)
```ts
import { xoshiro256ss } from "./prng";
## ❌ 안티패턴 (Anti-Patterns)
type AffixPool = { tag: string; weight: number; statRange: [number, number] };
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
function rollAffixes(pools: AffixPool[], count: number, seed: bigint): Affix[] {
const rng = xoshiro256ss(seed);
const result: Affix[] = [];
const available = [...pools];
for (let i = 0; i < count && available.length > 0; i++) {
const total = available.reduce((s, p) => s + p.weight, 0);
let r = rng() * total;
const idx = available.findIndex((p) => (r -= p.weight) < 0);
const pool = available[idx];
available.splice(idx, 1);
const [lo, hi] = pool.statRange;
result.push({ tag: pool.tag, value: lo + rng() * (hi - lo) });
}
return result;
}
```
### React 의 craft preview UI
```tsx
function CraftBench({ inventory }: { inventory: Item[] }) {
const [slots, setSlots] = useState<Item[]>([]);
const recipe = useMemo(() => findRecipe(slots, RECIPE_CATALOG), [slots]);
const preview = useMemo(() => {
if (!recipe) return null;
if (recipe.output.kind === "fixed") return { kind: "fixed", item: ITEM_DB[recipe.output.baseItemId] };
return { kind: "rolled", base: recipe.output.baseItemId, affixCount: recipe.output.affixPools.length };
}, [recipe]);
return (
<div className="grid grid-cols-2 gap-4">
<SlotGrid slots={slots} setSlots={setSlots} inventory={inventory} />
<PreviewPanel recipe={recipe} preview={preview} onCraft={() => craft(slots)} />
</div>
);
}
```
### Server-authoritative commit
```ts
// Client
async function craft(inputs: Item[]) {
const r = await fetch("/api/craft", {
method: "POST",
body: JSON.stringify({ inputIds: inputs.map((i) => i.instanceId) }),
});
if (!r.ok) throw new Error("craft failed");
return r.json() as Promise<CraftResult>;
}
// Server (authoritative seed)
function handleCraft(req) {
const inputs = loadInventory(req.userId, req.inputIds);
const recipe = findRecipe(inputs, CATALOG);
if (!recipe) return { ok: false, reason: "no_match" };
const seed = BigInt(`0x${randomBytes(8).toString("hex")}`);
const result = applyOutput(recipe.output, seed);
consumeInputs(req.userId, inputs);
grantItem(req.userId, result);
return { ok: true, item: result, seed: seed.toString() };
}
```
### Drag-drop 의 slot
```tsx
function Slot({ item, onDrop }: { item?: Item; onDrop: (it: Item) => void }) {
return (
<div
onDragOver={(e) => e.preventDefault()}
onDrop={(e) => {
const id = e.dataTransfer.getData("text/plain");
const it = INVENTORY.get(id);
if (it) onDrop(it);
}}
className="border-2 border-dashed h-24 w-24 grid place-items-center"
>
{item ? <ItemIcon item={item} /> : <span>+</span>}
</div>
);
}
```
### Probability 의 display
```tsx
function ProbabilityBar({ pools }: { pools: AffixPool[] }) {
const total = pools.reduce((s, p) => s + p.weight, 0);
return (
<ul>
{pools.map((p) => (
<li key={p.tag}>
{p.tag} {((p.weight / total) * 100).toFixed(1)}%
</li>
))}
</ul>
);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Casual game / mobile | Deterministic recipe — 매 predictability |
| ARPG / Diablo-like | Stochastic affix + 의 base 의 deterministic |
| Gacha / loot | Stochastic 의 의 server seed 의 authoritative |
| Single-player offline | Client RNG 의 OK |
| Multiplayer competitive | 매 server 의 의 seed 의 — anti-cheat |
**기본값**: data-driven recipe + server-rolled affix + reactive preview UI.
## 🔗 Graph
- 부모: [[Game UI Architecture]] · [[Inventory System]]
- 변형: [[Gacha System]] · [[Auto-Battler Merge]]
- 응용: [[Loot System]] · [[Affix Generation]] · [[Item Rarity]]
- Adjacent: [[Server Authority]] · [[Seeded RNG]] · [[Drag-and-Drop UI]]
## 🤖 LLM 활용
**언제**: crafting recipe schema 설계, affix pool weighting, preview reactive UI.
**언제 X**: 매 simple 의 single-purpose game (puzzle, runner) — 매 over-engineering.
## ❌ 안티패턴
- **Client-only roll**: 매 trivially exploitable (replay, save-scum).
- **Hard-coded recipe**: data-driven 의 X 의 — designer iteration 의 dev rebuild 의 require.
- **Hidden probability**: regulator 의 (China, Korea, Japan) 의 force disclose.
- **Synchronous animate-then-commit**: 매 latency 의 bad UX — optimistic preview 의 즉시 + server 의 confirm.
## 🧪 검증 / 중복
- Verified (Diablo IV crafting docs, Path of Exile wiki, Genshin gacha rates, GDC talks 의 crafting design).
- 신뢰도 B+ — game-specific 의 variance.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — recipe schema + affix roller + server authority 추가 |
+183 -86
View File
@@ -2,117 +2,214 @@
id: wiki-2026-0508-error-boundaries
title: Error Boundaries
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [React Error Boundary, ErrorBoundary, getDerivedStateFromError]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [react, error-handling, frontend, resilience]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React
---
## 📌 한 줄 통찰 (The Karpathy Summary)
Error Boundaries는 React 컴포넌트 트리 하위에서 발생하는 JavaScript 런타임 에러를 포착하여 전체 애플리케이션의 크래시(White Screen)를 방지하는 선언적 에러 처리 메커니즘이다. 에러가 발생한 지점을 격리하고 대체 UI(Fallback UI)를 렌더링함으로써 시스템의 가용성과 사용자 경험을 보호한다.
# Error Boundaries
## 📖 구조화된 지식 (Synthesized Content)
1. **작동 메커니즘 및 클래스 컴포넌트 의존성**
- React 16부터 도입되었으며, 자식 컴포넌트의 렌더링, 수명 주기 메서드, 생성자 내부의 에러를 감지한다.
- 반드시 클래스 컴포넌트로 구현해야 하며, `static getDerivedStateFromError()`로 상태를 업데이트하고 `componentDidCatch()`로 에러를 로깅한다.
2. **선언적 에러 격리 (Isolation)**
- 명령형 `try/catch`와 달리 React의 선언적 특성을 유지하며 컴포넌트 트리 수준에서 에러를 관리한다.
- 애플리케이션 전체가 아닌, 실패 위험이 높은 특정 위젯(차트, 서드파티 폼 등)을 독립된 Boundary로 감싸 '장애 격리'를 실현한다.
3. **포착 불가능한 영역 (Limitations)**
- 이벤트 핸들러, 비동기 코드(setTimeout, Fetch), 서버 사이드 렌더링(SSR), Error Boundary 자체 내의 에러는 포착하지 못한다.
- 이러한 영역은 여전히 `try/catch`나 전역 에러 핸들러를 통한 보완이 필요하다.
4. **미처리 에러의 결과**
- 포착되지 않은 에러는 전체 컴포넌트 트리의 마운트 해제(Unmounting)를 유발하며, 이는 손상된 데이터가 사용자에게 노출되는 것보다 안전한 선택으로 간주된다.
## 매 한 줄
> **"매 React subtree 의 의 render-time error 의 catch 의 의 fallback UI 의 의 swap 의 component"**. 의 entire app crash 의 의 prevent 의 — 의 try/catch 의 declarative React equivalent. 2026 의 의 매 React 19 의 still 의 class component 의만 의 의 Error Boundary 의 author 의 가능 (의 hook API 의 X).
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **클래스 컴포넌트 유지 필요성**: 최신 React가 Hooks 중심임에도 불구하고 Error Boundary 구현을 위해 클래스 컴포넌트를 유지해야 하는 아키텍처적 일관성 저하가 발생할 수 있다.
- **성능 및 렌더링 오버헤드**: 너무 많은 Error Boundary를 중첩할 경우 트리 깊이가 깊어지고 에러 전파 체크 로직에 따른 미세한 성능 영향이 있을 수 있다.
- **비동기 에러 처리의 공백**: 렌더링 에러만 포착하므로, 비동기 데이터 통신이 빈번한 현대 앱에서는 `react-error-boundary`와 같은 라이브러리를 통한 추가 처리가 필수적이다.
## 매 핵심
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[Frontend]]
* [[JavaScript]]
* [[Observability]]
* [[React]]
* [[Research]]
### 매 catch 의 X 의 것
- Event handler error (의 try/catch 의 사용).
- Async code (setTimeout, promise) — Error Boundary 의 의 reach 의 X.
- SSR (의 server-side throw 의 의 catch 의 의 X).
- Boundary itself 의 throw.
### Related Concepts
- **Fallback UI**: 에러 발생 시 사용자에게 노출되는 방어적 인터페이스 (관계: 출력 결과물)
- **Component Stack Traces**: 에러 발생 위치를 추적하는 런타임 정보 (관계: 디버깅 핵심 데이터)
- **Sentry / LogRocket**: 프로덕션 환경의 에러 수집 및 분석 플랫폼 (관계: 운영 모니터링 연동)
### 매 catch 의 것
- 의 child render error.
- 의 lifecycle method error.
- 의 constructor error.
### Deeper Research Questions
1. React의 내부 Fiber 아키텍처는 Error Boundary를 만났을 때 어떻게 렌더링 작업을 중단하고 커밋 단계로 전이하는가?
2. 이벤트 핸들러 내의 에러를 Error Boundary로 강제 전파하기 위한 'setState' 트릭의 원리와 한계는?
3. `react-error-boundary` 라이브러리가 함수형 컴포넌트 환경에서 클래스 컴포넌트의 한계를 극복하는 방식은?
4. 단일 전역 Error Boundary와 다중 지역 Error Boundary 간의 메모리 사용량 및 리렌더링 범위 트레이드오프는?
5. 서버 사이드 렌더링(SSR) 환경에서 클라이언트 사이드 Error Boundary가 활성화되기 전의 에러는 어떻게 처리해야 하는가?
### 매 hierarchy strategy
- **Top-level**: 의 fallback "Something went wrong" 의 의 entire app crash 의 의 prevent.
- **Route-level**: 의 broken page 의만 의 의 fail.
- **Widget-level**: 의 chart, embed, third-party 의 의 isolate.
### Practical Application Contexts
- **결제 및 금융 모듈**: 입력 폼의 작은 렌더링 오류가 전체 결제 프로세스 마비로 이어지지 않도록 격리.
- **서드파티 위젯 통합**: 안정성이 검증되지 않은 외부 라이브러리 기반 컴포넌트를 Boundary로 보호.
### 매 응용
1. Production crash 의 reporting (Sentry, Datadog).
2. Third-party widget 의 isolation.
3. Per-route error UI (Next.js `error.tsx`).
4. Suspense fallback combo (loading + error).
### Adjacent Topics
- **Try/Catch Statement in JS**
- **Observability in Frontend**
- **Graceful Degradation Design**
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 기본 class boundary
```tsx
import { Component, type ReactNode, type ErrorInfo } from "react";
**언제 이 지식을 쓰는가:**
- *(TODO)*
type Props = { fallback: ReactNode; onError?: (e: Error, info: ErrorInfo) => void; children: ReactNode };
type State = { hasError: boolean };
**언제 쓰면 안 되는가:**
- *(TODO)*
export class ErrorBoundary extends Component<Props, State> {
state: State = { hasError: false };
## 🧪 검증 상태 (Validation)
static getDerivedStateFromError(): State {
return { hasError: true };
}
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
componentDidCatch(error: Error, info: ErrorInfo) {
this.props.onError?.(error, info);
}
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
render() {
return this.state.hasError ? this.props.fallback : this.props.children;
}
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### react-error-boundary 라이브러리
```tsx
import { ErrorBoundary } from "react-error-boundary";
**선택 A를 써야 할 때:**
- *(TODO)*
function Fallback({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void }) {
return (
<div role="alert">
<p>Something went wrong:</p>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
);
}
**선택 B를 써야 할 때:**
- *(TODO)*
<ErrorBoundary
FallbackComponent={Fallback}
onError={(error, info) => Sentry.captureException(error, { extra: info })}
onReset={() => queryClient.resetQueries()}
>
<Dashboard />
</ErrorBoundary>
```
**기본값:**
> *(TODO)*
### Suspense + ErrorBoundary 의 combo
```tsx
<ErrorBoundary FallbackComponent={Fallback}>
<Suspense fallback={<Skeleton />}>
<UserProfile id={userId} />
</Suspense>
</ErrorBoundary>
```
## ❌ 안티패턴 (Anti-Patterns)
### 의 async event 의 의 manual rethrow
```tsx
function useAsyncError() {
const [, setState] = useState();
return useCallback((e: unknown) => {
setState(() => { throw e; });
}, []);
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
function MyComponent() {
const throwAsync = useAsyncError();
const onClick = async () => {
try {
await fetchData();
} catch (e) {
throwAsync(e); // 매 ErrorBoundary 의 의 reach
}
};
return <button onClick={onClick}>Load</button>;
}
```
### Next.js App Router `error.tsx`
```tsx
"use client";
export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
useEffect(() => { console.error(error); }, [error]);
return (
<div>
<h2>Something went wrong</h2>
<button onClick={reset}>Retry</button>
</div>
);
}
```
### Per-route boundary
```tsx
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={
<ErrorBoundary FallbackComponent={HomeFailed}><Home /></ErrorBoundary>
} />
<Route path="dashboard" element={
<ErrorBoundary FallbackComponent={DashFailed}><Dashboard /></ErrorBoundary>
} />
</Route>
</Routes>
```
### 의 Sentry 의 integrate
```tsx
import * as Sentry from "@sentry/react";
const SentryBoundary = Sentry.withErrorBoundary(MyApp, {
fallback: ({ error, resetError }) => <Fallback error={error} resetErrorBoundary={resetError} />,
showDialog: true,
});
```
### Reset on prop change
```tsx
<ErrorBoundary
FallbackComponent={Fallback}
resetKeys={[userId]} // 의 userId 의 의 change 의 시 의 boundary reset
>
<UserProfile id={userId} />
</ErrorBoundary>
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Top-level app crash 의 prevent | Single root boundary + telemetry |
| Route 의 isolation | Per-route boundary (Next.js `error.tsx`) |
| Third-party widget | Tight boundary 의 의 widget 의만 |
| Async data fetch | TanStack Query 의 `throwOnError` + boundary |
| Form validation | Inline error UI — 매 boundary 의 X |
**기본값**: root + per-route + per-widget — 매 layered boundaries.
## 🔗 Graph
- 부모: [[React]] · [[Error Handling]]
- 변형: [[Suspense]] · [[Next.js error.tsx]] · [[react-error-boundary]]
- 응용: [[Sentry Integration]] · [[Crash Reporting]] · [[Resilient UI]]
- Adjacent: [[Discriminated Unions for Error Handling]] · [[TanStack Query]]
## 🤖 LLM 활용
**언제**: production crash protection, third-party widget isolation, Suspense + error 의 combo.
**언제 X**: form-level validation — 매 inline UI 의 더 적합.
## ❌ 안티패턴
- **No top-level boundary**: 의 single child throw 의 의 entire app white-screen.
- **Boundary over async without rethrow**: 의 catch 의 의 fail — 의 manual rethrow 의 필요.
- **Eat error silently**: 매 telemetry 의 의 X — debug 의 impossible.
- **Reset 의 의 X**: user 의 의 retry 의 의 way 의 X — stuck 의 fallback.
- **getDerivedStateFromError 의 의 side effect**: pure function 의 의 의 violation.
## 🧪 검증 / 중복
- Verified (React 19 docs, react-error-boundary, Next.js App Router error handling, Sentry React SDK).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — async rethrow + Next.js error.tsx + reset key 추가 |
@@ -2,111 +2,194 @@
id: wiki-2026-0508-error-handling-and-stability
title: Error Handling and Stability
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [e1r2r3o4-h5a6-4n7d-l8i9-n0g1s2t3a4b5]
aliases: [Frontend Error Boundaries, Error Recovery]
duplicate_of: none
source_trust_level: A
confidence_score: 0.99
tags: [react, error-handling, stability, error-boundary, monitoring, resilience]
confidence_score: 0.9
verification_status: applied
tags: [errors, stability, observability, sentry]
raw_sources: []
last_reinforced: 2026-05-01
github_commit: wikification-error-handling
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React/Vue
---
# Frontend Error Handling & Application Stability
# Error Handling and Stability
## 📌 한 줄 통찰 (The Karpathy Summary)
> 프론트엔드 안정성은 모든 에러를 막는 것이 아니라, 발생한 에러가 전체 앱의 화이트 스크린으로 번지지 않도록 구획을 나누고(Error Boundary), 실시간 모니터링을 통해 빠르게 인지하고 복구하는 회복 탄력성(Resilience)에 있다.
## 한 줄
> **"매 frontend stability = error 의 isolation + telemetry + graceful degradation."**. 매 single uncaught error가 매 SPA 의 전체 white-screen 의 유발 — 매 ErrorBoundary, global handlers (`window.onerror`, `unhandledrejection`), 매 Sentry-class telemetry 가 필수. 매 2026의 트렌드는 React 19 ErrorBoundary + Sentry + Replay + AI-driven root-cause clustering.
## 📖 구조화된 지식 (Synthesized Content)
### 1. 계층적 에러 처리 전략
- **Error Boundaries**: React 컴포넌트 트리 상위에서 하위 컴포넌트의 런타임 에러를 캡처하여 사용자에게 대체 UI를 보여준다. 핵심 비즈니스 영역별로 안전장치를 배치한다.
- **Global Error Handling**: `window.onerror`, `unhandledrejection` 이벤트를 구독하여 예기치 못한 비동기 에러를 전역에서 캡처하고 서버로 전송한다.
- **Local Error Handling**: `try-catch` 블록과 API 요청 계층의 인터셉터를 활용하여 사용자에게 즉각적인 피드백을 제공한다.
## 매 핵심
### 2. 애플리케이션 안정성 확보
- **Fallback UI**: 에러 발생 시 단순히 앱을 중단시키는 대신, 새로고침 버튼이나 고객센터 연결 등 다음 행동을 유도하는 UI를 제공한다.
- **Graceful Degradation**: 일부 기능(예: 추천 목록)이 실패하더라도 핵심 기능(예: 결제)은 유지될 수 있도록 모듈 간 결합도를 낮춘다.
### 매 layers
- **Component**: React ErrorBoundary, Vue `errorCaptured`, Svelte `<svelte:boundary>`.
- **Async**: try/catch, Promise `.catch`, `unhandledrejection` listener.
- **Global**: `window.onerror`, `window.onunhandledrejection`.
- **Network**: fetch retry, circuit breaker, AbortController.
### 3. 모니터링 및 분석
- **Sentry 통합**: 에러 발생 시점의 사용자 세션, 기기 정보, 스택 트레이스를 수집하여 재현 및 수정을 용이하게 한다.
### 매 telemetry 기둥
- Capture (stack, breadcrumb, source map).
- Group (fingerprint, dedup).
- Alert (threshold, regression).
- Replay (Sentry / LogRocket — DOM reconstruction).
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과도한 에러 무시**: 모든 에러를 묵묵히 처리하면 실제 심각한 논리 오류를 놓칠 수 있다. 로그 수집과 경고 알림(Alerting) 체계가 병행되어야 한다.
- **에러 바운더리의 한계**: 이벤트 핸들러나 비동기 코드 내부의 에러는 Error Boundary가 직접 캡처하지 못하므로 별도의 처리가 필요하다.
### 매 응용
1. SPA route-level boundary — 매 chunk load fail 의 reload prompt.
2. Form submission retry with exponential backoff.
3. Feature flag fallback when remote config unavailable.
4. Service Worker offline shell.
## 🔗 지식 연결 (Graph)
- **Parent**: 10_Wiki/Topics/Development
- **Related**: Frontend Governance & Observability, Sentry and LogRocket Integration
- **Raw Source**: 00_Raw/Error Handling, 00_Raw/Frontend Application Stability, 00_Raw/React 애플리케이션 예\354\231\270 \353\260\217 \354\227\220\353\237\254 \354\262\230\353\246\254
## 💻 패턴
## 💻 GitHub 동기화 자동화 워크플로우
1. Stage: git add .
2. Commit: `git commit -m "[P-Reinforce] Wikify Frontend Error Handling and Application Stability Standard"`
3. Push: `git push origin main`
### 1. React ErrorBoundary (class)
```typescript
import { Component, type ReactNode } from 'react';
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[2026-05-01]]
* [[Boundaries]]
* [[Error Boundaries]]
* [[Frontend]]
* [[Frontend_Governance_and_Observability]]
* [[Observability]]
* [[P-Reinforce]]
* [[React]]
* [[Resilience]]
interface State { error?: Error }
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export class ErrorBoundary extends Component<{ fallback: ReactNode; children: ReactNode }, State> {
state: State = {};
static getDerivedStateFromError(error: Error): State { return { error }; }
componentDidCatch(error: Error, info: React.ErrorInfo) {
Sentry.captureException(error, { extra: { componentStack: info.componentStack } });
}
render() {
return this.state.error ? this.props.fallback : this.props.children;
}
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. react-error-boundary (functional)
```typescript
import { ErrorBoundary } from 'react-error-boundary';
**선택 A를 써야 할 때:**
- *(TODO)*
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<div role="alert">
<p>Failed: {error.message}</p>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
)}
onReset={() => location.reload()}
>
<App />
</ErrorBoundary>
```
**선택 B를 써야 할 때:**
- *(TODO)*
### 3. Global handlers
```typescript
window.addEventListener('error', (e) => {
Sentry.captureException(e.error ?? new Error(e.message));
});
window.addEventListener('unhandledrejection', (e) => {
Sentry.captureException(e.reason);
});
```
**기본값:**
> *(TODO)*
### 4. Chunk load failure recovery
```typescript
const lazyWithRetry = <T,>(load: () => Promise<{ default: T }>) =>
React.lazy(async () => {
try {
return await load();
} catch (err) {
if (!sessionStorage.getItem('chunk-retried')) {
sessionStorage.setItem('chunk-retried', '1');
location.reload();
}
throw err;
}
});
```
## ❌ 안티패턴 (Anti-Patterns)
### 5. Fetch retry with backoff
```typescript
async function fetchRetry(url: string, retries = 3, delay = 500): Promise<Response> {
try {
const res = await fetch(url);
if (!res.ok && res.status >= 500) throw new Error(`HTTP ${res.status}`);
return res;
} catch (err) {
if (retries === 0) throw err;
await new Promise((r) => setTimeout(r, delay));
return fetchRetry(url, retries - 1, delay * 2);
}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### 6. AbortController on unmount
```typescript
useEffect(() => {
const ac = new AbortController();
fetch('/api/x', { signal: ac.signal }).catch((e) => {
if (e.name !== 'AbortError') report(e);
});
return () => ac.abort();
}, []);
```
### 7. Sentry init (2026)
```typescript
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration({ maskAllText: false }),
],
tracesSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
release: import.meta.env.VITE_RELEASE,
});
```
### 8. Vue 3 errorHandler
```typescript
import { createApp } from 'vue';
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
Sentry.captureException(err, { extra: { info } });
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Component-local fail | ErrorBoundary at route level. |
| Async fail | try/catch + telemetry. |
| Chunk 404 (deploy mid-session) | lazyWithRetry + reload. |
| Transient 5xx | Exponential backoff retry. |
| Auth expired | Refresh token interceptor. |
**기본값**: Sentry + Replay + per-route ErrorBoundary + global handlers.
## 🔗 Graph
- 부모: [[Observability]] · [[Web Reliability]]
- 변형: [[Server Error Handling]] · [[Circuit Breaker]]
- 응용: [[Sentry]] · [[Datadog RUM]] · [[Logrocket]]
- Adjacent: [[Source Maps]] · [[Feature Flags]]
## 🤖 LLM 활용
**언제**: ErrorBoundary scaffolding, retry helper 작성, Sentry config.
**언제 X**: 매 root-cause analysis from minified stack — 매 source map upload 필수.
## ❌ 안티패턴
- **Swallow errors**: 매 `catch {}` 빈 — 매 silent fail.
- **No source map**: 매 prod stack 의 `a.b.c` — 매 debug X.
- **Boundary at root only**: 매 한 component fail이 매 entire app crash.
- **Console.error as monitoring**: 매 user 의 console 의 도달 X — telemetry 필수.
## 🧪 검증 / 중복
- Verified (Sentry docs, react.dev error boundary).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Error boundary + Sentry 2026 patterns |
+186 -62
View File
@@ -1,88 +1,212 @@
---
id: wiki-2026-0508-es-lint-configuration
title: Es Lint Configuration
title: ESLint Configuration
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [ESLint Config, eslint.config.js, Flat Config]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: ["JavaScript|[JavaScript", Tooling, ESLint, StaticAnalysis]
confidence_score: 0.9
verification_status: applied
tags: [eslint, linting, javascript, typescript, tooling]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: javascript
framework: eslint
---
# [[Es-Lint-Configuration|Es-Lint-Configuration]] (ESLint 설정 가이드)
# ESLint Configuration
## 📌 한 줄 통찰 (The Karpathy Summary)
> "천 명의 개발자가 한 명의 개발자처럼 코딩하게 만드는 규칙의 파수꾼." 소스 코드를 정적으로 분석하여 잠재적 버그를 찾고, 팀 내 합의된 코딩 컨벤션을 강제로 집행하는 도구다.
## 한 줄
> **"매 ESLint v9+ flat config (`eslint.config.js`) 는 array-of-config-objects 의 explicit composition"**. Legacy `.eslintrc.*` 의 deprecated. 매 modern setup 의 typescript-eslint, prettier integration, framework presets (Next, React) 의 mix.
## 📖 구조화된 지식 (Synthesized Content)
- **Configuration Layers**:
- **[[Parser|Parser]]**: TS, Babel 등 최신 문법을 분석할 수 있게 변환.
- **Plugins**: 특정 프레임워크 전용 규칙 추가 (React, NestJS 등).
- **Extends**: 구글, 에어비앤비 등에서 검증된 설정 세트를 그대로 상속.
- **Rules**: 'off', 'warn', 'error' 3단계로 개별 규칙의 엄격도 조절.
- **Auto-fix**: 저장 시점에 세미콜론 누락, 안 쓰는 변수 제거 등을 자동으로 교정하여 생산성 향상.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- 최신 ESLint(v9+)는 설정 파일 형식이 완전히 바뀐 'Flat Config' 시대로 진입했다. 기존 `eslintrc.*` 방식은 레거시가 되었으므로, 새로운 프로젝트에서는 `eslint.config.js`를 사용해야 한다. 또한 포맷팅 전용 도구인 [[Prettier|Prettier]]와 충돌하지 않도록 역할 분담(Linter: 논리검사, Formatter: 모양검사)을 명확히 하는 것이 핵심이다.
### 매 Flat Config (v9+)
- Single `eslint.config.js` (or `.mjs`) at project root.
- Exports array; each entry: `{ files, ignores, languageOptions, plugins, rules, ... }`.
- No `extends` — use `...config` spread.
- No `env` — use `globals` from `globals` package.
## 🔗 지식 연결 (Graph)
- Related: Prettier-Configuration , [[Custom-ESLint-Rules-Development|Custom-ESLint-Rules-Development]]
- Part of: [[SAST (Static Application Security Testing)|SAST (Static Application Security [[Testing]])]]
### 매 Core Concepts
- **languageOptions**: parser, parserOptions, globals.
- **plugins**: object map (`{ pluginName: pluginObject }`).
- **rules**: 'off' / 'warn' / 'error' (or 0/1/2), with config tuple `['error', opts]`.
- **files**: glob array (e.g. `['**/*.ts']`) — scope rules.
- **ignores**: replaces `.eslintignore`.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. TypeScript project linting (typescript-eslint).
2. React/Next.js framework rules.
3. Monorepo per-package overrides.
4. Prettier integration (eslint-config-prettier).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Minimal Modern Config
```js
// eslint.config.js (ESM)
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import globals from 'globals';
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export default [
{ ignores: ['dist/**', 'node_modules/**', '.next/**'] },
js.configs.recommended,
...tseslint.configs.recommended,
{
languageOptions: {
ecmaVersion: 2024,
sourceType: 'module',
globals: { ...globals.browser, ...globals.node },
},
rules: {
'no-console': ['warn', { allow: ['warn', 'error'] }],
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
];
```
## 🤔 의사결정 기준 (Decision Criteria)
### React + TypeScript
```js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import jsxA11y from 'eslint-plugin-jsx-a11y';
**선택 A를 써야 할 때:**
- *(TODO)*
export default [
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parserOptions: { project: './tsconfig.json' },
},
plugins: { react, 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y },
settings: { react: { version: 'detect' } },
rules: {
...react.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'react/react-in-jsx-scope': 'off', // not needed in React 17+
'react/prop-types': 'off', // TS handles this
},
},
];
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Next.js (15+)
```js
import next from '@next/eslint-plugin-next';
**기본값:**
> *(TODO)*
export default [
// ... base configs
{
plugins: { '@next/next': next },
rules: {
...next.configs.recommended.rules,
...next.configs['core-web-vitals'].rules,
},
},
];
```
## ❌ 안티패턴 (Anti-Patterns)
### Prettier Integration
```bash
npm i -D eslint-config-prettier
```
```js
import prettier from 'eslint-config-prettier';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default [
// ... your configs
prettier, // MUST be last — disables ESLint formatting rules
];
```
### Per-File Overrides
```js
export default [
// base
{
files: ['**/*.test.{ts,tsx}'],
languageOptions: { globals: { ...globals.jest } },
rules: { '@typescript-eslint/no-explicit-any': 'off' },
},
{
files: ['scripts/**/*.js'],
languageOptions: { sourceType: 'commonjs' },
},
];
```
### Type-Aware Rules
```js
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
project: true, // auto-find nearest tsconfig
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
},
}
```
### package.json Scripts
```json
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:cache": "eslint . --cache --cache-location .cache/eslint"
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New project (2026) | Flat config (v9+) |
| Legacy `.eslintrc` | Migrate via `@eslint/migrate-config` |
| Formatting | Prettier; eslint-config-prettier last |
| Type-aware rules | parserOptions.project: true |
| Monorepo | Root config + per-package overrides via files glob |
**기본값**: flat config + typescript-eslint recommended-type-checked + Prettier integration.
## 🔗 Graph
- 부모: [[ESLint]] · [[Code Quality]]
- 변형: [[typescript-eslint]] · [[Biome]] (alternative) · [[oxlint]] (alternative)
- 응용: [[Pre-commit Hooks]] · [[CI Linting]]
- Adjacent: [[Prettier]] · [[TSConfig]] · [[Husky]]
## 🤖 LLM 활용
**언제**: ESLint setup, rule conflict 의 debug, flat config migration.
**언제 X**: extreme performance — Biome / oxlint 의 consider.
## ❌ 안티패턴
- **`.eslintrc.*` in v9+**: deprecated, no longer auto-loaded.
- **Prettier as ESLint plugin (`eslint-plugin-prettier`)**: slow, conflict-prone. Use Prettier separately + eslint-config-prettier.
- **`extends` in flat config**: doesn't exist; use spread.
- **Global rules without `files` scope in monorepo**: lints unintended files.
- **Disabling whole categories**: targeted overrides 의 prefer.
## 🧪 검증 / 중복
- Verified (eslint.org docs — flat config, typescript-eslint v8 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — ESLint flat config full content |
@@ -2,98 +2,32 @@
id: wiki-2026-0508-eugen-systems의-warno-시뮬레이션-개발
title: Eugen Systems의 WARNO 시뮬레이션 개발
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: eugen-systems-modding-manual
duplicate_of: "[[Eugen Systems 모딩 매뉴얼]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, game-dev, modding, warno]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# Eugen Systems의 WARNO 시뮬레이션 개발
## 📌 한 줄 통찰 (The Karpathy Summary)
Eugen Systems가 개발한 WARNO는 1989년 냉전이 열전으로 번진 가상의 시나리오를 배경으로 하는 실시간 전술(RTT) 및 턴제 전략 시뮬레이션 게임입니다 [1, 2]. 이 게임은 자체 개발한 Iriszoom 엔진을 통해 세밀한 3D 그래픽과 대규모 전장을 매끄럽게 구현하며, NDF(Neutral Data Format)라는 독자적인 스크립트 언어를 활용한 데이터 아키텍처를 기반으로 설계되었습니다 [3-5]. 개발진은 커뮤니티의 피드백뿐만 아니라 객관적인 텔레메트리(Telemetry) 데이터를 실시간으로 분석하여 무기 스펙과 사단 편제 등 시뮬레이션의 전술적 밸런스를 정교하게 조정합니다 [6, 7].
> **이 문서는 [[Eugen Systems 모딩 매뉴얼]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **Iriszoom 엔진과 시각적 가시화:**
WARNO는 과거 R.U.S.E.부터 진화해 온 Eugen Systems의 독자 엔진인 Iriszoom의 최신 버전을 사용합니다 [3, 4]. 이 엔진은 물리 기반 렌더링(PBR) 시스템과 Metallic/Roughness/Ambient Occlusion 워크플로우를 도입하여 4K 해상도로 유닛과 지형의 질감을 매우 사실적으로 구현합니다 [3, 4, 8]. 기술적으로 지연 렌더링(Deferred Rendering) 구조를 활용해 수백 대의 유닛이 맞붙는 10 대 10 멀티플레이어 환경에서도 뛰어난 최적화를 유지하며, 탄약고 유폭 시 포탑이 날아가거나 헬기 로터 블레이드가 떨어져 나가는 동적 파괴 시스템이 물리 데이터와 연동되어 표현됩니다 [4, 9-11].
## 핵심 요약 (specialization aspects)
- WARNO 의 IRISZOOM engine 의 simulation pipeline.
- NDF script 의 unit/weapon definition.
- ModTools 의 의 export workflow.
* **NDF(Neutral Data Format) 기반의 데이터 아키텍처:**
시뮬레이션의 모든 논리적 설계와 유닛 메커니즘은 NDF(Neutral Data Format)라는 텍스트 기반의 자체 스크립트 언어로 정의되어 있습니다 [5, 12]. 게임의 소스 코드와 데이터가 엄격히 분리된 이 객체 지향적 구조 덕분에, 개발자나 유저(모더)들은 `UniteDescriptor.ndf`, `WeaponDescriptor.ndf`, `Ammunition.ndf` 등의 데이터 파일만 수정하여 유닛의 명중률, 관통력, 이동 속도, 장갑 수치 등을 쉽게 제어할 수 있습니다 [5, 13-15]. 이러한 개방적이고 모듈화된 데이터 설계는 RebsFRAGO와 같이 무기 데이터를 실제 현실의 제원값으로 치환하는 정교한 현실주의 모드의 탄생을 가능하게 했습니다 [5, 16-18].
## 🔗 Graph
- 부모: [[Eugen Systems 모딩 매뉴얼]] (canonical)
* **사단 시스템(Division System)을 통한 데이터 제약과 밸런스:**
Wargame 시리즈의 자유로운 국가별 덱(National Deck) 시스템과 달리, WARNO는 역사적인 사단 편제표(TO&E)에 기반한 '사단 시스템'을 채택했습니다 [19-21]. 각 사단은 부여된 활성화 포인트(Activation Points) 안에서 유닛을 구성해야 하며, 부대별로 배치 가능한 유닛의 종류와 카드당 가용 유닛 수(Availability), 포인트 비용 등 고유의 데이터 패널티와 이점을 가집니다 [7, 19, 21, 22]. 이는 플레이어가 모든 분야에서 완벽한 무적의 군대를 조합하는 것을 막고, 지형과 사단의 강점을 결합한 비대칭적 전술을 유도하기 위한 데이터 설계입니다 [21, 23, 24].
* **텔레메트리(Telemetry) 기반 밸런싱과 수학적 정밀도:**
게임 내 전투 역학은 거리 비례 명중률(가까울수록 기하급수적으로 상승), 승수적으로 작용하는 항공기 ECM(전자전) 데이터, 무기 사거리 등 복잡한 수학적 모델을 따릅니다 [25-28]. Eugen Systems는 이렇게 복잡하게 얽힌 시스템을 밸런싱하기 위해 플레이어들의 유닛 선택률(Pick rate), 교전 승률, 평균 생존 시간 등을 추적하는 '텔레메트리 데이터'를 활용합니다 [6, 7]. 개발진은 커뮤니티의 단순한 여론에 휩쓸리지 않고 수집된 객관적 데이터를 분석하여, 특정 유닛이나 사단이 과도한 효율을 낼 경우 NDF 파일의 포인트 비용이나 세부 스펙을 정밀하게 조정하는 방식을 취합니다 [6, 7, 29].
## 🔗 지식 연결 (Graph)
- **Related Topics:** `[[Iriszoom 엔진|Iriszoom 엔진]]`, `[[NDF (Neutral Data Format)|NDF (Neutral Data Format)]]`, `[[사단 시스템 (Division System)|사단 시스템 (Division System)]]`, `[[텔레메트리 (Telemetry) 밸런싱|텔레메트리 (Telemetry) 밸런싱]]`
- **Projects/Contexts:** `[[WARNO|WARNO]]`, `[[Wargame 시리즈|Wargame 시리즈]]`, `[[Steel Division 시리즈|Steel Division 시리즈]]`, `[[RebsFRAGO 모드|RebsFRAGO 모드]]`
- **Contradictions/Notes:** 덱 구성 아키텍처와 관련하여, 일부 유저들은 과거 Wargame 시리즈처럼 제약이 없는 국가별 덱 시스템이 유저의 창의성을 높인다고 주장하지만, 개발진과 다른 다수의 유저들은 사단 시스템(Division System)이 메타 고착화를 방지하고 훨씬 다양하고 역사적으로 몰입감 있는 밸런스를 제공한다고 반박합니다 [19, 30-34].
---
*Last updated: 2026-04-28*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+158 -78
View File
@@ -2,104 +2,184 @@
id: wiki-2026-0508-events
title: Events
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [DOM Events, Event Handling, JavaScript Events]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [frontend, dom, events, javascript]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: javascript
framework: dom
---
# [[Events|Events]]
# Events
## 📌 한 줄 통찰 (The Karpathy Summary)
게임 오브 워(Game of War) 및 4X 전략 게임에서 '이벤트(Events)'는 플레이어의 장기적 참여와 사회적 협력, 그리고 지속적인 수익 창출(Monetization)을 유도하기 위해 설계된 핵심적인 기간 한정 활동입니다. 이러한 이벤트는 매일 진행되는 소규모 일과부터 다수의 왕국(서버)이 맞붙는 대규모 전쟁에 이르기까지 다양하게 구성되며, 라이브옵스(LiveOps) 스케줄과 촘촘하게 결합되어 유저들의 결제를 강력하게 촉진합니다. 최상위 이벤트의 결과는 서버의 존폐나 최고 권력의 향방을 결정지을 만큼 막대한 영향력을 지닙니다.
## 한 줄
> **"매 DOM event 는 capture → target → bubble 3-phase 의 propagation"**. Events 는 user/system action (click, input, scroll, ...) 을 JS handler 에 dispatch 하는 mechanism. 매 modern app 의 React SyntheticEvent / addEventListener / passive listener 의 mix 의 사용.
## 📖 구조화된 지식 (Synthesized Content)
* **라이브옵스(LiveOps)와 결제(Monetization)의 핵심 동력**
* 이벤트는 4X 전략 게임에서 유저의 유지(Retention)를 수익으로 전환하는 가장 중요한 수단입니다 [1].
* '즉각적 수익화 전략(Immediate Monetization Strategy)'을 사용하는 게임들은 한 번에 최대 15개에 달하는 정규 및 시즌 이벤트를 동시에 진행하며 플레이어를 압도합니다. 각 이벤트의 보상과 진행도가 서로 맞물려 있어, 유저가 끊임없이 이벤트에 참여하고 그 과정에서 자연스럽게 패키지 상품을 구매하도록 설계되어 있습니다 [1, 2].
* 반면, '점진적 수익화 전략(Gradual Monetization Strategy)'을 취하는 게임들은 이벤트의 밀도를 낮추어 플레이어가 다수의 활동에 쫓기지 않고 개별 이벤트에만 집중할 수 있게 하여 장기적인 몰입을 유도하기도 합니다 [3].
## 매 핵심
* **대규모 엔드게임 이벤트: KvK (Kingdom vs. Kingdom)**
* KvK는 서버(왕국) 간의 자존심을 건 총력전으로, 왕국의 보호막이 해제되고 교차 서버 간 텔레포트 및 직접적인 침공이 허용되는 대규모 이벤트입니다 [4, 5].
* 일반적으로 매치메이킹, 준비(건설/연구 등으로 포인트 획득), 전투(적 왕국 침공), 치료 및 복구(Triage)의 4단계로 나뉘어 진행됩니다 [6, 7].
* KvK는 단일 서버의 생존이 걸린 '사활을 건(life or death)' 이벤트로 취급되며, KvK에서 지속적으로 패배하는 왕국은 유저들이 다른 서버로 이탈해버리는 "서버 사망(kingdom death)"을 겪게 되므로 모든 플레이어의 강제적인 참여와 과금을 유도합니다 [8].
### 매 Event Phases
- **Capture phase**: root → target (top-down). `{ capture: true }` 의 trigger.
- **Target phase**: target element 의 listener.
- **Bubble phase**: target → root (default). `e.stopPropagation()` 의 중단.
* **최고 권력을 향한 전쟁: 슈퍼 원더(Super Wonder)**
* 슈퍼 원더 이벤트는 한 달에 한 번 24시간 동안만 열리며, 모든 활성 서버의 최고 연맹들이 '용의 왕국(Kingdom of Dragons)'에 모여 그랜드 왕좌를 차지하기 위해 싸우는 이벤트입니다 [9, 10].
* 이벤트 종료 시점에 왕좌를 가장 오래 점유한 플레이어는 '황제(Emperor)'로 등극하며, 전 서버를 아우르는 강력한 통치권과 막대한 스탯 버프(예: 공격력 +2,600% 증가 등) 칭호를 다른 플레이어들에게 부여할 수 있는 특권을 얻습니다 [4, 9, 11, 12].
### 매 Event Types
- **Mouse**: click, dblclick, mousedown/up, mousemove, mouseenter/leave (no bubble), mouseover/out (bubble).
- **Keyboard**: keydown, keyup (NOT keypress — deprecated).
- **Touch/Pointer**: pointerdown/up/move (unified mouse+touch), touchstart/move/end.
- **Form**: input (every keystroke), change (commit), submit, focus/blur (no bubble), focusin/out (bubble).
- **Lifecycle**: DOMContentLoaded, load, beforeunload, visibilitychange.
- **Custom**: `new CustomEvent('foo', { detail: {...} })`.
* **일일 및 정규 왕국 이벤트(Regular Kingdom Events)**
* 대규모 전투 외에도 건설(Build), 병력 훈련, 몬스터 사냥(Kill Monster) 등 일상적인 행동과 연계된 이벤트들이 끊임없이 순환합니다 [13].
* 자신의 왕국 내에서 요새를 점령하거나 특정 토큰을 모으는 도미네이션(Domination) 이벤트, 포트리스 킬(Fortress Kill) 이벤트 등을 통해 유저들 간의 상호작용과 경쟁을 일상적으로 유도합니다 [14].
### 매 응용
1. UI interaction (button click, form submit).
2. Event delegation (single listener for many children).
3. Drag-and-drop (pointer events).
4. Keyboard shortcuts / accessibility.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Kingdom vs. Kingdom (KvK)|Kingdom vs. Kingdom (KvK)]], Super Wonder, [[LiveOps|LiveOps]], [[수익화(Monetization)|Monetization]]
- **Projects/Contexts:** Game of War: Fire Age BM 및 구조, 4X 전략 게임 이벤트 구조
- **Contradictions/Notes:** 소스에 따르면 4X 게임의 수익화 전략에 따라 이벤트 운영 철학이 극명하게 갈립니다. 일부 게임(예: Puzzles & Survival)은 이벤트를 고밀도로 중첩시켜 강한 과금 압박과 행동을 유도하는 반면, 다른 게임(예: State of Survival, King of Avalon)은 이벤트의 수를 제한하고 UI에서 숨길 수 있는 선택권까지 제공하여 유저의 피로도를 낮추고 장기적인 신뢰를 구축하는 방식을 택합니다 [1-3, 15].
## 💻 패턴
---
*Last updated: 2026-04-27*
### Basic addEventListener
```js
button.addEventListener('click', (e) => {
console.log('clicked', e.target);
});
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// removeEventListener requires same fn reference
const handler = (e) => console.log(e);
el.addEventListener('click', handler);
el.removeEventListener('click', handler);
```
## 🤔 의사결정 기준 (Decision Criteria)
### Event Delegation
```js
// Single listener on parent — handles all child clicks
document.querySelector('#list').addEventListener('click', (e) => {
const item = e.target.closest('[data-id]');
if (!item) return;
console.log('item:', item.dataset.id);
});
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Passive Listener (Scroll Performance)
```js
// Tells browser handler won't preventDefault → no scroll-blocking
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('touchmove', onTouchMove, { passive: true });
```
**선택 B를 써야 할 때:**
- *(TODO)*
### AbortController (modern cleanup)
```js
const ctrl = new AbortController();
el.addEventListener('click', handler, { signal: ctrl.signal });
el.addEventListener('mouseover', other, { signal: ctrl.signal });
// Remove all at once
ctrl.abort();
```
**기본값:**
> *(TODO)*
### Stop Propagation vs Prevent Default
```js
form.addEventListener('submit', (e) => {
e.preventDefault(); // cancel default (form GET/POST)
e.stopPropagation(); // don't bubble to ancestors
});
```
## ❌ 안티패턴 (Anti-Patterns)
### Custom Events
```js
const evt = new CustomEvent('user:login', {
detail: { userId: 42 },
bubbles: true,
});
element.dispatchEvent(evt);
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
document.addEventListener('user:login', (e) => {
console.log(e.detail.userId);
});
```
### React SyntheticEvent
```jsx
function Button() {
// React pools events; e.persist() no longer needed (React 17+)
const onClick = (e) => {
console.log(e.nativeEvent); // underlying DOM event
console.log(e.currentTarget);
};
return <button onClick={onClick}>Click</button>;
}
```
### Pointer Events (drag)
```js
let dragging = false;
el.addEventListener('pointerdown', (e) => {
el.setPointerCapture(e.pointerId);
dragging = true;
});
el.addEventListener('pointermove', (e) => {
if (!dragging) return;
el.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`;
});
el.addEventListener('pointerup', (e) => {
el.releasePointerCapture(e.pointerId);
dragging = false;
});
```
### Debounce / Throttle
```js
function debounce(fn, ms) {
let t;
return (...args) => {
clearTimeout(t);
t = setTimeout(() => fn(...args), ms);
};
}
input.addEventListener('input', debounce(search, 300));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 다수 child 의 listener | Delegation (single parent listener) |
| Scroll/touch handler | `{ passive: true }` |
| 다수 listener cleanup | `AbortController` |
| Mouse + touch unified | Pointer events |
| Cross-component coordination | CustomEvent or state library |
**기본값**: `addEventListener` + delegation + AbortController for cleanup.
## 🔗 Graph
- 부모: [[DOM]] · [[JavaScript]]
- 변형: [[Pointer Events]] · [[Custom Events]] · [[React SyntheticEvent]]
- 응용: [[Event Delegation]] · [[Drag and Drop]] · [[Keyboard Shortcuts]]
- Adjacent: [[Accessibility]] · [[Performance]]
## 🤖 LLM 활용
**언제**: event listener pattern 의 question, propagation 의 debug, delegation 의 implement.
**언제 X**: framework-specific event system 의 deep dive (React/Vue 의 own docs 의 참조).
## ❌ 안티패턴
- **Inline `onclick=""` attribute**: HTML/JS 의 mix, CSP 의 violation.
- **No cleanup in SPA**: memory leak. 매 unmount 의 removeEventListener 의 호출.
- **`scroll` without passive**: 60fps scroll 의 block.
- **`stopPropagation()` overuse**: delegation pattern 의 break.
- **Listener on every list item**: N 의 listener 대신 delegation 의 사용.
## 🧪 검증 / 중복
- Verified (MDN Web Docs — Event reference, WHATWG DOM spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DOM event handling full content |
+145 -66
View File
@@ -2,93 +2,172 @@
id: wiki-2026-0508-eye-tracking
title: Eye Tracking
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-EYTR-001]
aliases: [Gaze Tracking, Eye Gaze, Foveated Rendering Input]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced, eye-tracking, hci, Biometrics, attention, usability]
confidence_score: 0.85
verification_status: applied
tags: [eye-tracking, xr, vr, ar, accessibility, ux]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: webxr
---
# [[Eye-Tracking|Eye-Tracking]]
# Eye Tracking
## 📌 한 줄 통찰 (The Karpathy Summary)
> "시선의 목격자: 사용자의 눈이 어디를 보고, 어디에 머물며, 어떤 경로로 움직이는지 정밀하게 추적하여 인간의 관심도와 인지 부하를 데이터로 읽어내는 사용자 경험 분석의 끝판왕 도구."
## 한 줄
> **"매 eye tracking 은 user gaze direction 의 measure — pupil/cornea reflection 또는 ML model 의 사용"**. 2026 의 mainstream: Apple Vision Pro, Meta Quest 3S Pro, PSVR2. 매 foveated rendering, gaze-based UI selection, accessibility (ALS), UX research 의 enables.
## 📖 구조화된 지식 (Synthesized Content)
시선 추적(Eye-Tracking)은 눈의 위치와 움직임을 측정하여 시선의 방향을 파악하는 기술입니다.
## 매 핵심
1. **주요 지표**:
* **Fixation (고정)**: 특정 지점에 시선이 머무는 것. (관심/처리 중)
* **Saccade (도약)**: 한 지점에서 다른 지점으로 빠르게 움직이는 것.
* **Heatmap**: 시선이 집중된 영역을 색상으로 시각화. ([[Design-System|Design-System]] 검증에 활용)
2. **활용 분야**:
* **UI/UX [[Research|Research]]**: 사용자가 중요한 버튼을 찾지 못하는지 확인.
* **Medical**: 자폐증이나 치매 초기 진단.
* **Gaming/VR**: 시선이 머무는 곳만 고해상도로 렌더링(Foveated Rendering)하여 [[Efficiency|Efficiency]] 극대화.
### 매 Sensing Methods
- **PCCR (Pupil Center Corneal Reflection)**: IR LED illumination + IR camera. Sub-degree accuracy, dedicated HW (Tobii, Vision Pro).
- **Webcam-based ML**: WebGazer.js, MediaPipe Iris. ~3-5° accuracy, no special HW.
- **Electrooculography (EOG)**: skin electrodes; medical/lab use.
- **Scleral search coil**: highest precision, invasive (research only).
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거에는 전용 안경이나 수천만 원대 장비 정책이 필수였으나, 현대 정책은 딥러닝과 웹캠만으로 시선을 추적하는 '범용 카메라 기반 소프트웨어 정책'으로 대중화됨(RL Update).
- **정책 변화(RL Update)**: 광고나 마케팅 정책에서 시선을 강제로 빼앗는 '다크 패턴 정책'에 대한 규제와, 시선 데이터가 개인의 무의식을 드러낸다는 점에서 발생하는 '생체 정보 시선 프라이버시 정책'이 강화되고 있음.
### 매 Output Data
- **Gaze point**: 2D screen coord or 3D ray.
- **Pupil diameter**: cognitive load proxy.
- **Fixations**: stable gaze (>100ms) — what user actually reads.
- **Saccades**: rapid eye movement between fixations.
- **Smooth pursuit**: tracking moving target.
## 🔗 지식 연결 (Graph)
- User Experience (UX), [[Design-System|Design-System]], [[Affective Computing|Affective Computing]], [[Analysis|Analysis]], [[Cognitive Biases|Cognitive Biases]]
- **Modern Tech/Tools**: Tobii, Gazepoint, Webcam-based eye trackers (Webgazer.js).
---
### 매 응용
1. Foveated rendering (high-res only at gaze point — VR perf 4-10x).
2. Gaze + pinch UI selection (Apple Vision Pro paradigm).
3. Accessibility: gaze-typing for ALS/locked-in patients.
4. UX research: heatmaps, attention analysis.
5. Driver monitoring (drowsiness detection).
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
### WebGazer.js (browser, no HW)
```js
import webgazer from 'webgazer';
**언제 쓰면 안 되는가:**
- *(TODO)*
await webgazer.setRegression('ridge')
.setGazeListener((data, timestamp) => {
if (!data) return;
console.log('gaze:', data.x, data.y); // screen px
})
.begin();
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// User must calibrate by clicking around
```
## 🤔 의사결정 기준 (Decision Criteria)
### MediaPipe Iris (TF.js)
```js
import * as faceLandmarksDetection from '@tensorflow-models/face-landmarks-detection';
**선택 A를 써야 할 때:**
- *(TODO)*
const detector = await faceLandmarksDetection.createDetector(
faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh,
{ runtime: 'tfjs', refineLandmarks: true } // refine = iris landmarks
);
**선택 B를 써야 할 때:**
- *(TODO)*
const faces = await detector.estimateFaces(video);
const irisLeft = faces[0].keypoints.filter(k => k.name?.includes('leftIris'));
const irisRight = faces[0].keypoints.filter(k => k.name?.includes('rightIris'));
```
**기본값:**
> *(TODO)*
### WebXR Eye Tracking (Vision Pro Safari, Quest)
```ts
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['eye-tracking'],
});
## ❌ 안티패턴 (Anti-Patterns)
session.requestAnimationFrame(function onFrame(t, frame) {
const eyeSpace = session.requestReferenceSpace('viewer');
const gaze = frame.getViewerPose(eyeSpace);
// gaze.transform.position / orientation = gaze ray
session.requestAnimationFrame(onFrame);
});
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Fixation Detection (I-DT algorithm)
```ts
// Identification by Dispersion Threshold
function detectFixations(gazePoints: {x:number, y:number, t:number}[],
dispersionPx = 50, minDurationMs = 100) {
const fixations = [];
let window: typeof gazePoints = [];
for (const p of gazePoints) {
window.push(p);
const xs = window.map(g => g.x), ys = window.map(g => g.y);
const disp = (Math.max(...xs) - Math.min(...xs))
+ (Math.max(...ys) - Math.min(...ys));
if (disp > dispersionPx) {
const dur = window[window.length-2].t - window[0].t;
if (dur >= minDurationMs) fixations.push(window.slice(0, -1));
window = [p];
}
}
return fixations;
}
```
### Foveated Rendering Hint (WebGPU)
```ts
// VRS / foveated rendering via GPU extension (browser-dependent)
const passEncoder = encoder.beginRenderPass({
colorAttachments: [...],
// implementation-specific: shading rate texture pointing at gaze
});
```
### Heatmap from Fixations
```ts
function buildHeatmap(fixations, w, h, sigma = 30) {
const map = new Float32Array(w * h);
for (const f of fixations) {
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
const d2 = (x-f.x)**2 + (y-f.y)**2;
map[y*w+x] += Math.exp(-d2 / (2*sigma*sigma)) * f.duration;
}
}
return map;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| VR/AR headset (2026) | Native eye-tracking API (visionOS, OpenXR ext) |
| Browser, accuracy critical | Tobii / dedicated HW + SDK |
| Browser, no HW | WebGazer.js or MediaPipe Iris (lower accuracy) |
| Accessibility input | Tobii Eye Tracker 5 + Windows Eye Control |
| UX research | Tobii Pro / GazePoint + heatmap tool |
**기본값**: 매 platform 의 native eye-tracking API. Browser fallback: MediaPipe Iris.
## 🔗 Graph
- 부모: [[Human Computer Interaction]] · [[XR]]
- 변형: [[Foveated Rendering]] · [[Gaze Interaction]]
- 응용: [[Accessibility]] · [[UX Research]] · [[VR Optimization]]
- Adjacent: [[Apple Vision Pro]] · [[WebXR]] · [[MediaPipe]]
## 🤖 LLM 활용
**언제**: gaze-based UI 의 design, foveated rendering question, accessibility input.
**언제 X**: physiological eye-disease diagnosis (clinical 의 ophthalmologist).
## ❌ 안티패턴
- **No calibration**: webcam-based 의 every-user calibration 의 require.
- **Click-on-gaze without dwell time**: Midas touch problem — every glance triggers.
- **Storing raw gaze without consent**: PII / biometric (GDPR Art. 9).
- **Webcam ML for safety-critical**: insufficient accuracy (driver assist 의 dedicated HW).
- **Ignoring head movement**: gaze ≠ pupil position; head pose 의 compensate.
## 🧪 검증 / 중복
- Verified (Apple visionOS docs, OpenXR EXT_eye_gaze_interaction, Tobii Developer Zone).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — eye tracking full content |
+143 -101
View File
@@ -1,128 +1,170 @@
---
id: wiki-2026-0508-fabric
title: Fabric
category: Frontend
status: needs_review
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [React Native Fabric, Fabric Renderer, RN New Architecture]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [auto-wikified, technical-documentation, frontend]
confidence_score: 0.9
verification_status: applied
tags: [react-native, fabric, renderer, mobile, jsi]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: cpp
framework: react-native
---
# Fabric
## 📌 한 줄 통찰 (The Karpathy Summary)
Fabric React Native의 새로운 아키텍처(New Architecture)를 구성하는 핵심 요소 중 하나로, 밑바닥부터 완전히 새롭게 재작성된 새로운 UI 렌더링 시스템(UI 관리 레이어)이다 [1, 2]. 기존의 비동기 브릿지(Bridge) 방식의 병목 현상을 해결하기 위해 설계되었으며, 네이티브 UI 레이어에 대한 동기적 접근을 가능하게 한다 [1, 2]. 이를 통해 동시성 렌더링(Concurrent Rendering)과 동기적인 레이아웃 계산을 지원하며, 결과적으로 React Native 애플리케이션의 네이티브 렌더링 성능과 응답성을 비약적으로 향상시킨다 [1, 2].
## 한 줄
> **"매 Fabric React Native 의 new renderer — JSI 기반 synchronous JS↔native 의 enables"**. 2018-2024 에 incrementally rolled out, RN 0.74+ 에서 default. 매 legacy bridge (async JSON serialization) 의 replace, 매 concurrent React features (Suspense, Transitions) 의 mobile 의 enable.
## 📖 구조화된 지식 (Synthesized Content)
* **동기적 네이티브 UI 접근 메커니즘**
기존 아키텍처에서는 UI가 별도의 네이티브 스레드에서 관리되고 자바스크립트 스레드와의 통신이 비동기식으로 이루어져 성능 지연이 발생했다 [1, 2]. Fabric은 이 구조를 혁신하여, C++에서 UI의 가상 표현인 '섀도 트리(Shadow Tree)'를 직접 생성하고 스레드 간에 공유할 수 있도록 한다 [1]. 이를 통해 비동기적인 왕복 통신(round-trips) 없이도 네이티브 뷰를 측정하고 렌더링할 수 있게 된다 [2].
## 매 핵심
* **동시성 렌더링(Concurrent Rendering) 지원**
Fabric은 React 18 및 그 이후 버전과 완벽하게 호환된다 [1]. 메인 스레드에서 데이터 페칭을 위한 Suspense나 Transitions와 같은 동시성 기능을 지원하며, 사용자 입력 등에 반응하기 위해 React가 렌더링의 우선순위를 재조정하거나 렌더링을 중단(interrupt)할 수 있도록 허용한다 [1, 2]. 이는 훨씬 더 유체적이고 반응성 높은 UI를 제공하는 핵심 기술이다 [1].
### 매 Architecture (vs Old Bridge)
- **Old bridge**: JS thread ↔ Native thread async JSON messages. Serialize cost, no sync calls, list jank.
- **Fabric**: JSI (JavaScript Interface) — JS engine (Hermes) 의 C++ HostObjects 의 direct access. Sync calls, shared memory, type-safe via codegen.
* **동기적 레이아웃 계산(Synchronous Layout)**
JSI(JavaScript Interface)를 기반으로 통신이 동기화됨에 따라, React Native는 네이티브 측에서 레이아웃을 측정 및 계산한 후 해당 정보를 동일한 렌더 사이클 내에서 자바스크립트 스레드에 제공할 수 있다 [1]. 이 구조적 변화는 UI 요소가 프레임 단위에서 위치가 튀는 현상(UI jump)을 근본적으로 해결해준다 [1].
### 매 Components
- **JSI**: lightweight C++ API for JS engines (Hermes/JSC). 매 binding의 base.
- **Fabric Renderer (C++)**: shadow tree, layout (Yoga), commit phase. 매 cross-platform.
- **TurboModules**: lazy-loaded native modules with codegen-typed interface.
- **Codegen**: TS/Flow types → C++/Java/ObjC native code.
- **Hermes**: default JS engine (faster startup, lower memory, bytecode).
* **네이티브 컴포넌트 수준의 고성능 애니메이션**
렌더링 로직을 C++로 이동시키고 직접 통신을 활성화함으로써, Fabric은 UI 컴포넌트의 렌더링 및 업데이트 소요 시간을 대폭 감소시킨다 [1]. 이러한 네이티브 컴포넌트 렌더링 제어를 통해 부드러운 애니메이션과 거의 네이티브 수준에 근접한 성능(near-native performance)을 달성하게 된다 [3, 4].
### 매 응용
1. React 18 concurrent features (Suspense, useTransition) on mobile.
2. Synchronous measure/layout queries.
3. Type-safe native module bindings.
4. New Architecture only libs (Reanimated 3, Skia).
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
소스에 관련 정보가 부족합니다.
단, 소스에 명시된 아키텍처 구조를 통해 유추할 수 있는 제약 사항으로는 Fabric이 단독으로 기능하기보다는 JSI(JavaScript Interface) 기반의 바인딩과 TurboModules 등 New Architecture의 다른 요소들과 완벽하게 결합되어야만 비동기 브릿지의 한계를 극복하고 완전한 성능 향상을 이룰 수 있다는 구조적 종속성이 존재한다 [2, 4-6]. 또한 기존 브릿지 기반으로 작성된 서드파티 네이티브 라이브러리들은 이 새로운 동기식 렌더링 파이프라인에 맞춰 호환성 업데이트를 거쳐야 할 수 있다 [7, 8].
## 💻 패턴
## 🔗 지식 연결 (Graph)
### Related Concepts
### Enable New Architecture (RN 0.76+)
```bash
# Default ON in 0.76+; explicit:
# ios/Podfile
# RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
#### [관계 유형 A (아키텍처/기반 기술)]
- [[React Native New Architecture]]
- 연결 이유: Fabric은 TurboModules, JSI와 함께 React Native의 성능 병목을 해결하기 위해 도입된 'New Architecture'를 구성하는 핵심 삼위일체 중 하나이다 [2, 8].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비동기 브릿지를 제거한 새로운 시스템이 어떻게 프레임워크 전체의 성능 격차를 줄이고 모바일 개발 패러다임을 변화시키는지 종합적으로 이해할 수 있다 [8, 9].
- [[JSI (JavaScript Interface)]]
- 연결 이유: Fabric 렌더러가 자바스크립트 코드와 네이티브 객체 간에 직렬화 오버헤드 없이 동기적으로 소통할 수 있게 해주는 근간 C++ 레이어 기술이다 [2, 6].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 기존 JSON 직렬화 기반 통신 구조의 한계와, 직접적인 메모리/객체 참조가 렌더링 속도에 미치는 영향을 파악할 수 있다 [6, 10].
#### [관계 유형 B (구현/활용 도구)]
- [[TurboModules]]
- 연결 이유: Fabric이 UI 렌더링의 동기적 처리를 담당한다면, TurboModules는 네이티브 모듈의 지연 로딩(lazy-loading)과 동기적 호출을 담당하여 New Architecture의 성능을 완성하는 상호 보완적 기술이다 [2, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 앱 초기 시작 시 로딩 시간(Startup time)과 메모리 사용량을 최소화하는 아키텍처 최적화 기법을 배울 수 있다 [2, 11].
### Deeper Research Questions
- Fabric의 C++ 기반 Shadow Tree는 기존 자바스크립트 기반의 가상 DOM(Virtual DOM) 처리 방식 대비 모바일 기기 메모리 및 스레드 자원 관리에 어떤 차별적 이점을 제공하는가?
- React 18의 동시성 모델(Concurrent Rendering)은 Fabric 렌더러와 내부적으로 어떻게 결합하여 사용자 입력 시 렌더링 중단(interrupt) 및 우선순위 조정을 수행하는가?
- Fabric의 동기적 레이아웃 계산은 기존 비동기 브릿지 환경에서 자주 발생했던 'UI 렌더링 점프(jump)' 현상을 정확히 어떤 렌더 사이클 변화로 해결하였는가?
- React Native의 기존 아키텍처에서 Fabric이 적용된 New Architecture로 마이그레이션할 때, 개발자가 UI 스레드 및 애니메이션 구현 시 주의해야 할 코딩 패턴의 변화는 무엇인가?
- Fabric의 도입이 고성능을 요구하는 대규모 엔터프라이즈 모바일 애플리케이션의 개발 속도와 장기적 유지보수 비용(TCO)에 미치는 영향은 무엇인가?
### Practical Application Contexts
- **Implementation:** React Native 앱 개발 시 UI 프레임 드랍이나 렌더링 지연이 발생하는 경우, Fabric을 활성화(opt-in)하여 동기적 레이아웃 계산 및 React 18의 Suspense를 이용한 부드러운 화면 전환을 구현할 수 있다 [1, 2].
- **System Design:** 크로스 플랫폼 프론트엔드 시스템 설계 시, 네이티브 앱과 동일한 수준의 즉각적인 응답성과 UI 일관성이 필수적인 프로젝트에서 Fabric을 포함한 React Native의 New Architecture를 기술 스택의 핵심으로 채택할 수 있다 [2-4].
- **Operation / Maintenance:** 레거시 React Native 애플리케이션의 렌더링 성능 최적화를 진행할 때, 기존 브릿지 병목을 추적하는 대신 Fabric 기반의 최신 릴리스(0.73 이상)로 엔진을 업그레이드하여 구조적인 유지보수 전략을 세울 수 있다 [2, 9].
- **Learning Path:** 크로스 플랫폼 프론트엔드 개발자가 되기 위해 React 18의 핵심 개념을 학습한 후, 이것이 모바일 환경의 네이티브 렌더링에서 Fabric을 통해 어떻게 동기적으로 번역되고 적용되는지 심화 학습하는 데 활용된다 [1, 12].
- **My Project Relevance:** 모바일 애니메이션이나 복잡한 폼 처리가 필요한 애플리케이션을 React Native로 기획할 때, Fabric 렌더러가 제공하는 네이티브에 가까운 60fps 렌더링 성능 보장을 바탕으로 보다 공격적이고 정교한 UI/UX를 설계할 수 있다 [3, 13, 14].
### Adjacent Topics
- [[Impeller]]
- 확장 방향: React Native가 Fabric을 통해 UI 비동기 병목을 해결했듯, Flutter 진영이 기존 Skia 엔진의 셰이더 컴파일 지연(Jank) 현상을 해결하기 위해 내놓은 커스텀 렌더링 엔진인 'Impeller'의 구조와 렌더링 방식을 비교 분석함으로써 모바일 크로스 플랫폼 렌더링 최적화 기술 전반의 흐름을 이해할 수 있다 [7, 9, 15].
---
*Last updated: 2026-05-03*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
# android/gradle.properties
newArchEnabled=true
```
## 🤔 의사결정 기준 (Decision Criteria)
### Spec-driven Native Component (Codegen)
```ts
// MyViewNativeComponent.ts
import type { ViewProps } from 'react-native';
import type { Int32, WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
**선택 A를 써야 할 때:**
- *(TODO)*
export interface NativeProps extends ViewProps {
color?: string;
count?: WithDefault<Int32, 0>;
}
**선택 B를 써야 할 때:**
- *(TODO)*
export default codegenNativeComponent<NativeProps>('MyView');
```
**기본값:**
> *(TODO)*
### TurboModule Spec
```ts
// NativeCalculator.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
## ❌ 안티패턴 (Anti-Patterns)
export interface Spec extends TurboModule {
add(a: number, b: number): number; // SYNC call (impossible on old bridge)
greet(name: string): Promise<string>;
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
```
### iOS TurboModule Implementation
```objc
// Calculator.mm
#import "Calculator.h"
@implementation Calculator
RCT_EXPORT_MODULE()
- (NSNumber *)add:(double)a b:(double)b {
return @(a + b);
}
- (std::shared_ptr<facebook::react::TurboModule>)
getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared<facebook::react::NativeCalculatorSpecJSI>(params);
}
@end
```
### JSI Direct Binding (advanced)
```cpp
// C++ side
runtime.global().setProperty(
runtime, "nativeAdd",
Function::createFromHostFunction(runtime,
PropNameID::forAscii(runtime, "nativeAdd"), 2,
[](Runtime& rt, const Value&, const Value* args, size_t) {
return Value(args[0].asNumber() + args[1].asNumber());
}));
```
### Concurrent Features on RN
```jsx
import { useTransition, Suspense } from 'react';
function App() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState('');
return (
<>
<TextInput onChangeText={(t) => startTransition(() => setQuery(t))} />
<Suspense fallback={<Spinner />}>
<Results query={query} />
</Suspense>
</>
);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New project (2026) | Fabric default (RN 0.76+) |
| Legacy app | Migrate incrementally; interop layer |
| Custom native view | Fabric component + codegen |
| Sync native call | TurboModule (impossible old) |
| Heavy animation | Reanimated 3 (Fabric-only) |
**기본값**: New Architecture ON, Hermes ON, codegen-driven specs.
## 🔗 Graph
- 부모: [[React Native]] · [[React]]
- 변형: [[TurboModules]] · [[Hermes]] · [[JSI]]
- 응용: [[Reanimated]] · [[React Native Skia]]
- Adjacent: [[Yoga Layout]] · [[Bridge (Legacy)]] · [[Concurrent React]]
## 🤖 LLM 활용
**언제**: RN new architecture migration, TurboModule/Fabric component authoring, JSI binding.
**언제 X**: pure JS-only RN questions (state management, navigation library).
## ❌ 안티패턴
- **Mixing old bridge modules with Fabric without interop**: runtime crash.
- **Skipping codegen**: hand-written specs drift from native; codegen 의 source of truth.
- **JSI HostObject 의 long-running work**: blocks JS thread; offload to native thread.
- **Old `NativeModules.X` API in new code**: TurboModuleRegistry 의 사용.
## 🧪 검증 / 중복
- Verified (React Native official docs — New Architecture, RFC 0588 Fabric).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Fabric renderer / new arch full content |
@@ -2,101 +2,32 @@
id: wiki-2026-0508-fiber-아키텍처-fiber-architecture
title: Fiber 아키텍처 (Fiber Architecture)
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: fiber-architecture
duplicate_of: "[[Fiber_Architecture]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, react, fiber]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[Fiber 아키텍처 ([[Fiber Architecture]])]]
# Fiber 아키텍처 (Fiber Architecture)
## 📌[[ brief]] 신Summary
Fiber 아키텍처는 동시성 렌더링([[Concurrent Rendering]])을 지원하고 렌더링 프로세스를 세밀하게 제어하기 위해 React 16에서 도입된 재조정([[Reconciliation]]) 엔진의 완전한 재작성 버전이다 [1-3]. 이 아키텍처는 렌더링 작업을 '파이버 노드(Fiber node)'라고 불리는 작은 작업 단위(unit of work)로 분할하여 점진적으로 처리하는 작업 루프(work loop)를 기반으로 작동한다 [4, 5]. 렌더링 도중 우선순위가 높은 상호작용이 발생하면 작업을 일시 중지하고 브라우저에 제어권을 넘겼다가 다시 시작할 수 있는 '타임 슬라이싱([[Time-Slicing]])'을 가능하게 하여 UI의 반응성을 크게 향상시킨다 [4, 5].
> **이 문서는 [[Fiber_Architecture]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **작업 루프와 파이버 트리 (Work Loop and Fiber Tree):**
이전의 React는 스택 재조정자(stack reconciler)를 사용하여 전체 컴포넌트 트리를 단일 재귀 호출로 한 번에 처리했기 때문에 메인 스레드를 차단하는 문제가 있었다 [4]. Fiber는 컴포넌트 트리의 각 노드를 자식(child), 형제(sibling), 부모(return)에 대한 포인터를 가진 '파이버 노드'로 구성하며, 이를 단위로 작업 루프를 돈다 [6, 7]. 스케줄러는 트리를 깊이 우선 탐색(depth-first) 방식으로 순회하며 렌더링 작업을 수행하고, 현재 프레임에 남은 시간이 없으면 작업을 일시 중단(yield)하여 브라우저의 끊김을 방지한다 [7, 8].
* **재조정 단계 (Reconciliation Phases):**
React의 재조정 프로세스는 작업 중단 및 우선순위 지정을 가능하게 하기 위해 두 가지 명확한 단계로 나뉜다 [9].
* **렌더 단계 (Render phase):** 트리를 순회하며 이전 상태와 새로운 상태 간의 차이를 계산하는 단계로, DOM을 직접 수정하지 않는다 [9, 10]. 이 단계는 언제든 중단, 취소, 재시작이 가능하며 부작용(side effects)을 실행해서는 안 된다 [9, 10]. 렌더 단계가 끝나면 변경이 필요한 파이버들만 모아 이펙트 목록(effect list)을 구성한다 [11].
* **커밋 단계 (Commit phase):** 중단될 수 없는 동기적인 단계로, 렌더 단계에서 생성된 이펙트 목록을 바탕으로 DOM 노드의 삽입, 삭제, 업데이트를 한 번에 적용한다 [10, 12]. 이 단계에서 `useLayoutEffect``useEffect`와 같은 생명주기 메서드와 훅이 실행된다 [10, 12, 13].
* **우선순위 스케줄링과 레인 모델 (Priority and [[Lane Model]]):**
Fiber는 여러 업데이트의 혼합된 우선순위를 효율적으로 관리하기 위해 '레인(Lanes)'이라는 비트마스크 시스템을 사용한다 [14, 15]. 작업은 사용자 타이핑이나 클릭처럼 즉각적인 처리가 필요한 동기(Sync) 레인부터 스크롤과 같은 사용자 차단(User-[[Blocking]]) 레인, 데이터 페칭 결과를 나타내는 기본(Default) 레인, 백그라운드 작업인 유휴(Idle) 레인 등으로 분류된다 [14, 16]. 이를 통해 긴급한 UI 상호작용이 무거운 비동기 업데이트보다 먼저 처리될 수 있다 [14, 17].
* **동시성 기능의 기반 (Foundation for Concurrent Features):**
이러한 중단 가능한 렌더링 및 우선순위 관리 구조 덕분에 React는 `[[useTransition]]``[[useDeferredValue]]`와 같은 동시성 훅(concurrent hooks)을 도입할 수 있게 되었다 [18]. 이 훅들은 무거운 연산이 진행되는 동안에도 긴급한 사용자 입력을 위해 메인 스레드를 확보하여 부드러운 앱 경험을 유지하게 돕는다 [18, 19].
## 핵심 요약
- React 16+ 의 reconciler — incremental rendering unit.
- Stack reconciler 의 replace, work 의 interruptible / resumable.
- 매 concurrent features (Suspense, Transitions, useDeferredValue) 의 foundation.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[가상 DOM ([[Virtual DOM]])]], [[재조정 (Reconciliation)]], [[동시성 렌더링 (Concurrent Rendering)]], 타임 슬라이싱 (Time-Slicing)
- **Projects/Contexts:** React 16, [[React 19]] 동시성 훅 (useTransition, useDeferredValue)
- **Contradictions/Notes:** 소스 간의 의견 충돌은 없으며, Fiber 아키텍처의 목표는 복잡한 렌더링 작업으로 인해 프레임이 떨어지는 기존의 스택 재조정자(Stack Reconciler) 문제를 해결하기 위해 필수적으로 도입된 구조적 변화라고 일관되게 설명된다 [2, 4].
## 🔗 Graph
- 부모: [[Fiber_Architecture]] (canonical)
---
*Last updated: 2026-04-25*
## 📌 한 줄 통찰 (The Karpathy Summary)
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -2,107 +2,32 @@
id: wiki-2026-0508-fiber-아키텍처와-동시성-concurrent-rende
title: Fiber 아키텍처와 동시성 (Concurrent Rendering)
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: fiber-architecture
duplicate_of: "[[Fiber_Architecture]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, react, fiber, concurrent]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[Fiber 아키텍처와 동시성 (Concurrent Rendering)|Fiber 아키텍처와 동시성 (Concurrent Rendering]]
# Fiber 아키텍처와 동시성 (Concurrent Rendering)
## 📌 한 줄 통찰 (The Karpathy Summary)
React의 **Fiber 아키텍처**는 단일 호출로 전체 트리를 동기적으로 렌더링하여 메인 스레드를 차단하던 기존의 한계를 극복하기 위해 재작성된 재조정([[Reconciliation|Reconciliation]]) 엔진입니다 [1, 2]. 이 엔진은 렌더링 과정을 작은 '작은 작업 단위(Unit of work)'로 분할하여 **동시성 렌더링(Concurrent Rendering)**을 구현합니다 [2, 3]. 결과적으로 긴급한 사용자 상호작용(예: 클릭, 타이핑)이 무거운 렌더링 작업에 의해 지연되지 않도록 작업을 일시 중지, 재개, 우선순위 재조정하여 사용자 인터페이스(UI)의 반응성을 극대화합니다 [4, 5].
> **이 문서는 [[Fiber_Architecture]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
- **기존 렌더링의 문제점과 Fiber의 도입:**
React 16 이전에는 전체 컴포넌트 트리를 단일 재귀 호출로 처리하는 '스택 재조정자(Stack Reconciler)'를 사용했습니다 [2]. 이 방식은 렌더링이 완료될 때까지 메인 스레드를 차단(synchronous [[Blocking|Blocking]])하여, 큰 규모의 애플리케이션에서는 UI가 사용자의 입력이나 애니메이션에 반응하지 못하는 문제를 발생시켰습니다 [2]. 이를 해결하기 위해 렌더링을 중단 및 재개할 수 있는 Fiber 아키텍처가 도입되었습니다 [1, 2].
## 핵심 요약 (specialization aspects)
- React 18+ concurrent rendering: Suspense, useTransition, useDeferredValue, automatic batching.
- Fiber 의 interruptible work loop 의 foundation.
- Time slicing — 5ms chunk 의 default, browser yield 의 사용.
- **작업 루프(Work Loop)와 작업 단위(Unit of Work):**
Fiber는 컴포넌트나 DOM 요소를 나타내는 'Fiber 노드' 단위로 렌더링 작업을 수행합니다 [2, 3]. 렌더링을 여러 프레임에 분산시키기 위해 '작업 루프'를 작동하며, 다음 작업을 선택하여 처리(beginWork)하다가 우선순위가 높은 작업이 발생하면 렌더링을 일시 중단하고 브라우저에 제어권을 양보(Yield)합니다 [3, 5].
## 🔗 Graph
- 부모: [[Fiber_Architecture]] (canonical)
- **재조정(Reconciliation) 단계의 분리:**
동시성 렌더링을 위해 React의 재조정 과정은 중단 가능성에 따라 두 가지 단계로 나뉩니다 [6].
* **렌더링 단계(Render Phase):** 컴포넌트 트리를 순회하며 이전 상태와 새로운 상태의 차이를 계산하고 효과 목록(Effect list)을 구축합니다 [6]. 이 단계는 실제 DOM을 변경하지 않는 순수한 연산 과정이므로 **언제든지 일시 중지, 취소 또는 재시작이 가능**합니다 [6, 7].
* **커밋 단계(Commit Phase):** 렌더링 단계에서 만들어진 변경 사항(효과 목록)을 실제 DOM에 한 번에 적용합니다 [8]. 이 과정은 **동기적이고 중단할 수 없습니다** [7, 8].
- **우선순위 제어 및 차선 모델([[Lane Model|Lane Model]]):**
React는 타임 슬라이싱([[Time-Slicing|Time-Slicing]])과 동시성을 효과적으로 관리하기 위해 32비트 정수 기반의 '차선(Lanes)' 시스템을 활용합니다 [4, 9].
* 동기적 차선(Sync Lane): 타이핑, 클릭 등 즉시 처리해야 하는 긴급한 작업 [4, 10].
* 입력 연속 차선(InputContinuous Lane): 스크롤, 마우스 호버 등 유동적인 움직임 [4, 10].
* 그 외에도 데이터 페칭 결과를 처리하는 기본 차선(Default Lane)과 백그라운드 렌더링을 처리하는 유휴 차선(Idle Lane)으로 나뉩니다 [4].
이러한 세밀한 모델 덕분에 작업 중인 Fiber(WIP Fibers)를 우선순위에 따라 지연시키거나 우선 처리할 수 있습니다 [11].
- **동시성 기능(Concurrent Features)의 활용:**
Fiber의 동시성 렌더링 구조는 [[React 18|React 18]], 19의 `useTransition``[[useDeferredValue|useDeferredValue]]`와 같은 훅(Hook)을 가능하게 합니다 [12, 13]. 긴급하지 않은 업데이트의 우선순위를 낮춰 처리함으로써 무거운 리스트 필터링이나 데이터 계산 중에도 앱의 반응성을 부드럽게 유지할 수 있습니다 [12, 14].
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[가상 DOM과 재조정 (Virtual DOM and Reconciliation)|가상 DOM과 재조정 (Virtual DOM and Reconciliation]], 차선 모델과 작업 우선순위 (Lane Model & Priorities), Time-Slicing, [[React 동시성 훅 (useTransition, useDeferredValue)|React 동시성 훅 (useTransition, useDeferredValue]]
- **Projects/Contexts:** [[메인 스레드 차단 문제 해결을 위한 React 16의 Fiber 엔진 교체 및 React 18, 19의 동시성 렌더링 적용 사례|메인 스레드 차단 문제 해결을 위한 React 16의 Fiber 엔진 교체 및 React 18, 19의 동시성 렌더링 적용 사례]]
- **Contradictions/Notes:** 소스 전반에 걸쳐 내용이 일치하며 상충되는 의견은 없습니다. 모든 소스는 Fiber 아키텍처가 렌더링을 작은 단계로 분할하고 우선순위를 부여함으로써 메인 스레드의 부하를 줄여 동시성과 반응성을 달성한다는 점을 일관되게 강조합니다.
---
*Last updated: 2026-04-25*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+177 -66
View File
@@ -2,91 +2,202 @@
id: wiki-2026-0508-figma-tokens-studio
title: Figma Tokens Studio
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Tokens Studio, Figma Design Tokens Plugin]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.9
verification_status: applied
tags: [figma, design-tokens, design-system]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: JSON
framework: Figma Plugin
---
# [[Figma Tokens Studio|Figma Tokens Studio]]
# Figma Tokens Studio
## 📌 한 줄 통찰 (The Karpathy Summary)
[[Figma|Figma]] Tokens Studio(과거 명칭: Figma Tokens)는 디자이너가 색상, 서체, 간격과 같은 디자인 결정(디자인 토큰)을 JSON 형식으로 구조화할 수 있게 해주는 Figma 플러그인입니다 [1]. 이 도구를 활용하면 Figma에서 작업한 토큰을 외부 파일로 내보내어 코드 기반의 디자인 시스템과 동기화할 수 있습니다 [1, 2]. 확장성 있는 UI 시스템에서 디자인과 개발 워크플로우를 연결하여 일관된 테마를 구축하는 데 필수적인 역할을 합니다 [1, 3].
## 한 줄
> **"매 Tokens Studio = Figma 안의 design token source-of-truth + Style Dictionary 연동."**. 매 W3C Design Tokens Format Spec (DTCG, 2024-)에 매 align — 매 plugin이 매 token 의 JSON 의 Figma styles + variables 의 sync. 매 modern flow는 Tokens Studio → GitHub PR → Style Dictionary build → CSS/Tailwind/iOS/Android 의 multi-platform 출력.
## 📖 구조화된 지식 (Synthesized Content)
* **디자인 토큰의 JSON 구조화 및 추출**: Tokens Studio for Figma는 디자이너가 내린 디자인 결정들을 플랫폼에 구애받지 않는 JSON 데이터로 정의하고 내보낼 수 있도록 지원합니다 [1].
* **테마 생성 엔진과의 파이프라인 연동**: 이 플러그인을 통해 내보낸 테마별 JSON 토큰 파일(예: `colors-light.json`, `colors-dark.json`)은 [[Style Dictionary|Style Dictionary]]와 같은 오픈소스 테마 엔진과 결합하여 사용할 수 있습니다 [4, 5]. 이 과정을 통해 React 애플리케이션 등에서 직접 사용할 수 있는 [[JavaScript|JavaScript]]/TypeScript 테마 객체나 CSS 변수로 자동 변환됩니다 [4].
* **단일 진실 공급원([[Single_Source_of_Truth|Single Source of Truth]]) 유지**: Tokens Studio와 같은 플러그인을 통해 토큰을 추출하여 공유 리포지토리나 코드베이스로 동기화함으로써, 디자이너와 개발자 간에 동일한 디자인 언어(디자인 토큰)를 공유할 수 있습니다 [2, 3]. 이는 다중 테마, 다크 모드, 여러 브랜드 스타일을 수동 코드 작성 없이 안전하게 확장할 수 있게 해줍니다 [1, 3].
* *참고: 소스에 관련 정보가 부족합니다.* (Figma Tokens Studio 플러그인 자체의 구체적인 내부 사용법이나 세부 기능에 대한 구체적인 설명은 소스에 포함되어 있지 않으며, 주로 Style Dictionary를 활용한 JSON 토큰 추출 파이프라인의 일부로만 언급됩니다 [1, 2].)
## 매 핵심
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Design Tokens|Design Tokens]], Style Dictionary, CSS Variables, [[Dynamic Theming|Dynamic Theming]]
- **Projects/Contexts:** Scalable UISystems, Design-to-Code Workflow
- **Contradictions/Notes:** 소스 데이터는 Figma Tokens Studio의 작동 원리나 전체 기능에 대해 깊이 다루지 않습니다. 단지 디자이너가 만든 토큰을 코드로 가져오기 위해 JSON 형태로 내보내는 도구(플러그인)로써의 역할에만 초점을 맞추고 있으므로, 소스에 관련 정보가 부족합니다 [1, 2].
### 매 token types
- color, dimension, fontFamily, fontWeight, lineHeight, letterSpacing, opacity, borderRadius, boxShadow, typography (composite).
- 매 alias `{global.color.primary.500}` — 매 reference 의 통한 indirection.
---
*Last updated: 2026-04-26*
### 매 sets / themes
- **Set**: 매 token 의 그룹 (global, brand-A, light, dark).
- **Theme**: 매 set 의 enabled combination (e.g., brand-A + light).
- 매 multi-brand × multi-mode 의 매 표현.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Figma Variables sync — 매 plugin이 매 native variables 의 push.
2. Code export — Style Dictionary → CSS custom props / Tailwind theme / iOS UIColor.
3. Git sync — Tokens Studio Pro → GitHub repo, PR-based review.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 1. DTCG token JSON shape
```json
{
"color": {
"primary": {
"500": { "$value": "#3366FF", "$type": "color" }
}
},
"spacing": {
"md": { "$value": "16px", "$type": "dimension" }
},
"typography": {
"heading-lg": {
"$type": "typography",
"$value": {
"fontFamily": "{font.family.sans}",
"fontSize": "{font.size.xl}",
"fontWeight": 700,
"lineHeight": 1.2
}
}
}
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### 2. Alias / reference
```json
{
"color": {
"brand": { "$value": "#FF5500", "$type": "color" },
"button": {
"primary": { "$value": "{color.brand}", "$type": "color" }
}
}
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### 3. Style Dictionary config
```javascript
// sd.config.js
import StyleDictionary from 'style-dictionary';
**선택 B를 써야 할 때:**
- *(TODO)*
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [{ destination: 'tokens.css', format: 'css/variables' }],
},
tailwind: {
transformGroup: 'js',
buildPath: 'build/tw/',
files: [{ destination: 'theme.js', format: 'javascript/module' }],
},
ios: {
transformGroup: 'ios-swift',
buildPath: 'build/ios/',
files: [{ destination: 'Tokens.swift', format: 'ios-swift/class.swift' }],
},
},
};
```
**기본값:**
> *(TODO)*
### 4. CSS output
```css
:root {
--color-primary-500: #3366ff;
--spacing-md: 16px;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### 5. Tailwind preset from tokens
```javascript
// tailwind.config.js
import tokens from './build/tw/theme.js';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default {
theme: {
colors: tokens.color,
spacing: tokens.spacing,
fontFamily: { sans: tokens.font.family.sans },
},
};
```
### 6. Themes via attribute
```css
[data-theme='light'] { --color-bg: #ffffff; }
[data-theme='dark'] { --color-bg: #0b0b10; }
body { background: var(--color-bg); }
```
### 7. GitHub Action (build on PR merge)
```yaml
name: tokens-build
on:
push:
branches: [main]
paths: ['tokens/**']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci && npm run tokens:build
- run: |
git config user.email bot@acme.dev
git config user.name token-bot
git add build && git commit -m "chore(tokens): build" || true
git push
```
### 8. Figma Variables JSON (native, post-2024)
```javascript
// figma plugin code (post-2024 Variables API)
const collection = figma.variables.createVariableCollection('Brand');
const v = figma.variables.createVariable('color.primary.500', collection.id, 'COLOR');
v.setValueForMode(collection.modes[0].modeId, { r: 0.2, g: 0.4, b: 1, a: 1 });
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 단일 brand | Tokens Studio Free + JSON export. |
| Multi-brand / Pro | Tokens Studio Pro + GitHub sync. |
| Native Figma only | Figma Variables direct. |
| Multi-platform code | Style Dictionary build pipeline. |
| 매 component spec | Tokens + auto-generated docs. |
**기본값**: Tokens Studio + DTCG JSON + Style Dictionary + Tailwind.
## 🔗 Graph
- 부모: [[Design Tokens]] · [[Design System]]
- 변형: [[Figma Variables]] · [[Specify]] · [[Supernova]]
- 응용: [[Style Dictionary]] · [[Tailwind Theme]] · [[Component Library]]
- Adjacent: [[DTCG]] · [[CSS Variables]]
## 🤖 LLM 활용
**언제**: 매 token JSON 의 scaffolding, Style Dictionary config, 매 alias 검증.
**언제 X**: 매 visual review — Figma 안에서 매 designer 의 confirm.
## ❌ 안티패턴
- **Hard-coded hex in code**: 매 token bypass — drift 발생.
- **Token name with semantic in global**: 매 `color.button` 의 global 안에 — 매 brand layer 분리.
- **No alias**: 매 매 component-level token 의 raw value — refactor 의 어려움.
- **Manual sync**: 매 designer가 매 figma update + dev가 매 code update — 매 GitHub action 자동화.
## 🧪 검증 / 중복
- Verified (tokens.studio docs 2024-2026, DTCG spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Tokens Studio + DTCG + Style Dictionary |
@@ -2,149 +2,221 @@
id: wiki-2026-0508-folder-structure-best-practices
title: Folder Structure Best Practices
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [Project Structure, Code Organization, Frontend Folder Layout]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.85
verification_status: applied
tags: [architecture, folder-structure, frontend, project-organization]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react-next
---
# [[Folder Structure Best Practices|Folder Structure Best Practices]]
# Folder Structure Best Practices
## 📌 한 줄 통찰 (The Karpathy Summary)
React 등 프론트엔드 프로젝트에서 코드의 유지보수성, 확장성, 그리고 협업 효율성을 높이기 위해 파일과 디렉터리를 체계적으로 구성하는 방법론입니다 [1]. 현대적인 애플리케이션에서는 과거의 파일 유형 기반(유형별 분류) 구조에서 벗어나, 기능(Feature)이나 도메인 중심으로 관련된 로직을 묶는 하이브리드 또는 기능 기반 방식이 모범 사례로 권장됩니다 [2, 3]. 이를 통해 UI, 비즈니스 로직, 상태 관리 등의 관심사를 명확히 분리하고 프로젝트가 커짐에 따라 발생하는 기술 부채를 최소화할 수 있습니다 [4].
## 한 줄
> **"매 folder structure 의 골 — colocation by feature, not by file-type"**. 매 modern frontend (2026) 의 favored: feature-sliced design, screaming architecture, Next.js app router colocation. 매 type-based folders (`components/`, `utils/`) 의 rejection — feature 의 boundary 의 unclear.
## 📖 Core 소스 Content
## 매 핵심
* **구조의 진화와 한계:**
* 초기 소규모 프로젝트는 주로 모든 컴포넌트를 `components` 폴더에, 모든 훅을 `hooks` 폴더에 넣는 플랫(Flat) 구조나 파일 유형 기반 구조로 시작합니다 [5, 6].
* 하지만 앱의 규모가 커지면 단일 기능을 수정하기 위해 여러 폴더를 넘나들어야 하므로, 개발 속도가 느려지고 디버깅이 어려워지며 코드베이스가 복잡해지는 한계가 발생합니다 [3, 6, 7].
* **기능 기반(Feature-based) 및 하이브리드 구조:**
* 2025년 기준 가장 권장되는 접근 방식은 파일 유형이 아닌 비즈니스 기능이나 모듈을 중심으로 폴더를 구성하는 것입니다 [2, 8, 9].
* 각 기능(Feature)은 캡슐화되어 다른 기능과 독립적으로 작동할 수 있으므로, 규모 확장 시 기존 코드에 영향을 주지 않고 새로운 기능을 매끄럽게 추가할 수 있습니다 [8, 10].
* **권장 디렉터리 구성 (src/ 하위):**
* `assets/`: 이미지, 폰트 등 정적 미디어 리소스 보관 [11, 12].
* `components/`: 여러 기능에서 공통으로 재사용되는 도메인에 구애받지 않는 UI 요소 (예: 버튼, 모달, 네비게이션 바 등) [2, 12, 13].
* `features/` (또는 `modules/`): 인증(Auth), 대시보드(Dashboard) 등 도메인별 비즈니스 로직. 이 폴더 내부에는 해당 기능에만 쓰이는 컴포넌트, 훅, API 등을 캡슐화하여 보관합니다 [2, 9, 13].
* `hooks/`: 폼 처리, 데이터 페칭 등 앱 전반에서 재사용 가능한 커스텀 훅 [9, 14].
* `pages/` (또는 `routes/`): 라우팅에 매핑되는 페이지 레벨 컴포넌트 [15, 16].
* `services/`: 서드파티 서비스 연동이나 API 요청 등 외부 통신 로직 [16, 17].
* `store/` (또는 `context/`): Redux, Zustand, Context API를 활용하는 전역 상태 관리 로직 [14-16].
* `utils/`: 날짜 포맷팅, 데이터 유효성 검사 등 상태를 가지지 않는 유틸리티 함수 [17, 18].
* `styles/`: 글로벌 CSS, 테마(Theme) 등 전역 스타일링 파일 [18, 19].
* `types/`: TypeScript 사용 시 전역으로 사용되는 타입 및 인터페이스 보관 [18].
* `config/`: 환경 변수나 애플리케이션 전역 설정(API 기본 URL 등) 관리 [18, 20].
* **Feature-Sliced Design (FSD):**
* 기능 기반 폴더 구조보다 더 엄격하게 의존성의 방향을 통제하는 프론트엔드 아키텍처 방법론입니다 [21].
* `shared` -> `entities` -> `features` -> `widgets` -> `pages` -> `app` 이라는 고정된 다층 계층(Layer)을 가집니다 [22, 23].
* 상위 계층은 하위 계층의 코드를 가져올 수 있지만(Import), 하위 계층은 상위 계층을 참조할 수 없는 단방향 의존성 규칙을 통해 순환 의존성을 방지합니다 [22, 24].
* **Next.js 환경에서의 라우트 그룹 (Route Groups):**
* Next.js 프로젝트에서는 괄호를 사용한 폴더명 `(folderName)` 방식을 통해, 실제 URL 경로에는 영향을 주지 않으면서도 관련 기능이나 논리에 따라 라우트를 깔끔하게 그룹화할 수 있습니다 [25-27].
### 매 Type-based (anti) vs Feature-based (good)
- **Type-based**: `/components`, `/hooks`, `/utils`, `/services`, `/types` — every change touches 5 folders.
- **Feature-based**: `/features/checkout/{components,hooks,api,types}` — change scope = single folder.
## 🔗 지식 연결 (Graph)
### Related Concepts
- [[Feature-Sliced Design|Feature-Sliced Design]]
- 연결 이유: 대규모 React 애플리케이션의 폴더 구조를 구축하기 위해 고안된 전문적인 프론트엔드 아키텍처 방법론이기 때문입니다 [21].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 폴더 간의 단방향 의존성 규칙과 각 폴더(Layer, Slice, Segment)가 담당해야 하는 역할의 엄격한 분리 방식 [22, 28].
### 매 Levels of Hierarchy
1. **Routes / pages** (Next.js `app/`, Remix `routes/`).
2. **Features** (`features/<feature>/...`) — domain boundaries.
3. **Shared** (`lib/`, `shared/`, `ui/`) — cross-feature reusables.
4. **Entities/domain** (Feature-Sliced: `entities/user`, `entities/cart`).
- [[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]] (관심사의 분리)
- 연결 이유: 폴더 구조를 설계하는 근본적인 목적이 UI 렌더링, 전역 상태 관리, 데이터 통신(API) 등의 책임을 각기 다른 위치로 분리하는 데 있기 때문입니다 [4, 29].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: `services/`, `store/`, `components/` 등의 폴더를 분리하여 단일 책임 원칙(SRP)을 프론트엔드 아키텍처 전반에 적용하는 방법 [4, 30].
### 매 Boundaries
- Features 의 each other 의 import X (cross-feature 의 shared layer 의 통과).
- Lower layers 의 higher 의 import X (UI 의 feature 의 import X).
- 매 ESLint `no-restricted-imports` 또는 `eslint-plugin-boundaries` 의 enforce.
- [[Naming Conventions|Naming Conventions]] (명명 규칙)
- 연결 이유: 일관된 폴더 및 파일 명명 규칙(예: 폴더명은 kebab-case, 컴포넌트는 PascalCase)은 폴더 구조 내에서 파일을 예측 가능하게 찾고 충돌을 방지하는 핵심 규칙이기 때문입니다 [31-33].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 다양한 운영체제와 CI/CD 파이프라인에서 빌드 에러를 방지하고 팀 내 코드 가독성을 유지하는 방법 [34, 35].
### 매 응용
1. Next.js 15 app router project.
2. Vite + React SPA.
3. Monorepo (Turborepo, Nx).
4. React Native app.
### Deeper Research Questions
- 기능 기반(Feature-based) 폴더 구조에서 각 기능이 상호작용해야 할 때 발생하는 교차 관심사(Cross-cutting concerns)나 공유 의존성을 어떻게 관리하고 해결할 수 있는가?
- 레거시 파일 유형 기반(File-type based) React 프로젝트를 기능 기반 혹은 Feature-Sliced Design으로 점진적으로 마이그레이션하기 위한 가장 안전하고 효율적인 단계는 무엇인가?
- Feature-Sliced Design의 단방향 의존성 원칙을 ESLint와 같은 정적 분석 도구로 자동 강제화(Governance)하는 방법은 무엇인가?
- 폴더 구조를 모듈화할 때 발생하는 파일 중첩 문제와 이를 피하기 위한 적절한 인덱스(Barrel) 파일 사용 전략의 장단점은 무엇인가?
- 상태 관리 라이브러리(Context API, Zustand, Redux 등)의 종류에 따라 권장되는 `store/` 폴더 내부의 구조는 어떻게 달라져야 하는가?
## 💻 패턴
### Practical Application Contexts
- **Implementation:** React 컴포넌트를 생성할 때, 모든 요소를 `components/` 폴더에 넣지 않고 특정 도메인(예: 인증)에만 쓰이는 요소는 `features/auth/components/`로 격리하여 캡슐화를 실천합니다.
- **System Design:** 프로젝트 초기 세팅 단계에서 비즈니스 도메인을 분석하여 어떤 코드가 전역(`shared/` 또는 `components/`)에 속하고 어떤 코드가 로컬(`features/`)에 속할지 기준을 마련합니다.
- **Operation / Maintenance:** 기능에 버그가 발생했을 때, 해당 기능의 폴더(`features/feature-name/`)만 확인하면 UI, 상태, API 요청 로직이 모여 있어 디버깅 및 유지보수 속도가 크게 향상됩니다.
- **Learning Path:** 처음에는 단순한 플랫 구조로 React를 학습한 후, 컴포넌트가 30개 이상으로 늘어나는 시점에 기능 기반 폴더 구조를 도입하여 아키텍처 설계 역량을 기를 수 있습니다.
- **My Project Relevance:** 현재 진행 중이거나 리팩토링해야 할 React 코드베이스에서, 거대해진 `components/` 폴더를 도메인 단위의 `features/` 폴더로 나누고 재사용 불가 로직들을 분리하는 데 직접적으로 적용됩니다.
### Adjacent Topics
- [[상태 관리(State Management)|State Management]]
- 확장 방향: 전역 상태(Global State)와 로컬 상태(Local State)를 어디에 보관해야 하는지, Zustand와 같은 도구가 `store/` 폴더의 구조를 어떻게 단순화하는지 확장하여 조사할 수 있습니다.
- [[Code Splitting|Code Splitting]] (코드 스플리팅)
- 확장 방향: 라우트 혹은 폴더(Feature) 단위로 코드 스플리팅과 지연 로딩(Lazy Loading)을 적용하여 초기 번들 크기를 줄이고 성능을 최적화하는 전략과 연결됩니다.
---
*Last updated: 2026-04-30*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Feature-Sliced (recommended 2026)
```
src/
├── app/ # app entry, providers, global styles
├── pages/ # (or routes/) page-level composition
├── features/ # business actions (toggle-cart, send-comment)
│ └── send-comment/
│ ├── ui/
│ ├── model/ # state, hooks
│ ├── api/
│ └── index.ts # public API
├── entities/ # business entities (user, post, cart)
│ └── user/
│ ├── ui/
│ ├── model/
│ └── api/
├── shared/ # reusable, domain-agnostic
│ ├── ui/ # buttons, inputs (design system)
│ ├── lib/ # utilities
│ ├── api/ # base http client
│ └── config/
└── widgets/ # composite UI blocks (Header, Sidebar)
```
## 🤔 의사결정 기준 (Decision Criteria)
### Next.js 15 App Router (colocation)
```
app/
├── layout.tsx
├── page.tsx
├── (marketing)/ # route group, no URL segment
│ └── about/page.tsx
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ ├── _components/ # private (underscore = not routable)
│ │ └── Sidebar.tsx
│ ├── settings/
│ │ ├── page.tsx
│ │ └── actions.ts # server actions
│ └── api/
│ └── route.ts
src/
├── lib/ # shared utilities, db, auth
├── components/ui/ # design system
└── features/ # cross-page features
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Vite + React SPA (mid-size)
```
src/
├── main.tsx
├── App.tsx
├── routes/ # react-router routes
├── features/
│ └── auth/
│ ├── components/
│ ├── hooks/
│ ├── api.ts
│ ├── types.ts
│ └── index.ts
├── components/ui/ # design system
├── hooks/ # generic hooks
├── lib/
└── types/
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Monorepo (Turborepo)
```
apps/
├── web/ # Next.js app
├── mobile/ # Expo
└── docs/
packages/
├── ui/ # shared design system
├── config/ # eslint, ts, tailwind presets
├── api/ # tRPC / generated client
└── db/ # Prisma schema
```
**기본값:**
> *(TODO)*
### Feature Public API (barrel)
```ts
// features/checkout/index.ts — explicit exports only
export { CheckoutPage } from './ui/CheckoutPage';
export { useCheckout } from './model/useCheckout';
export type { CheckoutState } from './model/types';
// internals (api/, model/internal) NOT re-exported
```
## ❌ 안티패턴 (Anti-Patterns)
### Boundary Enforcement (eslint-plugin-boundaries)
```js
// eslint.config.js
import boundaries from 'eslint-plugin-boundaries';
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default [{
plugins: { boundaries },
settings: {
'boundaries/elements': [
{ type: 'shared', pattern: 'src/shared/*' },
{ type: 'entity', pattern: 'src/entities/*' },
{ type: 'feature', pattern: 'src/features/*' },
{ type: 'widget', pattern: 'src/widgets/*' },
{ type: 'page', pattern: 'src/pages/*' },
],
},
rules: {
'boundaries/element-types': ['error', {
default: 'disallow',
rules: [
{ from: 'page', allow: ['widget', 'feature', 'entity', 'shared'] },
{ from: 'widget', allow: ['feature', 'entity', 'shared'] },
{ from: 'feature', allow: ['entity', 'shared'] },
{ from: 'entity', allow: ['shared'] },
{ from: 'shared', allow: ['shared'] },
],
}],
},
}];
```
### TS Path Aliases
```json
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["src/shared/*"],
"@features/*": ["src/features/*"]
}
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Small SPA (<20 components) | Flat or simple `components/` + `pages/` |
| Mid-size (20-200) | Feature-based (`features/` + `shared/`) |
| Large / team scale | Feature-Sliced Design + boundary lint |
| Next.js project | App router colocation + `src/features/` |
| Monorepo | Turborepo `apps/` + `packages/` |
**기본값**: feature-based + shared layer + ESLint boundary enforcement.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Frontend Architecture]]
- 변형: [[Feature-Sliced Design]] · [[Atomic Design]] · [[Screaming Architecture]]
- 응용: [[Monorepo]] · [[Design System]]
- Adjacent: [[Next.js]] · [[Turborepo]] · [[Module Boundaries]]
## 🤖 LLM 활용
**언제**: project structure 의 design, refactor folder layout, boundary rule 의 setup.
**언제 X**: tiny prototype — overhead 의 not worth.
## ❌ 안티패턴
- **Type-based root** (`/components`, `/hooks`, `/utils`): scales poorly.
- **Deeply nested barrels**: circular import / slow build.
- **God `utils/`**: dump folder. 매 specific domain 의 split.
- **Cross-feature imports**: feature isolation 의 break — shared 의 use.
- **`index.ts` 의 every file의 leak**: tree-shaking break, public API 의 unclear.
- **`pages/` 안에 business logic**: route 는 thin, feature 의 delegate.
## 🧪 검증 / 중복
- Verified (Feature-Sliced Design docs, Next.js project structure docs, Bulletproof React).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — folder structure best practices full content |
@@ -2,109 +2,31 @@
id: wiki-2026-0508-frontend-architecture
title: Frontend Architecture
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: large-frontend-projects
duplicate_of: "[[Large_Frontend_Projects]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, frontend, architecture]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
## 📌 한 줄 통찰 (The Karpathy Summary)
프론트엔드 아키텍처는 현대 웹 애플리케이션의 복잡성을 관리하고 지속 가능한 유지보수성과 확장성을 확보하기 위한 구조적 설계 기반이다. 단순한 UI 렌더링을 넘어 비즈니스 로직과 UI의 분리, 엄격한 의존성 관리, 그리고 기능(Feature) 기반의 모듈화를 통해 견고한 소프트웨어 시스템을 구축하는 것을 목표로 한다.
# Frontend Architecture
## 📖 구조화된 지식 (Synthesized Content)
1. **기능 기반 설계 및 FSD (Feature-Sliced Design)**
- 기술적 타입(컴포넌트, 훅 등)이 아닌 비즈니스 기능(도메인) 중심으로 코드를 구성하여 응집도를 높인다.
- FSD 아키텍처를 통해 계층(Layer) 간 단방향 의존성을 강제하고, 모듈 간의 순환 참조와 아키텍처 붕괴를 원천적으로 방지한다.
2. **소프트웨어 공학 원칙의 적용**
- **SOLID**: 단일 책임 원칙(SRP)으로 컴포넌트를 세분화하고, 컴포넌트 합성(Composition)으로 개방-폐쇄 원칙(OCP)을 준수한다.
- **KISS, DRY, YAGNI**: 코드를 단순하게 유지하고 불필요한 추상화와 오버엔지니어링을 경계하여 실용적인 코드베이스를 유지한다.
3. **계층화된 상태 관리**
- 상태의 성격에 따라 로컬(React State), 글로벌 앱 상태(Zustand), 서버 캐시 상태(TanStack Query)로 레이어를 분리하여 리렌더링 성능과 데이터 동기화 효율을 최적화한다.
4. **성능 및 회복성 설계**
- Vite 기반의 코드 스플리팅과 지연 로딩을 통해 번들 크기를 최적화하고, Error Boundary를 배치하여 특정 모듈의 오류가 시스템 전체로 전파되는 것을 차단한다.
> **이 문서는 [[Large_Frontend_Projects]] 의 중복본입니다.** Canonical 문서로 redirect.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **설계 오버헤드**: 엄격한 아키텍처(FSD 등) 도입 시 초기 폴더 구성과 계층 분리에 따른 인지적 부하 및 파일 수 증가가 발생할 수 있다.
- **추상화의 양날의 검**: DRY 원칙을 무리하게 적용하여 지나치게 추상화된 공통 로직은 오히려 코드 독해를 방해하고 변경에 취약하게 만들 수 있다(KISS 원칙과의 충돌).
- **기술 부채의 점진적 해결**: 기존의 모놀리식 구조에서 기능 기반 아키텍처로 전환할 때, 과도한 빅뱅 방식의 리팩토링보다는 점진적 마이그레이션 전략이 권장된다.
## 핵심 요약 (specialization aspects)
- Frontend architecture 의 large-scale 의 same concern: module boundaries, state, build, performance budgets.
- See canonical for: micro-frontends, monorepo, feature-sliced design, performance.
## 🔗 지식 연결 (Graph)
### Related Concepts
- **Feature-Sliced Design**: 프론트엔드 모듈화의 최신 표준 방법론 (관계: 핵심 아키텍처 모델)
- **State Management**: 데이터 흐름의 중앙 통제 및 최적화 (관계: 데이터 레이어 설계)
- **SOLID Principles**: 객체 지향 및 컴포넌트 설계의 근간 (관계: 코드 품질 기준)
## 🔗 Graph
- 부모: [[Large_Frontend_Projects]] (canonical)
### Deeper Research Questions
1. FSD의 'Widgets' 계층과 'Features' 계층 사이의 책임 분배를 결정하는 가장 명확한 기준은 무엇인가?
2. 마이크로 프론트엔드 전환 시, 중앙 집중식 상태 관리 라이브러리와 서비스별 격리된 상태 관리 중 어떤 것이 유리한가?
3. 컴포넌트 합성(Composition) 패턴이 개방-폐쇄 원칙(OCP)을 프론트엔드 환경에서 어떻게 물리적으로 구현하는가?
4. 서버 사이드 데이터(RSC) 비중이 늘어날 때, 클라이언트 아키텍처의 상태 관리 레이어는 어떻게 간소화되어야 하는가?
5. 아키텍처의 단방향 의존성 규칙을 정적 분석 도구(ESLint plugin-import 등)를 통해 자동화하여 강제하는 방안은?
### Practical Application Contexts
- **대규모 앱 리팩토링**: 흩어져 있는 비즈니스 로직을 기능별 폴더로 캡슐화하여 유지보수성 확보.
- **신규 프로젝트 설계**: 초기 아키텍처 수립 단계에서 상태 레이어와 오류 처리 전략 정의.
### Adjacent Topics
- **Micro-Frontends**
- **Server Components (RSC)**
- **Test-Driven Development (TDD) in Frontend**
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -2,90 +2,258 @@
id: wiki-2026-0508-frontend-architecture-and-folder
title: Frontend Architecture and Folder Structure
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [FE-ARCH-STRUCT-001]
aliases: [Project Structure, Folder Convention, Frontend Layout]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: ["Frontend|[Frontend", Architecture, folder-structure, Scalability, Modularity, atomic-design, clean-architecture]
confidence_score: 0.9
verification_status: applied
tags: [frontend, architecture, project-structure, conventions]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: React
---
# Frontend Architecture and Folder Structure (프런트엔드 아키텍처 및 폴더 구조)
# Frontend Architecture and Folder Structure
## 📌 한 줄 통찰 (The Karpathy Summary)
> "파일이 어디에 있는지 고민하는 시간을 제로로 만들고, 프로젝트 규모가 커져도 복잡도가 선형적으로 유지되도록 관심사 분리(SoC)에 기반한 물리적/논리적 영토를 명확히 획정하라" — 확장성과 협업 효율을 결정짓는 프런트엔드 프로젝트의 설계 지도.
## 한 줄
> **"매 file layout 의 의 architecture 의 — folder 의 dependency direction 의 enforce"**. 2026 의 의 매 dominant convention 의 **Feature-Sliced Design (FSD)** + **colocation by route** (Next.js App Router). 매 monorepo 의 의 매 cross-package boundary 의 의 nx/turbo 의 의 enforce.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Domain-Driven and Feature-Encapsulated Structuring" — 공통 컴포넌트 중심의 구조에서 벗어나, 기능(Feature)이나 도메인 단위로 관련 로직(Hooks, Components, Types, Utils)을 응집시키는 패턴.
- **표준 폴더 구조 아키텍처:**
- **`/src/components`:** 여러 곳에서 재사용되는 범용 UI 원자(Buttons, Inputs).
- **`/src/features`:** 특정 비즈니스 기능(Auth, Cart, Profile) 단위로 캡슐화된 폴더. 각 폴더 내에 해당 기능 전용 자산 포함.
- **`/src/hooks`:** 범용 커스텀 훅들.
- **`/src/pages` / `/src/app`:** 라우팅 진입점 및 페이지 레이아웃.
- **`/src/assets` & `/src/styles`:** 이미지, 폰트 및 전역 CSS 설정.
- **의의:** 의존성 방향을 명확히 하여 코드 변경의 파급 효과를 제한하고, 새로운 팀원이 프로젝트에 빠르게 적응할 수 있는 높은 관측성을 제공함.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거에는 `components`, `containers`, `actions`, `reducers` 등 기술적 계층으로 폴더를 나누었으나(Layered Architecture), 현대 정책은 관련 있는 기능을 한곳에 모으는 '도메인/피처 중심 정책'으로 전환됨.
- **정책 변화:** Antigravity 프로젝트는 모든 저장소에 대해 'Feature-first' 폴더 구조를 강제하며, 각 피처 폴더 밖으로 유출되는 의존성은 엄격히 검토되는 'Strict Encapsulation' 정책을 고수함.
### 매 layered approach (FSD)
- **app**: 의 entrypoint, provider, router setup.
- **pages / routes**: 의 page-level composition.
- **widgets**: 의 self-contained UI block (Header, Sidebar).
- **features**: 의 user action (LoginForm, AddToCart).
- **entities**: 의 domain object (User, Product).
- **shared**: 의 reusable utility (UI kit, lib, config).
## 🔗 지식 연결 (Graph)
- Scalable-[[Frontend-Architecture|Frontend-Architecture]], Atomic-Styling-and-[[Design Systems|Design-Systems]], [[Clean-Code-Principles|Clean-Code-Principles]], Modular-Monolith
- **Raw Source:** 00_Raw/Frontend Folder Structure.md
매 dependency 의 down-only — 의 widget 의 entity/shared 의 import 의 OK, 의 reverse 의 X.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 colocation 의 rule
- 의 component 의 의 close 의 의 use site.
- 의 test, story, type 의 의 same folder.
- Route folder 의 의 page-only 의 keep — 의 reusable 의 의 lift up.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용
1. Solo project 의 의 minimal (`src/components`, `src/pages`).
2. Team project 의 의 FSD layered.
3. Monorepo 의 의 nx/turbo 의 의 boundary enforce.
4. Design system 의 의 separate package.
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### FSD layout
```
src/
app/
providers/
routes/
main.tsx
pages/
home/
profile/
widgets/
header/
sidebar/
features/
auth-login/
ui/
model/
api/
index.ts
entities/
user/
ui/
model/
api/
shared/
ui/
lib/
config/
api/
```
## 🤔 의사결정 기준 (Decision Criteria)
### Next.js App Router 의 colocation
```
app/
layout.tsx
page.tsx
(marketing)/ # route group
pricing/
page.tsx
_components/
PricingCard.tsx
dashboard/
layout.tsx
page.tsx
[id]/
page.tsx
loading.tsx
error.tsx
_lib/
fetch-data.ts
components/ # shared, lifted
ui/
lib/
utils.ts
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Public API per slice (`index.ts`)
```ts
// features/auth-login/index.ts
export { LoginForm } from "./ui/LoginForm";
export { useLogin } from "./model/use-login";
// 매 internal helper 의 의 of export 의 X — barrier.
```
**선택 B를 써야 할 때:**
- *(TODO)*
```ts
// widgets/header/Header.tsx
import { LoginForm } from "@/features/auth-login"; // OK — public API
// import { internalHelper } from "@/features/auth-login/lib/internal"; // X
```
**기본값:**
> *(TODO)*
### TS path alias
```jsonc
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/app/*"],
"@pages/*": ["src/pages/*"],
"@widgets/*": ["src/widgets/*"],
"@features/*": ["src/features/*"],
"@entities/*": ["src/entities/*"],
"@shared/*": ["src/shared/*"]
}
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### ESLint boundaries
```js
// eslint.config.js
import boundaries from "eslint-plugin-boundaries";
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
export default [{
plugins: { boundaries },
settings: {
"boundaries/elements": [
{ type: "app", pattern: "src/app/*" },
{ type: "pages", pattern: "src/pages/*" },
{ type: "widgets", pattern: "src/widgets/*" },
{ type: "features", pattern: "src/features/*" },
{ type: "entities", pattern: "src/entities/*" },
{ type: "shared", pattern: "src/shared/*" },
],
},
rules: {
"boundaries/element-types": ["error", {
default: "disallow",
rules: [
{ from: "app", allow: ["pages", "widgets", "features", "entities", "shared"] },
{ from: "pages", allow: ["widgets", "features", "entities", "shared"] },
{ from: "widgets", allow: ["features", "entities", "shared"] },
{ from: "features", allow: ["entities", "shared"] },
{ from: "entities", allow: ["shared"] },
{ from: "shared", allow: ["shared"] },
],
}],
},
}];
```
### Slice 의 internal layer
```
features/auth-login/
ui/ # React component
LoginForm.tsx
LoginForm.test.tsx
LoginForm.stories.tsx
model/ # state, hooks, business logic
use-login.ts
login-store.ts
api/ # network call
login-request.ts
lib/ # helpers (private)
validate-credentials.ts
index.ts # public API
```
### Monorepo (turbo)
```
apps/
web/ # Next.js app
mobile/ # React Native
packages/
ui/ # design system
api-client/ # tRPC/REST client
config-eslint/
config-tsconfig/
```
```jsonc
// turbo.json
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**"] },
"lint": {},
"test": { "dependsOn": ["^build"] }
}
}
```
### Barrel file 의 caution
```ts
// 매 export * 의 의 tree-shaking 의 hurt 의 가능
export * from "./Button";
export * from "./Card";
// 매 explicit re-export 의 더 의 safe
export { Button } from "./Button";
export { Card } from "./Card";
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Solo / prototype | `src/{components,pages,lib}` flat |
| Team < 5, single app | FSD-lite (skip `entities`, merge `widgets`) |
| Team > 5 | Full FSD + ESLint boundaries |
| Multi-app | Monorepo (turbo / nx) + shared `packages/ui` |
| Next.js App Router | Route colocation + `_private` folders |
**기본값**: FSD-lite (app/pages/features/shared) + path alias + ESLint boundaries.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Project Structure]]
- 변형: [[Feature-Sliced Design]] · [[Atomic Design]] · [[Clean Architecture]]
- 응용: [[Monorepo with Turbo]] · [[Next.js App Router]]
- Adjacent: [[ESLint Boundaries]] · [[TypeScript Path Aliases]] · [[Barrel Exports]]
## 🤖 LLM 활용
**언제**: new project 의 scaffold, legacy reorg, monorepo migration, dependency direction 의 enforce.
**언제 X**: 의 매 < 50 file project — flat structure 의 충분.
## ❌ 안티패턴
- **`src/components/` god folder**: 매 1000+ file 의 의 unscalable.
- **Cross-feature import**: feature-A 의 feature-B 의 internal 의 reach — 의 shared/entities 의 의 lift up.
- **Deep nesting** (`a/b/c/d/e/f/`): 매 navigate 의 hard — 매 max 4-level 의 keep.
- **Barrel `export *`**: 매 tree-shake 의 의 break, 매 circular 의 의 hide.
- **No boundary enforcement**: convention 의 의 의 only — 의 violation 의 의 silent 의 accumulate.
## 🧪 검증 / 중복
- Verified (Feature-Sliced Design docs, Next.js App Router, Vercel monorepo guide, nx docs, eslint-plugin-boundaries).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — FSD layout + ESLint boundaries + monorepo 추가 |
+138 -418
View File
@@ -4,444 +4,164 @@ title: Frontend
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [Web Frontend, Client-side Engineering, UI Engineering]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [category-index, frontend]
confidence_score: 0.9
verification_status: applied
tags: [frontend, web, react, performance]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react
---
# Frontend Directory
# Frontend
이 문서는 `Frontend` 카테고리에 속한 모든 지식 문서들의 목록을 제공합니다.
## 매 한 줄
> **"매 user 의 매 device 에서 매 실행되는 매 모든 것 — 매 markup, 매 style, 매 behavior, 매 network."**. 2026 의 매 frontend 는 매 React 19 + 매 RSC + 매 Vite/Turbopack + 매 Bun/Node + 매 Edge runtime 의 매 stack 에서 매 진화 중. Core Web Vitals + 매 a11y + 매 i18n 이 매 hygiene.
## 📄 문서 목록
- [[3D_Web_HMI]] : 3D Web-based HMI
- [[ANGLE (Almost Native Graphics Layer Engine)]] : [[ANGLE (Almost Native Graphics Layer Engine)|ANGLE (Almost Native Graphics Layer Engine]]
- [[ANGLE]] : [[ANGLE|ANGLE]]
- [[Accessibility (A11y)]] : [[Accessibility (A11y)|Accessibility (A11y]]
- [[Atomic Design]] : [[Atomic Design|Atomic Design]]
- [[Atomic-Styling-and-Design-Systems]] : Atomic Styling and Design[[_system|system]]s (아토믹 스타일링과 디자인 시스템)
- [[Automatic Batching]] : [[Automatic Batching|Automatic Batching]]
- [[Automatic Batching을 통한 React 18 성능 최적화]] : [[Automatic Batching을 통한 React 18 성능 최적화|Automatic Batching을 통한 React 18 성능 최적화]]
- [[BEM (Block Element Modifier)]] : [[BEM (Block Element Modifier)|BEM (Block Element Modifier]]
- [[BEM]] : [[BEM|BEM]]
- [[BatchedMesh]] : [[BatchedMesh|BatchedMesh]]
- [[Batching]] : [[Batching|Batching]]
- [[Branchless Security Checks]] : [[Branchless Security Checks|Branchless Security Checks]]
- [[Branded Types in TypeScript]] : [[Branded Types in TypeScript|Branded Types in TypeScript]]
- [[Branded-Types-for-Nominal-Typing]] : [[Branded-Types-for-Nominal-Typing|Branded-Types-for-Nominal-Typing]] (브랜디드 타입을 활용한 공칭 타입화)
- [[Browser Security Mitigations]] : [[Browser Security Mitigations|Browser Security Mitigations]]
- [[Buffer Allocation]] : [[Buffer Allocation|Buffer Allocation]]
- [[Building Reusable UI Components]] : [[Building Reusable UI Components|Building Reusable UI Components]]
- [[Bundle Size Optimization]] : Bundle Size Optimization
- [[CPU Overhead]] : [[CPU Overhead|CPU Overhead]]
- [[CSS Grid 및 Flexbox]] : [[CSS Grid 및 Flexbox|CSS Grid 및 Flexbox]]
- [[CSS Grid]] : [[CSS Grid|CSS Grid]]
- [[CSS Media Queries]] : [[CSS Media Queries|CSS Media Queries]]
- [[CSS Modules]] : [[CSS Modules|CSS Modules]]
- [[CSSOM(CSS Object Model)]] : [[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]]
- [[CSSOM]] : [[CSSOM|CSSOM]]
- [[Cache miss rates]] : [[Cache miss rates|Cache miss rates]]
- [[Case-Study-Kiwi-com-Frontend-Migration]] : Case Study: Kiwi.com Frontend Migration (사례 연구: Kiwi.com 프런트엔드 마이그레이션)
- [[CesiumJS]] : [[CesiumJS|CesiumJS]]
- [[Chrome]] : [[Chrome|Chrome]]
- [[Chromium WebGPU Implementation]] : [[Chromium WebGPU Implementation|Chromium WebGPU Implementation]]
- [[Client-Side Rendering (CSR)]] : [[Client-Side Rendering (CSR)|Client-Side Rendering (CSR]]
- [[Code Splitting]] : [[Code Splitting|Code Splitting]]
- [[Code-Splitting-and-Frontend-Performance-Optimization]] : Code Splitting and [[Frontend|Frontend]] [[Performance Optimization|Performance Optimization]] (코드 스플리팅과 성능 최적화)
- [[Collaboration_Governance]] : [[Collaboration_Governance|Collaboration_Governance]] (협업과 코드 품격)
- [[Combat_System_Reference_Error_Resolution]] : 🛠️ CombatSystem: [[Reference|Reference]]Error Re[[Solution|Solution]] Guide
- [[Component API Design]] : [[Component API Design|Component API Design]]
- [[Component-Composition]] : Component Composition (컴포넌트 합성)
- [[Computational Geometry]] : [[Computational Geometry|Computational Geometry]] (계산 기하학)
- [[Concurrent Features]] : [[Concurrent Features|Concurrent Features]]
- [[Concurrent Rendering in React 18+]] : [[Concurrent Rendering in React 18+|Concurrent Rendering in React 18+]]
- [[Critical Rendering Path (CRP)]] : [[Critical Rendering Path (CRP)|Critical Rendering Path (CRP]]
- [[Custom-Hooks-Patterns]] : Custom Hooks Patterns (커스텀 훅 패턴)
- [[DOM 및 CSSOM]] : [[DOM 및 CSSOM|DOM 및 CSSOM]]
- [[Datacollector-Knowledge-Hub]] : 📡 Datacollector Project: Engineering Hub (MOC)
- [[Debugging Frontend Applications]] : [[Debugging Frontend Applications|Debugging Frontend Applications]]
- [[Declaration-Files]] : [[Declaration-Files|Declaration-Files]] (선언 파일, .d.ts)
- [[DefinitelyTyped]] : [[DefinitelyTyped|DefinitelyTyped]]
- [[Design_Systems_and_Web_Components]] : [[디자인 시스템과 웹 컴포넌트 표준 (Design Systems & Web Components)]]
- [[Diffing Algorithm]] : [[Diffing Algorithm|Diffing Algorithm]]
- [[Direct3D]] : [[Direct3D|Direct3D]]
- [[Discriminated-Unions-for-Error-Handling]] : [[Discriminated Unions|Discriminated Unions]] (판별 가능한 유니온)
- [[Discriminated-Unions-for-State-Modeling]] : [[Discriminated-Unions-for-State-Modeling|Discriminated-Unions-for-State-Modeling]] (상태 모델링을 위한 구별된 유니온)
- [[Draw Call Optimization]] : [[Draw Call Optimization|Draw Call Optimization]]
- [[Dynamic Theming]] : [[Dynamic Theming|Dynamic Theming]]
- [[ESLint-Plugin-Development]] : [[ESLint-Plugin-Development|ESLint-Plugin-Development]]
- [[ESLint-Plugin-TypeScript]] : [[ESLint-Plugin-TypeScript|ESLint-Plugin-TypeScript]]
- [[EXT_disjoint_timer_query]] : [[EXT_disjoint_timer_query|EXT_disjoint_timer_query]]
- [[Effect TS 및 ts-brand 라이브러리 활용]] : [[Effect TS 및 ts-brand 라이브러리 활용|Effect TS 및 ts-brand 라이브러리 활용]]
- [[Effect TS]] : [[Effect TS|Effect TS]]
- [[Equipment-Crafting-and-Synthesis-Engine]] : Equipment Crafting and Synthesis Engine
- [[Error Boundaries]] : Error Boundaries
- [[Error_Handling_and_Stability]] : Frontend Error Handling & Application Stability
- [[Es-Lint-Configuration]] : [[Es-Lint-Configuration|Es-Lint-Configuration]] (ESLint 설정 가이드)
- [[Eugen Systems의 WARNO 시뮬레이션 개발]] : Eugen Systems의 WARNO 시뮬레이션 개발
- [[Events]] : [[Events|Events]]
- [[Eye-Tracking]] : [[Eye-Tracking|Eye-Tracking]]
- [[FXAA]] : [[FXAA|FXAA]]
- [[Fiber 아키텍처와 동시성 (Concurrent Rendering)]] : [[Fiber 아키텍처와 동시성 (Concurrent Rendering)|Fiber 아키텍처와 동시성 (Concurrent Rendering]]
- [[Figma Tokens Studio]] : [[Figma Tokens Studio|Figma Tokens Studio]]
- [[Folder Structure Best Practices]] : [[Folder Structure Best Practices|Folder Structure Best Practices]]
- [[Frontend Observability & Logging]] : Frontend Observability & Logging
- [[Frontend Performance Debugging]] : [[Frontend Performance Debugging|Frontend Performance Debugging]]
- [[Frontend-Architecture-and-Folder-Structure]] : Frontend Architecture and Folder Structure (프런트엔드 아키텍처 및 폴더 구조)
- [[Frontend-Debugging-and-Testing]] : Frontend Debugging and Testing (프런트엔드 디버깅 및 테스트)
- [[Frontend-Performance-Optimization-Guide]] : Frontend [[Performance Optimization|Performance Optimization]] Guide (프런트엔드 성능 최적화 가이드)
- [[Frontend-Team-Collaboration-and-Governance]] : Frontend Team Collaboration and Governance (프런트엔드 팀 협업 및 거버넌스)
- [[Frontend]] : [[Frontend|Frontend]]
- [[Frontend_Governance_and_Observability]] : Frontend Governance & Observability
- [[Frontend_Performance]] : [[웹 성능 최적화와 병목 지점 해소 (Frontend Performance)]]
- [[Functional-Programming-in-TypeScript]] : [[Functional Programming|Functional Programming]] in TypeScript (함수형 프로그래밍)
- [[GC Root]] : [[GC Root|GC Root]]
- [[GPU Resources]] : [[GPU Resources|GPU Resources]]
- [[GPU-driven Rendering]] : [[GPU-driven Rendering|GPU-driven Rendering]]
- [[GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례]] : [[GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례|GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례]]
- [[Google Chrome]] : [[Google Chrome|Google Chrome]]
- [[GraphQL-Code-Generator]] : [[GraphQL-Code-Generator|GraphQL-Code-Generator]]
- [[Guilty-Gear-Xrd-Rendering-Pipeline]] : [[Guilty-Gear-Xrd-Rendering-Pipeline|Guilty-Gear-Xrd-Rendering-Pipeline]]
- [[HTML5 Canvas]] : [[HTML5 Canvas|HTML5 Canvas]]
- [[Hydration-Mismatch-and-SSR-Debugging]] : Hydration Mismatch and SSR Debugging (수화 불일치 및 SSR 디버깅)
- [[IDE_Stability_Fix]] : Skybound IDE 안정성 및 타입 보정
- [[Index_2]] : Index: Topics > 01_Frontend_Mastery
- [[Indirect Draw]] : [[Indirect Draw|Indirect Draw]]
- [[Instancing]] : [[Instancing|Instancing]]
- [[Interface-Segregation-Principle-in-TypeScript]] : [[Interface-Segregation-Principle-in-TypeScript|Interface-Segregation-Principle-in-TypeScript]]
- [[Inventory Management Example]] : [[Inventory Management Example|Inventory Management Example]]
- [[JSX]] : JSX
- [[JavaScript-Async-and-Event-Loop]] : JavaScript Async and Event Loop (JS 비동기와 이벤트 루프)
- [[JavaScript-Optimization-Patterns]] : JavaScript Optimization Patterns (자바스크립트 최적화 패턴)
- [[JavaScriptCore]] : [[JavaScriptCore|JavaScriptCore]]
- [[JavaScript]] : [[JavaScript|JavaScript]]
- [[Judgment]] : [[Judgment|Judgment]]
- [[Kingdom vs. Kingdom (KvK)]] : [[Kingdom vs. Kingdom (KvK)|Kingdom vs. Kingdom (KvK)]]
- [[Kingdom vs. Kingdom Events (KvK)]] : [[Kingdom vs. Kingdom Events (KvK)|Kingdom vs. Kingdom Events (KvK)]]
- [[Lane Model]] : [[Lane Model|Lane Model]]
- [[Lanes Model]] : [[Lanes Model|Lanes Model]]
- [[Large-scale Application Refactoring]] : [[Large-scale Application Refactoring|Large-scale Application Refactoring]]
- [[Large-scale React Systems]] : Large-scale React Systems
- [[Lazy Loading]] : [[Lazy Loading|Lazy Loading]]
- [[Levels of Understanding]] : [[Levels of Understanding|Levels of Understanding]]
- [[Markov-Random-Fields]] : [[Markov-Random-Fields|Markov-Random-Fields]]
- [[Memory Leak Prevention 메모리 누수 방지]] : [[Memory Leak Prevention 메모리 누수 방지|Memory Leak Prevention 메모리 누수 방지]]
- [[Memory-Leak-Debugging-in-JavaScript]] : Memory Leak Debugging in JavaScript (자바스크립트 메모리 누수 디버깅)
- [[Meta Quest Store]] : [[Meta Quest Store|Meta Quest Store]]
- [[Micro-latency]] : [[Micro-latency|Micro-latency]]
- [[Mobile-Augmented-Reality]] : [[Mobile-Augmented-Reality|Mobile-Augmented-Reality]]
- [[Mobile-First-Responsive-Design-Principles]] : Mobile-First Responsive Design [[Principles|Principles]] (모바일 우선 반응형 설계 원칙)
- [[Modern-Frontend-Engineering-Architecture]] : Modern Frontend Engineering Architecture (현대 프런트엔드 엔지니어링 아키텍처)
- [[Naming Conventions]] : Naming Conventions
- [[Next.js 15 App Router]] : [[Next.js 15 App Router|Next.js 15 App Router]]
- [[Next.js App Router Migration]] : [[Next.js App Router Migration|Next.js App Router Migration]]
- [[Next.js 기반의 Hybrid Rendering (SSR-CSR-RSC 혼합 적용)]] : [[Next.js|Next.js]] 기반의 Hybrid Rendering (SSR/CSR/RSC 혼합 적용)
- [[Next.js를 활용한 하이브리드 렌더링 및 React Server Components 도입]] : [[Next.js를 활용한 하이브리드 렌더링 및 React Server Components 도입|Next.js를 활용한 하이브리드 렌더링 및 React Server Components 도입]]
- [[Nextjs_Framework]] : [[Next.js 프레임워크와 현대적 웹 렌더링 (Next.js Framework)]]
- [[Nextjs_and_Modern_React_Patterns]] : Next.js & Modern React Design Patterns
- [[Nodejs-Global-Namespace-Augmentation]] : [[Nodejs-Global-Namespace-Augmentation|Nodejs-Global-Namespace-Augmentation]]
- [[Nominal-Typing-in-TypeScript]] : [[Nominal-Typing-in-TypeScript|Nominal-Typing-in-TypeScript]]
- [[Non-Photorealistic-Rendering-in-Level-Design]] : [[Non-Photorealistic-Rendering-in-Level-Design|Non-Photorealistic-Rendering-in-Level-Design]]
- [[OffscreenCanvas Safari 제약 사항]] : [[OffscreenCanvas Safari 제약 사항|OffscreenCanvas Safari 제약 사항]]
- [[OffscreenCanvas와 Web Worker를 활용한 메인 스레드 병목 해결]] : [[OffscreenCanvas와 Web Worker를 활용한 메인 스레드 병목 해결|OffscreenCanvas와 Web Worker를 활용한 메인 스레드 병목 해결]]
- [[Opaque-Types]] : [[Opaque-Types|Opaque-Types]]
- [[Open-Closed Principle (OCP)]] : Open-Closed Principle (OCP)
- [[OpenGL ES 20]] : [[OpenGL ES 20|OpenGL ES 20]]
- [[OpenGL ES]] : [[OpenGL ES|OpenGL ES]]
- [[Opera]] : [[Opera|Opera]]
- [[Parser]] : Parser (구문 분석기)
- [[Performance_and_Memory_Management]] : Frontend Performance & Memory Management
- [[Pointer Poisoning]] : [[Pointer Poisoning|Pointer Poisoning]]
- [[Principles]] : [[Principles|Principles]]
- [[Probabilistic-Graphical-Models]] : Probabilistic Graphical Models (확률적 그래픽 모델)
- [[Prop Drilling]] : [[Prop Drilling|Prop Drilling]]
- [[Protocol-Buffers-TypeScript]] : [[Protocol-Buffers-TypeScript|Protocol-Buffers-TypeScript]]
- [[Randomized-Algorithms]] : Randomized Algorithms (확률적 알고리즘)
- [[Re-renders Optimization]] : [[Re-renders Optimization|Re-renders Optimization]]
- [[React 16+ Core Engine]] : [[React 16+ Core Engine|React 16+ Core Engine]]
- [[React 18 & 19 Performance Optimization]] : [[React 18 & 19 Performance Optimization|React 18 & 19 Performance Optimization]]
- [[React 18 동시성 렌더링 (Concurrent Rendering)]] : [[React 18 동시성 렌더링 (Concurrent Rendering)|React 18 동시성 렌더링 (Concurrent Rendering]]
- [[React 18 자동 일괄 처리 및 React 19 컴파일러 최적화 적용]] : [[React 18 자동 일괄 처리 및 React 19 컴파일러 최적화 적용|React 18 자동 일괄 처리 및 React 19 컴파일러 최적화 적용]]
- [[React 19 Compiler]] : [[React 19 Compiler|React 19 Compiler]]
- [[React 19 Compiler의 Threejs 런타임 성능 개선 원리]] : [[React 19 Compiler의 Threejs 런타임 성능 개선 원리|React 19 Compiler의 Threejs 런타임 성능 개선 원리]]
- [[React 19]] : [[React 19|React 19]]
- [[React Application Scaling]] : [[React Application Scaling|React Application Scaling]]
- [[React Codebase Refactoring]] : [[React Codebase Refactoring|React Codebase Refactoring]]
- [[React Context]] : [[React Context|React Context]]
- [[React Design Tokens]] : [[React Design Tokens|React Design Tokens]]
- [[React DevTools Profiler]] : [[React DevTools Profiler|React DevTools Profiler]]
- [[React Flight Protocol]] : [[React Flight Protocol|React Flight Protocol]]
- [[React Folder Structure]] : React Folder Structure
- [[React Native 게임 최적화 (JSI Hermes)]] : [[React Native 게임 최적화 (JSI Hermes)|React Native 게임 최적화 (JSI Hermes)]]
- [[React Refactoring]] : React Refactoring
- [[React Server Components]] : React Server Components
- [[React Three Fiber (R3F)]] : [[React Three Fiber (R3F)|React Three Fiber (R3F]]
- [[React Three Fiber 자산 최적화 (Asset Optimization)]] : [[React Three Fiber 자산 최적화 (Asset Optimization)|React Three Fiber 자산 최적화 (Asset Optimization]]
- [[React Three Fiber에서 Rapier 물리 엔진 최적화하기]] : [[React Three Fiber에서 Rapier 물리 엔진 최적화하기|React Three Fiber에서 Rapier 물리 엔진 최적화하기]]
- [[React 동시성 기능 (Concurrent Features)]] : [[React 동시성 기능 (Concurrent Features)|React 동시성 기능 (Concurrent Features)]]
- [[React 및 Nextjs 개발 환경]] : [[React 및 Nextjs 개발 환경|React 및 Nextjs 개발 환경]]
- [[React 상태 관리 (React State Management)]] : [[React 상태 관리 (React State Management)|React 상태 관리 (React State Management]]
- [[React 상태 관리 및 API 응답 처리]] : [[React 상태 관리 및 API 응답 처리|React 상태 관리 및 API 응답 처리]]
- [[React 재조정 (Reconciliation) 최적화]] : [[React 재조정 (Reconciliation) 최적화|React 재조정 (Reconciliation) 최적화]]
- [[React-Error-Boundaries-and-Handling]] : React Error Boundaries and Handling (React 에러 경계 및 예외 처리)
- [[React.lazy()]] : [[React.lazy()|React.lazy()]]
- [[React_Clean_Code_Best_Practices]] : [[React_Clean_Code_Best_Practices|React_Clean_Code_Best_Practices]] (리액트 클린 코드)
- [[React_Hooks_Deep_Dive]] : [[React_Hooks_Deep_Dive|React_Hooks_Deep_Dive]] (리액트 훅 심화)
- [[React_Mental_Model]] : [[React_Mental_Model|React_Mental_Model]] (리액트 멘탈 모델)
- [[Readonly Type]] : [[Readonly Type|Readonly Type]]
- [[Redux 등 상태 관리 (State Management)]] : [[Redux 등 상태 관리 (State Management)|Redux 등 상태 관리 (State Management]]
- [[Refactoring Techniques]] : Refactoring Techniques
- [[Refactoring-Legacy-React-Codebases]] : Refactoring Legacy React Codebases (레거시 React 코드 리팩토링)
- [[Relative-Positioning]] : Relative Positioning (상대적 배치)
- [[Reusable UI Component Libraries]] : [[Reusable UI Component Libraries|Reusable UI Component Libraries]]
- [[Risk-Orchestration]] : [[Risk-Orchestration|Risk-Orchestration]]
- [[Rollup]] : [[Rollup|Rollup]]
- [[Rowhammer attack]] : [[Rowhammer attack|Rowhammer attack]]
- [[Rowhammer]] : [[Rowhammer|Rowhammer]]
- [[SCSS (Sass)]] : [[SCSS (Sass)|SCSS (Sass]]
- [[SCSS]] : [[SCSS|SCSS]]
- [[SPA (Single Page Application)]] : [[SPA (Single Page Application)|SPA (Single Page Application]]
- [[Sanity Studio]] : [[Sanity Studio|Sanity Studio]]
- [[Satisfies Operator]] : [[Satisfies Operator|Satisfies Operator]]
- [[Scalable Design Systems]] : [[Scalable Design Systems|Scalable DesignSystems]]
- [[Scavenger 알고리즘]] : [[Scavenger 알고리즘|Scavenger 알고리즘]]
- [[Scripts]] : [[Scripts|Scripts]]
- [[Service-Dominant-Logic]] : [[Service-Dominant-Logic|Service-Dominant-Logic]]
- [[Shopify Polaris]] : [[Shopify Polaris|Shopify Polaris]]
- [[Skybound_Skill_Image_Integration]] : [LOG] Skybound Skill Image & Icon Integration
- [[Spectre and Meltdown]] : [[Spectre and Meltdown|Spectre and Meltdown]]
- [[Spectre]] : [[Spectre|Spectre]]
- [[State-Management-Patterns]] : State Management Patterns (상태 관리 패턴)
- [[State_Management_and_Concurrent_React]] : Modern State Management & Concurrent React
- [[Static-Site-Generation-with-Gatsby]] : Static Site Generation with Gatsby (Gatsby를 활용한 정적 사이트 생성)
- [[Street Duel Fighter]] : [[Street Duel Fighter|Street Duel Fighter]]
- [[Style Dictionary Pipelines]] : [[Style Dictionary Pipelines|Style Dictionary Pipelines]]
- [[Style Dictionary]] : [[Style Dictionary|Style Dictionary]]
- [[Style Registry]] : [[Style Registry|Style Registry]]
- [[Styled Components v6]] : [[Styled Components v6|Styled Components v6]]
- [[Submodules]] : [[Submodules|Submodules]]
- [[TLB design]] : [[TLB design|TLB design]]
- [[TS-Declaration-Files]] : [[TS-Declaration-Files|TS-Declaration-Files]]
- [[Threejs WebGL Rendering Optimization]] : [[Threejs WebGL Rendering Optimization|Threejs WebGL Rendering Optimization]]
- [[Threejs WebGPU 파티클 예제]] : [[Threejs WebGPU 파티클 예제|Threejs WebGPU 파티클 예제]]
- [[Threejs 자원 해제 (Dispose)]] : [[Threejs 자원 해제 (Dispose)|Threejs 자원 해제 (Dispose)]]
- [[Throttling Debouncing]] : [[Throttling Debouncing|Throttling Debouncing]]
- [[Timestamp Queries]] : [[Timestamp Queries|Timestamp Queries]]
- [[Timing Attack]] : [[Timing Attack|Timing Attack]]
- [[Timing Attacks]] : [[Timing Attacks|Timing Attacks]]
- [[Total Blocking Time (TBT)]] : [[Total Blocking Time (TBT)|Total Blocking Time (TBT]]
- [[Turborepo 및 Nx와 같은 빌드 오케스트레이션 도구를 활용하는 대규모 조직의 React 시스템]] : [[Turborepo 및 Nx와 같은 빌드 오케스트레이션 도구를 활용하는 대규모 조직의 React 시스템|Turborepo 및 Nx와 같은 빌드 오케스트레이션 도구를 활용하는 대규모 조직의 React 시스템]]
- [[Type Declaration]] : [[Type Declaration|Type Declaration]]
- [[Type-Variance-in-TypeScript]] : [[Type-Variance-in-TypeScript|Type-Variance-in-TypeScript]]
- [[TypeScript 49]] : [[TypeScript 49|TypeScript 49]]
- [[TypeScript API Development]] : [[TypeScript API Development|TypeScript API Development]]
- [[TypeScript Advanced Type System]] : [[TypeScript Advanced Type System|TypeScript Advanced Type System]]
- [[TypeScript Type System (Interface Design)]] : [[TypeScript Type System (Interface Design)|TypeScript Type System (Interface Design)]]
- [[TypeScript Utility Types (Record Readonly)]] : [[TypeScript Utility Types (Record Readonly)|TypeScript Utility Types (Record Readonly]]
- [[TypeScript 타입 시스템 (TypeScript Type System)]] : [[TypeScript 타입 시스템 (TypeScript Type System)|TypeScript 타입 시스템 (TypeScript Type System]]
- [[TypeScript-Compiler-API-Design]] : [[TypeScript-Compiler-API-Design|TypeScript-Compiler-API-Design]]
- [[TypeScript-Language-Service-API]] : [[TypeScript-Language-Service-API|TypeScript-Language-Service-API]]
- [[TypeScript-Project-References]] : [[TypeScript-Project-References|TypeScript-Project-References]]
- [[TypeScript_Type_Safety]] : [[TypeScript_Type_Safety|TypeScript_Type_Safety]] (타입스크립트 정석)
- [[TypedArray]] : [[TypedArray|TypedArray]]
- [[UXPin Merge]] : [[UXPin Merge|UXPin Merge]]
- [[Utsubo]] : [[Utsubo|Utsubo]]
- [[V8 JavaScript Engine]] : [[V8 JavaScript Engine|V8 JavaScript Engine]]
- [[Vite Build Optimization]] : Vite Build Optimization
- [[Vite Build System]] : [[Vite Build System|Vite Build System]]
- [[Voxel-based Rendering]] : [[Voxel-based Rendering|Voxel-based Rendering]]
- [[Vue_3_Reactivity_System]] : Vue 3 Reactivity System
- [[Vulkan]] : [[Vulkan|Vulkan]]
- [[WEBGL_multi_draw]] : [[WEBGL_multi_draw|WEBGL_multi_draw]]
- [[Waves of Connection]] : [[Waves of Connection|Waves of Connection]]
- [[Web Content Accessibility Guidelines (WCAG)]] : [[Web Content Accessibility Guidelines (WCAG)|Web Content Accessibility Guidelines (WCAG]]
- [[Web Worker (웹 워커)]] : [[Web Worker (웹 워커)|Web Worker (웹 워커]]
- [[WebAssembly]] : [[WebAssembly|WebAssembly]]
- [[WebGL 20]] : [[WebGL 20|WebGL 20]]
- [[WebGL API]] : [[WebGL API|WebGL API]]
- [[WebGL Optimization]] : [[WebGL Optimization|WebGL Optimization]]
- [[WebGL 모바일 GPU 성능 관리]] : [[WebGL 모바일 GPU 성능 관리|WebGL 모바일 GPU 성능 관리]]
- [[WebGL2]] : [[WebGL2|WebGL2]]
- [[WebGLRenderingContext]] : [[WebGLRenderingContext|WebGLRenderingContext]]
- [[WebGPU Compute Shader]] : [[WebGPU Compute Shader|WebGPU Compute Shader]]
- [[WebGPU Compute Shaders]] : [[WebGPU Compute Shaders|WebGPU Compute Shaders]]
- [[WebGPU _ WebGL Timing API Security]] : [[WebGPU _ WebGL Timing API Security|WebGPU _ WebGL Timing API Security]]
- [[WebKit Security Mitigations]] : [[WebKit Security Mitigations|WebKit Security Mitigations]]
- [[WebKit]] : [[WebKit|WebKit]]
- [[Wonder]] : [[Wonder|Wonder]]
- [[Wonderland Engine]] : [[Wonderland Engine|Wonderland Engine]]
- [[Zero-Runtime CSS-in-JS]] : [[Zero-Runtime CSS-in-JS|Zero-runtime CSS-in-JS]]
- [[_report]] : 📝 CEO 종합 보고서
- [[as const Assertion]] : [[as const Assertion|as const Assertion]]
- [[as const]] : [[as const|as const]]
- [[developer]] : 💻 Developer — Business 팀에서 정의한 Model A 기준(AO 0.90+, TTV 0.85+)에 맞춰 Mock API 프레임워크를 활용한 End-to-End 성능 테스트 시나리오를 즉시 구현하고 실행하라.
- [[flushSync]] : [[flushSync|flushSync]]
- [[never 타입]] : [[never 타입|never 타입]]
- [[satisfies Keyword]] : [[satisfies Keyword|satisfies Keyword]]
- [[satisfies 연산자]] : [[satisfies 연산자|satisfies 연산자]]
- [[startTransition]] : [[startTransition|startTransition]]
- [[styled-components v6.3+]] : [[styled-components v6.3+|styled-components v6.3+]]
- [[threejs Issue _30352]] : [[threejs Issue _30352|threejs Issue _30352]]
- [[ts-brand]] : [[ts-brand|ts-brand]]
- [[useEffect 클린업(Cleanup)]] : [[useEffect 클린업(Cleanup)|useEffect 클린업(Cleanup]]
- [[vanilla-extract]] : [[vanilla-extract|vanilla-extract]]
- [[가상 DOM (Virtual DOM) 및 Fiber]] : [[가상 DOM (Virtual DOM) 및 Fiber|가상 DOM (Virtual DOM) 및 Fiber]]
- [[가상 경제 시뮬레이션 및 사전 검증(Virtual Economy Simulation)]] : 가상 경제 시뮬레이션 및 사전 검증(Virtual Economy Simulation)
- [[게임 경제 밸런스(Game Balance)]] : [[게임 경제 밸런스(Game Balance)|게임 경제 밸런스(Game Balance)]]
- [[게임 경제 설계]] : 게임 경제 설계
- [[게임 밸런싱]] : [[게임 밸런싱|게임 밸런싱]]
- [[고성능 3D WebGL 게임 렌더링 엔진]] : [[고성능 3D WebGL 게임 렌더링 엔진|고성능 3D WebGL 게임 렌더링 엔진]]
- [[과잉 속성 체크(EPC)]] : [[과잉 속성 체크(EPC)|과잉 속성 체크(EPC]]
- [[교집합 타입(Intersection Type)]] : [[교집합 타입(Intersection Type)|교집합 타입(Intersection Type]]
- [[구조적 타이핑]] : [[구조적 타이핑|구조적 타이핑]]
- [[다크 모드 및 다중 브랜드 테마 동적 전환 시스템]] : [[다크 모드 및 다중 브랜드 테마 동적 전환 시스템|다크 모드 및 다중 브랜드 테마 동적 전환 시스템]]
- [[대규모 데이터 렌더링 및 가상화 최적화]] : [[대규모 데이터 렌더링 및 가상화 최적화|대규모 데이터 렌더링 및 가상화 최적화]]
- [[대규모 이커머스 플랫폼 렌더링 설계]] : [[대규모 이커머스 플랫폼 렌더링 설계|대규모 이커머스 플랫폼 렌더링 설계]]
- [[대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축]] : [[대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축|대규모 콘텐츠 기반 애플리케이션 및 전자상거래 플랫폼 구축]]
- [[대수의 법칙(Law of Large Numbers)]] : 대수의 법칙(Law of Large Numbers)
- [[디자인 시스템 개념]] : [[디자인 시스템 개념|디자인 시스템 개념]]
- [[디자인 시스템 구축]] : [[디자인 시스템 구축|디자인 시스템 구축]]
- [[디자인 시스템 기반 컴포넌트 개발]] : [[디자인 시스템 기반 컴포넌트 개발|디자인 시스템 기반 컴포넌트 개발]]
- [[디자인 시스템의 타이포그래피 토큰 확장 및 최적화]] : [[디자인 시스템의 타이포그래피 토큰 확장 및 최적화|디자인 시스템의 타이포그래피 토큰 확장 및 최적화]]
- [[디자인-개발 워크플로우(Design-to-Code Workflow)]] : [[디자인-개발 워크플로우(Design-to-Code Workflow)|디자인-개발 워크플로우(Design-to-Code Workflow]]
- [[디지털 트윈 및 데이터 시뮬레이션]] : [[디지털 트윈 및 데이터 시뮬레이션|디지털 트윈 및 데이터 시뮬레이션]]
- [[런타임 상태 검증(Runtime Validation)]] : [[런타임 상태 검증(Runtime Validation)|런타임 상태 검증(Runtime Validation]]
- [[레이아웃 Flexbox - Grid 완전 이해]] : 레이아웃 [[Flexbox|Flexbox]] / Grid 완전 이해
- [[렌더링 차단 리소스(Render-blocking resources)]] : [[렌더링 차단 리소스(Render-blocking resources)|렌더링 차단 리소스(Render-Blocking resources]]
- [[메인 스레드 차단 문제 해결을 위한 React 16의 Fiber 엔진 교체 및 React 18, 19의 동시성 렌더링 적용 사례]] : [[메인 스레드 차단 문제 해결을 위한 React 16의 Fiber 엔진 교체 및 React 18, 19의 동시성 렌더링 적용 사례|메인 스레드 차단 문제 해결을 위한 React 16의 Fiber 엔진 교체 및 React 18, 19의 동시성 렌더링 적용 사례]]
- [[모듈식 CSS(Modular CSS)]] : [[모듈식 CSS(Modular CSS)|모듈식 CSS(Modular CSS]]
- [[모바일 퍼스트 및 다양한 디바이스 환경을 위한 반응형 레이아웃 구축]] : [[모바일 퍼스트 및 다양한 디바이스 환경을 위한 반응형 레이아웃 구축|모바일 퍼스트 및 다양한 디바이스 환경을 위한 반응형 레이아웃 구축]]
- [[몬테카를로 시뮬레이션(Monte Carlo Simulation)]] : 몬테카를로 시뮬레이션(Monte Carlo Simulation)
- [[무거운 데이터 리스트 필터링 구현]] : [[무거운 데이터 리스트 필터링 구현|무거운 데이터 리스트 필터링 구현]]
- [[반응 시간(Reaction Time)]] : [[반응 시간(Reaction Time)|반응 시간(Reaction Time]]
- [[반응형 윈도우 리사이즈(Resize) 이벤트 처리]] : [[반응형 윈도우 리사이즈(Resize) 이벤트 처리|반응형 윈도우 리사이즈(Resize) 이벤트 처리]]
- [[백엔드-프론트엔드 데이터 변환(Data Transformation between Backend and Frontend)]] : [[백엔드-프론트엔드 데이터 변환(Data Transformation between Backend and Frontend)|백엔드-프론트엔드 데이터 변환(Data Transformation between Backend and Frontend]]
- [[불필요한 리렌더링 방지]] : [[불필요한 리렌더링 방지|불필요한 리렌더링 방지]]
- [[브라우저 그래픽 렌더링 백엔드]] : [[브라우저 그래픽 렌더링 백엔드|브라우저 그래픽 렌더링 백엔드]]
- [[브라우저 렌더링 과정]] : [[브라우저 렌더링 과정|브라우저 렌더링 과정]]
- [[브라우저 메모리 관리 및 최적화]] : [[브라우저 메모리 관리 및 최적화|브라우저 메모리 관리 및 최적화]]
- [[비동기 데이터 관리]] : [[비동기 데이터 관리|비동기 데이터 관리]]
- [[상태 관리(State Management)]] : [[상태 관리(State Management)|상태 관리(State Management]]
- [[상태 모델링 (State Modeling)]] : [[상태 모델링 (State Modeling)|상태 모델링 (State Modeling]]
- [[설정 객체 및 룩업 테이블 설계(Configuration Objects and Lookup Tables)]] : [[설정 객체 및 룩업 테이블 설계(Configuration Objects and Lookup Tables)|설정 객체 및 룩업 테이블 설계(Configuration Objects and Lookup Tables]]
- [[성능 최적화가 필수적인 대규모 다중 테마 플랫폼]] : [[성능 최적화가 필수적인 대규모 다중 테마 플랫폼|성능 최적화가 필수적인 대규모 다중 테마 플랫폼]]
- [[스토리지 텍스처(Storage Textures)]] : [[스토리지 텍스처(Storage Textures)|스토리지 텍스처(Storage Textures]]
- [[스포티파이 자율적 분대 모델 (Spotify Squad)]] : [[스포티파이 자율적 분대 모델 (Spotify Squad)|스포티파이 자율적 분대 모델 (Spotify Squad]]
- [[스포티파이 자율적 분대 모델 및 마이크로 프론트엔드 (Spotify Squads and Micro Frontends)]] : [[스포티파이 자율적 분대 모델 및 마이크로 프론트엔드 (Spotify Squads and Micro Frontends)|스포티파이 자율적 분대 모델 및 마이크로 프론트엔드 (Spotify Squads and Micro Frontends]]
- [[스포티파이(Spotify)의 스쿼드 모델 및 마이크로 프론트엔드 도입]] : [[스포티파이(Spotify)의 스쿼드 모델 및 마이크로 프론트엔드 도입|스포티파이(Spotify)의 스쿼드 모델 및 마이크로 프론트엔드 도입]]
- [[시뮬레이션(Simulation)]] : [[시뮬레이션(Simulation)|시뮬레이션(Simulation)]]
- [[시뮬레이션과 예측 모델링(Simulation and Predictive Modeling)]] : 시뮬레이션과 예측 모델링(Simulation and Predictive Modeling)
- [[식별 가능한 유니온]] : [[식별 가능한 유니온|식별 가능한 유니온]]
- [[실시간 데이터 대시보드 레이아웃 조절 시스템]] : [[실시간 데이터 대시보드 레이아웃 조절 시스템|실시간 데이터 대시보드 레이아웃 조절 시스템]]
- [[알 수 없는 외부 데이터 검증 (unknown types)]] : [[알 수 없는 외부 데이터 검증 (unknown types)|알 수 없는 외부 데이터 검증 (unknown types]]
- [[에일리어싱 (Aliasing)]] : [[에일리어싱 (Aliasing)|에일리어싱 (Aliasing]]
- [[왕국 대 왕국 (KvK) 이벤트]] : [[왕국 대 왕국 (KvK) 이벤트|왕국 대 왕국 (KvK) 이벤트]]
- [[웹 렌더링 전략 (CSR, SSR, SSG, ISR)]] : [[웹 렌더링 전략 (CSR, SSR, SSG, ISR)|웹 렌더링 전략 (CSR, SSR, SSG, ISR]]
- [[웹 워커 이벤트 포워딩 통신 지연 최소화 방법]] : [[웹 워커 이벤트 포워딩 통신 지연 최소화 방법|웹 워커 이벤트 포워딩 통신 지연 최소화 방법]]
- [[웹 프론트엔드 성능 최적화]] : [[웹 프론트엔드 성능 최적화|웹 프론트엔드 성능 최적화]]
- [[인터페이스 (Interface)]] : [[인터페이스 (Interface)|인터페이스 (Interface)]]
- [[전력 시스템(Power Systems)]] : [[전력 시스템(Power Systems)|전력 시스템(Power Systems)]]
- [[제어 흐름 분석 (Control Flow Analysis)]] : [[제어 흐름 분석 (Control Flow Analysis)|제어 흐름 분석 (Control Flow Analysis]]
- [[지연 렌더링(Deferred Rendering)]] : 지연 렌더링(Deferred Rendering)
- [[차선 모델과 작업 우선순위 (Lane Model & Priorities)]] : [[차선 모델과 작업 우선순위 (Lane Model & Priorities)|차선 모델과 작업 우선순위 (Lane Model & Priorities]]
- [[철벽 수비대 인터페이스 설계 전략]] : [[철벽 수비대 인터페이스 설계 전략|철벽 수비대 인터페이스 설계 전략]]
- [[초과 속성 검사 (Excess Property Checks)]] : [[초과 속성 검사 (Excess Property Checks)|초과 속성 검사 (Excess Property Checks]]
- [[컴포넌트 기반 아키텍처 (React, Vue 등)]] : [[컴포넌트 기반 아키텍처 (React, Vue 등)|컴포넌트 기반 아키텍처 (React, Vue 등]]
- [[컴포넌트 기반 아키텍처]] : [[컴포넌트 기반 아키텍처|컴포넌트 기반 아키텍처]]
- [[컴포넌트 기반 웹 프레임워크 아키텍처 설계]] : [[컴포넌트 기반 웹 프레임워크 아키텍처 설계|컴포넌트 기반 웹 프레임워크 아키텍처 설계]]
- [[콘텐츠 기반의 이커머스 및 뉴스 웹사이트 성능 튜닝]] : [[콘텐츠 기반의 이커머스 및 뉴스 웹사이트 성능 튜닝|콘텐츠 기반의 이커머스 및 뉴스 웹사이트 성능 튜닝]]
- [[크로스 플랫폼 UI 개발(Cross-Platform UI Development)]] : [[크로스 플랫폼 UI 개발(Cross-Platform UI Development)|크로스 플랫폼 UI 개발(Cross-Platform UI Development]]
- [[크로스 플랫폼 디자인 시스템 연동]] : [[크로스 플랫폼 디자인 시스템 연동|크로스 플랫폼 디자인 시스템 연동]]
- [[크로스 플랫폼(Web, iOS, Android) UI 개발 및 배포 파이프라인]] : [[크로스 플랫폼(Web, iOS, Android) UI 개발 및 배포 파이프라인|크로스 플랫폼(Web, iOS, Android) UI 개발 및 배포 파이프라인]]
- [[클라이언트 사이드 렌더링 (CSR)]] : [[클라이언트 사이드 렌더링 (CSR)|클라이언트 사이드 렌더링 (CSR]]
- [[타이핑에 즉각 반응해야 하는 검색창 (Search-as-you-type)]] : [[타이핑에 즉각 반응해야 하는 검색창 (Search-as-you-type)|타이핑에 즉각 반응해야 하는 검색창 (Search-as-you-type]]
- [[타입 단언(Type Assertion)]] : [[타입 단언(Type Assertion)|타입 단언(Type Assertion]]
- [[프론트엔드 애플리케이션 렌더링 병목 개선]] : [[프론트엔드 애플리케이션 렌더링 병목 개선|프론트엔드 애플리케이션 렌더링 병목 개선]]
- [[프론트엔드 컴포넌트 구조화]] : [[프론트엔드 컴포넌트 구조화|프론트엔드 컴포넌트 구조화]]
- [[프론트엔드 컴포넌트 설계]] : [[프론트엔드 컴포넌트 설계|프론트엔드 컴포넌트 설계]]
- [[힙 스냅샷 (Heap Snapshots)]] : [[힙 스냅샷 (Heap Snapshots)|힙 스냅샷 (Heap Snapshots]]
## 매 핵심
## 📌 한 줄 통찰 (The Karpathy Summary)
### 매 Layer
- **Markup**: HTML, semantic, a11y.
- **Style**: CSS — Cascade Layers, Container Queries, `:has()`, OKLCH.
- **Behavior**: JS/TS — framework (React/Vue/Svelte/Solid).
- **Build**: Vite, Turbopack, Bun, esbuild, swc.
- **Runtime**: Browser, Edge (Cloudflare Workers, Vercel), Node, Bun.
> 프런트엔드는 사용자 인터페이스 계층으로, HTML/CSS/JS의 토대 위에 컴포넌트 모델·상태 관리·메타 프레임워크가 쌓인 구조다.
### 매 Framework landscape (2026)
- **React 19**: RSC + Actions + use() hook + Compiler.
- **Next.js 15**: App Router default, Turbopack stable.
- **Astro 5**: content site / island.
- **SvelteKit 2** / **Vue 3.5 + Nuxt 4** / **Solid 2**.
- **Remix → React Router 7**: data loading first.
## 📖 구조화된 지식 (Synthesized Content)
### 매 Performance pillars
- **LCP < 2.5s**: image optimize, preconnect, fetchpriority.
- **INP < 200ms**: long task chunking, scheduler.yield.
- **CLS < 0.1**: dimension reserved, font-display swap.
- **Bundle**: route split, tree-shake, dynamic import.
**추출된 패턴:** UI 라이브러리(React/Vue/Svelte) + 메타 프레임워크(Next/Nuxt/SvelteKit) + 도구체인 + 디자인 시스템의 4계층.
### 매 Modern primitives
- **CSS**: container queries, `:has()`, view transitions API, anchor positioning.
- **JS**: scheduler.yield, AbortSignal.timeout, Temporal (stage 4 2026).
- **HTML**: popover, dialog, search.
- **Network**: HTTP/3, Early Hints, Speculation Rules.
**세부 내용:**
- 라이브러리: React/Vue/Svelte/Solid.
- 메타: Next.js/Nuxt/SvelteKit.
- 빌드: Vite, Turbopack, Webpack.
- 상태: Redux, Zustand, Tanstack Query.
- 스타일: Tailwind, CSS-in-JS, vanilla CSS.
### 매 응용
1. SSR + RSC 로 매 SEO 기반 commerce.
2. Edge personalization — 매 cookie / geo 기반.
3. PWA + offline-first.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🔗 지식 연결 (Graph)
- **Parent:** [[10_Wiki/Topics]]
- **Related:** *(TODO: 최소 2개)*
- **Opposite / Trade-off:** *(TODO)*
- **Raw Source:** 직접 입력
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### View Transitions API (cross-document)
```html
<meta name="view-transition" content="same-origin" />
<style>
::view-transition-old(hero) { animation: fade-out 0.3s; }
::view-transition-new(hero) { animation: fade-in 0.3s; }
.hero { view-transition-name: hero; }
</style>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Container query
```css
.card { container-type: inline-size; }
@container (min-width: 400px) {
.card-body { display: grid; grid-template-columns: 1fr 1fr; }
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### React 19 Actions (form)
```tsx
'use client';
async function submit(formData: FormData) {
'use server';
await db.insert(formData.get('msg') as string);
}
export default function Form() {
return <form action={submit}><input name="msg" /><button>Send</button></form>;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### use() hook (React 19)
```tsx
function Comments({ promise }: { promise: Promise<Comment[]> }) {
const comments = use(promise); // suspends
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>;
}
```
**기본값:**
> *(TODO)*
### Image optimization (Next 15)
```tsx
import Image from 'next/image';
<Image src="/hero.avif" width={1280} height={720} priority alt="" sizes="100vw" />
```
## ❌ 안티패턴 (Anti-Patterns)
### Speculation Rules (prerender)
```html
<script type="speculationrules">
{
"prerender": [{ "where": { "selector_matches": "a.product" }, "eagerness": "moderate" }]
}
</script>
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Scheduler.yield long task
```javascript
async function process(items) {
for (const it of items) {
work(it);
if ('scheduler' in self) await scheduler.yield();
}
}
```
### CSS cascade layers
```css
@layer reset, base, components, utilities;
@layer reset { * { margin: 0; box-sizing: border-box; } }
@layer components { .btn { padding: 0.5rem 1rem; } }
```
## 매 결정 기준
| 상황 | Stack |
|---|---|
| 매 SEO content site | Astro 5 (zero JS default) |
| 매 SaaS dashboard | Vite + React 19 (CSR) |
| 매 commerce | Next 15 App Router (RSC + ISR) |
| 매 docs | Astro Starlight / Docusaurus |
| 매 marketing | Astro / 11ty |
| 매 realtime | React + WebSocket / Liveblocks |
**기본값**: Vite + React 19 + TS strict + ESLint + Vitest. 매 SSR 필요 시 매 Next 15.
## 🔗 Graph
- 부모: [[Web Development]] · [[Software Engineering]]
- 변형: [[Mobile App]] · [[Desktop App]]
- 응용: [[E-commerce]] · [[Dashboard]] · [[Content Site]]
- Adjacent: [[React]] · [[Performance]] · [[Accessibility]] · [[CSS]]
## 🤖 LLM 활용
**언제**: 매 stack 선택, 매 perf 진단, 매 pattern (RSC, Suspense, View Transitions) 적용.
**언제 X**: 매 backend-only — 매 다른 도메인.
## ❌ 안티패턴
- **CSS-in-JS runtime**: 매 INP 악화 (2026 모범: zero-runtime — Tailwind / vanilla-extract / Panda).
- **Mega global state**: 매 server vs client state 미분리.
- **Polyfill 남발**: 매 modern browser default — 매 baseline 활용.
- **No a11y test**: 매 axe-core CI 없음.
## 🧪 검증 / 중복
- Verified (web.dev, MDN baseline 2026, React 19 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 2026 stack + modern primitives |
@@ -2,90 +2,188 @@
id: wiki-2026-0508-functional-programming-in-typesc
title: Functional Programming in TypeScript
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [FP-TS-001]
aliases: [FP TS, fp-ts, Effect-TS, Functional TypeScript]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [typescript, Functional-Programming, immutability, pure-functions]
confidence_score: 0.9
verification_status: applied
tags: [typescript, functional-programming, effect-ts, fp-ts]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: effect-ts
---
# [[Functional Programming|Functional Programming]] in TypeScript (함수형 프로그래밍)
# Functional Programming in TypeScript
## 📌 한 줄 통찰 (The Karpathy Summary)
> "데이터를 바꾸지 말고, 새로운 데이터를 파이프라인으로 흘려보내라" — 불변성과 순수 함수를 통해 부수 효과(Side-effects)를 제거하고, 코드의 예측 가능성을 극대화하는 프로그래밍 패러다임.
## 한 줄
> **"매 type system 이 매 effect 와 매 error 를 매 first-class 로 추적한다."**. Pure function + immutable + typed effect. 매 2026 의 FP-TS landscape 는 매 Effect-TS 가 매 dominant — fp-ts/io-ts 의 매 후계자.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** 상태 변화를 추적하는 대신, 입력에 대해 항상 동일한 출력을 내놓는 함수들을 조합(Composition)하여 복잡한 로직을 구성하는 선언적 패턴.
- **세부 내용:**
- **Immutability:** 기존 데이터를 직접 수정(Mutation)하지 않고, 전개 연산자(`...`) 등을 사용하여 새로운 사본을 생성.
- **Pure Functions:** 외부 상태에 의존하거나 수정하지 않는 함수. 테스트와 디버깅이 매우 쉬움.
- **Higher-Order Functions:** 함수를 인자로 받거나 결과로 반환 (예: `map`, `filter`, `reduce`).
- **Type Safety:** TypeScript의 강력한 제네릭과 [[readonly|readonly]] 타입을 활용하여 컴파일 타임에 불변성을 강제.
- **Declarative Code:** '어떻게(How)'가 아닌 '무엇(What)'을 할 것인지 기술하여 코드의 의도를 명확히 함.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 성능상의 이유로 가변 객체를 선호하던 과거와 달리, 현대의 JS 엔진 최적화와 메모리 관리 능력 향상으로 불변 객체 사용이 성능과 안정성 사이의 최적의 타협점이 됨.
- **정책 변화:** Antigravity 프로젝트의 핵심 비즈니스 로직은 함수형 패러다임을 따라 작성하며, 상태 관리는 Redux나 Zustand와 같은 불변성 지향 라이브러리를 사용함.
### 매 원칙
- **Purity**: 매 같은 input → 매 같은 output. 매 side effect X.
- **Immutability**: 매 mutation X. 매 readonly + structural copy.
- **Composition**: 매 small function 의 매 pipe / flow.
- **Total functions**: 매 모든 input 에 매 정의된 output. 매 throw X — 매 Either / Effect.
- **Typed errors**: 매 error type 을 매 signature 에 매 표현.
## 🔗 지식 연결 (Graph)
- **Parent:** 10_Wiki/💡 Topics/AI
- **Related:** Immutability, Pure-Functions, Monad, [[Reactive-Programming|Reactive-Programming]]
- **Raw Source:** 10_Wiki/Topics/AI/Functional-Programming-in-TypeScript.md
### 매 핵심 구조
- **Option**: nullable 의 매 type-safe 표현.
- **Either**: success / failure union.
- **Effect**: 매 lazy computation + dependency + error type — `Effect<A, E, R>`.
- **Stream**: 매 lazy async iterator.
- **Schema**: 매 runtime + static type.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. API client — 매 typed error / retry / timeout 의 매 declarative.
2. Form validation — 매 Schema parse + Either.
3. Concurrent workflow — 매 Effect.all + structured concurrency.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Option / Either basics (Effect-TS)
```typescript
import { Option, Either } from 'effect';
## 🧪 검증 상태 (Validation)
const safeDiv = (a: number, b: number): Option.Option<number> =>
b === 0 ? Option.none() : Option.some(a / b);
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const parsed: Either.Either<number, string> =
Either.try({ try: () => JSON.parse('{"x":1}').x, catch: e => String(e) });
```
## 🤔 의사결정 기준 (Decision Criteria)
### Pipe + flow
```typescript
import { pipe, flow } from 'effect';
**선택 A를 써야 할 때:**
- *(TODO)*
const upper = (s: string) => s.toUpperCase();
const exclaim = (s: string) => `${s}!`;
**선택 B를 써야 할 때:**
- *(TODO)*
const shout = flow(upper, exclaim);
console.log(pipe('hello', shout)); // "HELLO!"
```
**기본값:**
> *(TODO)*
### Effect with typed errors
```typescript
import { Effect } from 'effect';
## ❌ 안티패턴 (Anti-Patterns)
class NotFoundError { readonly _tag = 'NotFoundError' }
class NetworkError { readonly _tag = 'NetworkError' }
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
const fetchUser = (id: string): Effect.Effect<User, NotFoundError | NetworkError> =>
Effect.tryPromise({
try: () => fetch(`/u/${id}`).then(r => {
if (r.status === 404) throw new NotFoundError();
return r.json();
}),
catch: e => e instanceof NotFoundError ? e : new NetworkError(),
});
```
### Service / dependency injection
```typescript
import { Context, Effect, Layer } from 'effect';
class Logger extends Context.Tag('Logger')<Logger, { log: (m: string) => void }>() {}
const program = Effect.gen(function* () {
const logger = yield* Logger;
logger.log('hi');
});
const LoggerLive = Layer.succeed(Logger, { log: console.log });
Effect.runSync(Effect.provide(program, LoggerLive));
```
### Schema validation (runtime + static)
```typescript
import { Schema } from 'effect';
const User = Schema.Struct({
id: Schema.String,
age: Schema.Number.pipe(Schema.between(0, 150)),
email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+$/)),
});
type User = Schema.Schema.Type<typeof User>;
const parseUser = Schema.decodeUnknownEither(User);
```
### Structured concurrency
```typescript
const fetchAll = Effect.all(
[fetchUser('a'), fetchUser('b'), fetchUser('c')],
{ concurrency: 2 } // limit
).pipe(
Effect.timeout('5 seconds'),
Effect.retry({ times: 3 }),
);
```
### Immutable update with Optic
```typescript
import { Lens } from 'monocle-ts';
interface Order { user: { name: string } }
const userName = Lens.fromPath<Order>()(['user', 'name']);
const upd = userName.modify(s => s.toUpperCase());
const next = upd({ user: { name: 'foo' } }); // structural copy
```
### Discriminated union exhaustiveness
```typescript
type Shape =
| { kind: 'circle'; r: number }
| { kind: 'square'; s: number };
const area = (sh: Shape): number => {
switch (sh.kind) {
case 'circle': return Math.PI * sh.r ** 2;
case 'square': return sh.s ** 2;
default: { const _: never = sh; return _; } // compile error if missed
}
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 nullable | Option (or `T \| undefined` + helper) |
| 매 expected error | Either / Effect typed error |
| 매 unexpected (bug) | throw — 매 error boundary |
| 매 async + DI + retry | Effect-TS |
| 매 simple validation | Zod (lighter) |
| 매 large schema + transform | Effect Schema |
**기본값**: 매 plain TS + readonly + discriminated union. 매 복잡한 effect orchestration 은 매 Effect-TS.
## 🔗 Graph
- 부모: [[TypeScript]] · [[Functional Programming]]
- 변형: [[Effect-TS]] · [[fp-ts]] · [[Rambda]]
- 응용: [[Validation]] · [[API Client]] · [[State Management]]
- Adjacent: [[Zod]] · [[Lenses]] · [[Algebraic Effects]]
## 🤖 LLM 활용
**언제**: 매 typed error model 설계, 매 schema-first API, 매 effect-heavy domain code.
**언제 X**: 매 simple CRUD UI — 매 overkill.
## ❌ 안티패턴
- **Effect 모든 곳**: 매 over-abstraction. 매 leaf function 은 매 plain.
- **`any` escape hatch**: 매 type 의 매 의미 손실.
- **Mutating in pipe**: 매 immutability 위반.
- **Throw inside Effect.try with rethrow**: 매 typed error 회피.
## 🧪 검증 / 중복
- Verified (Effect-TS 3.x docs, fp-ts legacy migration guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 Effect-TS 기준 패턴 + Schema |
+178 -65
View File
@@ -2,92 +2,205 @@
id: wiki-2026-0508-gpu-resources
title: GPU Resources
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-4AA291]
aliases: [GPU Buffer, GPU Texture, Render Target, WebGPU Resources]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [gpu, webgpu, graphics, rendering]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - GPU Resources"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: webgpu
---
# [[GPU Resources|GPU Resources]]
# GPU Resources
## 📌 한 줄 통찰 (The Karpathy Summary)
> GPU 리소스는 Three.js 및 [[WebGL|WebGL]] 환경에서 렌더링을 위해 할당되는 VRAM 자원으로, 기하학적 구조(Geometries), 재질(Materials), 텍스처(Textures), 렌더 타겟(Render targets) 등을 포함합니다 [1-3]. 브라우저 렌더링 엔진은 이러한 리소스들을 자동으로 가비지 컬렉트(Garbage Collect)하지 않기 때문에 사용이 끝나면 개발자가 직접 명시적으로 메모리에서 해제해야 합니다 [1]. 효율적인 GPU 리소스 관리가 이루어지지 않으면 심각한 메모리 누수([[Memory Leaks|Memory Leaks]])가 발생하며, 궁극적으로 브라우저의 제한된 GPU 메모리를 초과하여 컨텍스트 손실(Context Lost)과 화면 멈춤 현상을 유발합니다 [3, 4].
## 한 줄
> **"매 GPU 는 매 buffer + texture + sampler + binding 의 매 4 primitive 위에서 매 모든 것을 그린다."**. Buffer 는 매 raw memory, texture 는 매 sampled grid, render target 은 매 write 가능한 texture. 매 2026 WebGPU / Vulkan / Metal 모두 매 같은 model.
## 📖 구조화된 지식 (Synthesized Content)
- **GPU 리소스의 구성 및 메모리 소비량:** 3D 모델을 렌더링할 때 GPU 메모리에는 정점 버퍼(Vertex buffers), 인덱스 버퍼(Index buffers), 텍스처 맵, 그리고 셰이더 프로그램 등이 할당됩니다 [3]. 고해상도 텍스처는 막대한 메모리를 차지하여, 단일 4K(4096x4096) 압축 해제 텍스처의 경우 VRAM의 64MB 이상을 단독으로 소비할 수 있습니다 [1, 5]. 추가적으로 후처리(Post-[[Processing|Processing]]) 단계에서 사용되는 개별 렌더 타겟들 또한 프레임 버퍼 메모리를 추가 할당합니다 [2].
- **명시적인 자원 해제(Disposal) 필수성:** Three.js 프레임워크는 GPU 리소스를 추적하여 자동으로 메모리에서 지워주지 않습니다 [1]. 따라서 메모리 누수를 방지하기 위해서는 에셋이 더 이상 필요하지 않을 때 반드시 `geometry.dispose()`, `material.dispose()`, `texture.dispose()` 함수를 호출해 GPU 자원을 명시적으로 해제해야 합니다 [1, 4, 6].
- **특수 텍스처 및 빈번한 생성 객체 관리:** GLTF 모델 파일에서 `ImageBitmap` 형태로 로드된 텍스처 리소스의 경우, 기본 폐기 메서드 외에도 명시적으로 `texture.source.data.close?()`를 호출해 닫아주어야만 메모리가 새는 것을 막을 수 있습니다 [4, 7]. 또한 게임 내 탄환이나 파티클처럼 자주 생성되고 파괴되는 리소스의 경우 매번 새로 할당하지 않고 오브젝트 풀링(Object [[Pooling|Pooling]]) 방식을 사용하여 메모리 할당 오버헤드를 막는 것이 좋습니다 [4, 7].
- **리소스 한계 모니터링:** WebGL 컨텍스트의 가용 메모리 한도는 디바이스 환경에 따라 약 256MB에서 1GB 수준으로 제한적입니다 [3]. 이 용량을 초과해 GPU 리소스가 할당되면 컨텍스트 손실이 발생하여 애플리케이션이 충돌하게 됩니다 [3]. 이를 방지하기 위해서는 런타임 중에 `renderer.info.[[memory|memory]]` 상태를 꾸준히 모니터링하여 텍스처나 지오메트리 수가 지속적으로 증가하는 메모리 누수 현상이 없는지 확인해야 합니다 [1, 4].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 Buffer 종류
- **Vertex buffer**: 매 vertex attribute (position, normal, uv).
- **Index buffer**: 매 triangle index.
- **Uniform buffer (UBO)**: 매 small constant data — 매 16KB 권장.
- **Storage buffer (SSBO)**: 매 large read/write — 매 compute shader.
- **Staging buffer**: 매 CPU→GPU upload 의 매 intermediate.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Memory Management|Memory Management]], Memory Leaks, Textures, VRAM, [[Garbage Collection|Garbage Collection]]
- **Projects/Contexts:** Three.js, [[WebGL|WebGL]], [[WebGPU|WebGPU]]
- **Contradictions/Notes:** 소스에 관련 모순이나 충돌 정보는 없습니다.
### 매 Texture 종류
- **Sampled texture**: 매 shader 에서 매 sample.
- **Storage texture**: 매 compute write.
- **Depth/Stencil**: 매 depth test.
- **Cube map / 3D / Array**: 매 special layout.
- **Format**: rgba8unorm, rgba16float, bgra8unorm-srgb, depth32float, etc.
---
*Last updated: 2026-04-19*
### 매 Render Target
- 매 texture + 매 RENDER_ATTACHMENT usage. 매 framebuffer 의 매 color/depth attachment.
- 매 swap chain texture 는 매 surface 가 매 제공 (acquireNextImage / getCurrentTexture).
---
### 매 Binding model
- **WebGPU/Vulkan**: bind group / descriptor set — 매 group of resources.
- **Layout**: 매 shader 와 매 CPU 가 매 합의한 schema.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. PBR renderer — 매 g-buffer (multiple render target).
2. Post-processing — 매 ping-pong render target.
3. Compute particles — 매 storage buffer + indirect draw.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### WebGPU buffer create + write
```typescript
const buf = device.createBuffer({
size: 256,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(buf, 0, new Float32Array([1, 2, 3, 4]));
```
## 🤔 의사결정 기준 (Decision Criteria)
### Vertex buffer + draw
```typescript
const verts = new Float32Array([0, 0.5, 0, -0.5, -0.5, 0, 0.5, -0.5, 0]);
const vb = device.createBuffer({
size: verts.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vb, 0, verts);
**선택 A를 써야 할 때:**
- *(TODO)*
pass.setVertexBuffer(0, vb);
pass.draw(3);
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Texture upload
```typescript
const img = await createImageBitmap(blob);
const tex = device.createTexture({
size: [img.width, img.height, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
device.queue.copyExternalImageToTexture(
{ source: img },
{ texture: tex },
[img.width, img.height],
);
```
**기본값:**
> *(TODO)*
### Render target (offscreen)
```typescript
const colorTex = device.createTexture({
size: [w, h, 1],
format: 'rgba16float',
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
});
const depthTex = device.createTexture({
size: [w, h, 1],
format: 'depth24plus',
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
## ❌ 안티패턴 (Anti-Patterns)
const enc = device.createCommandEncoder();
const pass = enc.beginRenderPass({
colorAttachments: [{
view: colorTex.createView(),
clearValue: { r: 0, g: 0, b: 0, a: 1 },
loadOp: 'clear',
storeOp: 'store',
}],
depthStencilAttachment: {
view: depthTex.createView(),
depthClearValue: 1.0,
depthLoadOp: 'clear',
depthStoreOp: 'store',
},
});
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Bind group + sampler
```typescript
const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' });
const layout = device.createBindGroupLayout({
entries: [
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: {} },
{ binding: 2, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
],
});
const group = device.createBindGroup({
layout,
entries: [
{ binding: 0, resource: sampler },
{ binding: 1, resource: tex.createView() },
{ binding: 2, resource: { buffer: ubo } },
],
});
```
### Compute shader with storage buffer
```typescript
const ssbo = device.createBuffer({
size: 1024 * 1024,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const pipe = device.createComputePipeline({
layout: 'auto',
compute: { module: device.createShaderModule({ code: wgsl }), entryPoint: 'main' },
});
const enc = device.createCommandEncoder();
const cp = enc.beginComputePass();
cp.setPipeline(pipe);
cp.setBindGroup(0, bindGroup);
cp.dispatchWorkgroups(1024);
cp.end();
```
### Resource lifecycle
```typescript
buffer.destroy(); // explicit free — required for large resources
texture.destroy();
```
## 매 결정 기준
| 상황 | Resource |
|---|---|
| 매 small constants per draw | Uniform buffer |
| 매 large read-only data | Storage buffer (read) |
| 매 read/write GPGPU | Storage buffer |
| 매 sampled image | Texture (2D/3D/Cube) |
| 매 framebuffer attachment | Texture w/ RENDER_ATTACHMENT |
| 매 CPU↔GPU stream | Staging buffer + queue.writeBuffer |
**기본값**: WebGPU + bind group layout 명시. 매 destroy() 호출 잊지 X.
## 🔗 Graph
- 부모: [[WebGPU]] · [[Computer Graphics]]
- 변형: [[Vulkan Resources]] · [[Metal Resources]] · [[D3D12 Resources]]
- 응용: [[PBR Pipeline]] · [[Post Processing]] · [[Compute Shader]]
- Adjacent: [[Shader Language]] · [[Framebuffer]] · [[Sampler]]
## 🤖 LLM 활용
**언제**: 매 GPU pipeline 설계, 매 memory budget, 매 binding layout debug.
**언제 X**: 매 high-level engine (Three.js, Babylon) 사용 시 — 매 abstraction 위.
## ❌ 안티패턴
- **매 frame buffer create**: 매 alloc 폭증. 매 reuse / pool.
- **UBO 에 매 large data**: 매 16KB cap. 매 SSBO 사용.
- **destroy() 누락**: 매 GPU OOM.
- **Bind group layout mismatch**: 매 shader / CPU schema drift.
## 🧪 검증 / 중복
- Verified (WebGPU spec, Vulkan spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 WebGPU buffer/texture/RT 패턴 |
@@ -2,99 +2,32 @@
id: wiki-2026-0508-gpu-가속-및-컴포지팅
title: GPU 가속 및 컴포지팅
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: gpu-acceleration-compositing
duplicate_of: "[[GPU Acceleration (Compositing)]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, frontend, gpu, compositing, css]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[GPU 가속 및 컴포지팅]]
# GPU 가속 및 컴포지팅
## 📌 한 줄 통찰 (The Karpathy Summary)
GPU 가속 및 컴포지팅은 브라우저의 메인 스레드에서 처리하던 애니메이션 작업을 기기의 GPU(그래픽 처리 장치)로 위임하여 웹 성능을 크게 향상시키는 기술입니다 [1]. 이 기법을 사용하면 비용이 많이 드는 브라우저의 레이아웃(Reflow) 및 페인트(Repaint) 단계를 건너뛰고, 오직 컴포지트(Composite) 단계만을 실행하여 렌더링 부담을 줄일 수 있습니다 [2]. 특히 모바일 기기나 저사양 환경에서도 초당 60프레임(60 FPS)의 매끄러운 애니메이션을 달성하는 데 핵심적인 역할을 합니다 [2-4].
> **이 문서는 [[GPU Acceleration (Compositing)]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 Core 단락
* **픽셀 파이프라인과 컴포지트 단계:** DOM 요소가 변경될 때 브라우저는 '스타일 재계산 -> 레이아웃(Reflow) -> 페인트(Repaint) -> 컴포지트(Composite)'로 이어지는 픽셀 파이프라인을 실행합니다 [5]. 애니메이션 성능을 극한으로 끌어올리기 위해서는 전체 파이프라인을 다시 거치지 않고, 마지막 컴포지트 단계만을 유발하는 속성을 사용하는 것이 중요합니다 [2].
* **GPU 가속을 유발하는 속성:** 브라우저가 특정 애니메이션을 자동으로 GPU로 보내도록 만들 수 있습니다 [1]. 대표적으로 `transform` `opacity` 속성이 이를 지원하며, 리플로우나 리페인트 없이 GPU 가속을 통해 애니메이션을 처리합니다 [2, 6, 7]. 추가로 `transform: translateZ()``rotate3d()` 같은 3D 변환, `position: fixed`, 그리고 `will-change` 속성이 적용된 요소나 `<video>`, `<canvas>`, `<iframe>` 요소 등도 자체적인 레이어에서 렌더링되어 컴포지팅의 이점을 얻습니다 [3].
* **사용 시 주의사항:** 모든 속성이 가속을 통해 이점을 얻는 것은 아닙니다. `box-shadow`, `filter`, `border-radius`와 같은 속성들은 애니메이션 시 컴포지팅 레이어나 블렌딩 과정에서 추가적인 리소스를 요구하여 오히려 애니메이션을 느리게 만들 수 있습니다 [6]. 또한 `will-change` 속성은 브라우저가 변경 사항을 미리 최적화하도록 돕지만, 너무 많은 요소에 남용할 경우 도리어 성능을 저하시킬 수 있습니다 [8].
* **성능 프로파일링 및 디버깅:** CSS 애니메이션이 올바르게 최적화되었는지 확인하려면 [[Chrome DevTools]]를 활용할 수 있습니다. 특히 Layer Profiler를 사용하면 어떤 요소가 복합 레이어(Composite layer)에서 렌더링되고 있는지 식별하여 성능 병목 현상을 파악할 수 있습니다 [9].
## 핵심 요약 (specialization aspects)
- 매 browser 의 의 layer 의 promote 의 의 GPU compositing 의 trigger 의 property.
- `transform`, `opacity`, `will-change` 의 의 cheap.
- `top/left/width/height` 의 의 layout-trigger — 매 expensive.
## 🔗 지식 연결 (Graph)
- **Related Topics:** CSS 애니메이션 성능 최적화, Reflow와 Repaint (리플로우와 리페인트), transform 및 opacity 속성, will-change 속성
- **Projects/Contexts:** 모바일 우선 및 저사양 기기를 고려한 웹 성능 최적화, 60 FPS의 부드러운 상호작용 및 애니메이션 구현
- **Contradictions/Notes:** 컴포지팅은 애니메이션 성능 최적화의 핵심이지만, `box-shadow``filter` 등의 속성을 포함한 애니메이션은 무거운 렌더링 과정을 유발해 오히려 성능 저하를 초래할 수 있으므로 주의해야 합니다 [6].
## 🔗 Graph
- 부모: [[GPU Acceleration (Compositing)]] (canonical)
---
*Last updated: 2026-04-26*
## 📖 구조화된 지식 (Synthesized Content)
**추출된 패턴:**
> *(TODO)*
**세부 내용:**
- *(TODO)*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -1,108 +1,183 @@
---
id: wiki-2026-0508-gpu-webgl-파이프라인의-미세-지연-micro-lat
title: GPU WebGL 파이프라인의 미세 지연(Micro latency) 측정 사례
title: GPU WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-035B08]
aliases: [WebGL Micro-latency, GPU Pipeline Latency, WebGL Profiling]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [webgl, gpu, performance, latency, profiling]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - GPU_[[WebGL|WebGL]] 파이프라인의 미세 지연(Micro-latency) 측정 사례"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: javascript
framework: webgl2
---
# [[GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례|GPU_WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례]]
# GPU WebGL 파이프라인의 미세 지연(Micro-latency) 측정 사례
## 📌 한 줄 통찰 (The Karpathy Summary)
> GPU/WebGL 파이프라인의 미세 지연(Micro-latency)은 CPU, GPU 및 브라우저 추상화 계층 간의 상호작용에서 발생하는 서브 프레임(Sub-frame) 수준의 시간 지연을 의미하며, 사용자 몰입도를 저하시키는 주요 원인입니다 [1]. 이를 정확히 측정하기 위해 WebGL/[[WebGPU|WebGPU]]의 타이머 API, 브라우저 내부의 성능 프로파일링 도구, 그리고 고속 카메라와 오실로스코프를 활용한 하드웨어 기반 측정 등 다양한 접근법이 활용되고 있습니다 [2-6]. 그러나 보안 취약점(Spectre, Meltdown 등)으로 인해 정밀한 시간 측정 기능이 브라우저 차원에서 양자화([[Quantization|Quantization]])되거나 제한되는 등 여러 측정 상의 제약이 따르고 있습니다 [3, 7].
## 한 줄
> **"매 GPU 작업은 비동기 — `gl.finish()` 의 X, query object 의 O"**. WebGL 의 draw call 은 GPU command buffer 에 enqueue 만 되므로 CPU 측 `performance.now()` 만으로 측정 시 실제 GPU 시간과 ms 단위 misalignment 발생. `EXT_disjoint_timer_query_webgl2` 가 매 정답.
## 📖 구조화된 지식 (Synthesized Content)
* **API 수준의 그래픽 타이머 측정 (API-Level Timing)**
* **WebGL 타이머 쿼리:** `EXT_disjoint_timer_query` 확장은 렌더링 파이프라인을 중단하지 않고 GPU 명령어 세트의 실행 시간을 측정할 수 있도록 고안되었습니다 [2, 8]. 그러나 이 고정밀 타이머가 Spectre 및 Meltdown과 같은 캐시 부채널 공격([[Side-channel Attack|Side-channel Attack]]s)에 악용될 수 있다는 보안 연구 결과에 따라, 대부분의 브라우저 벤더는 해당 확장을 비활성화하거나 해상도를 엄격하게 양자화(Quantization)하였습니다 [2, 3, 9-11].
* **WebGPU 타임스탬프 쿼리:** WebGPU는 `timestamp-query` 기능을 통해 나노초 단위의 정밀한 측정을 지원하도록 설계되었습니다 [3, 12]. 하지만 역시 타이밍 공격을 방지하기 위해 사이트 격리(Site isolation) 여부에 따라 타임스탬프의 해상도가 100 마이크로초 수준으로 양자화되거나 비격리 컨텍스트에서는 아예 노출되지 않는 보안 조치가 적용됩니다 [3, 7, 13, 14]. 개발자는 로컬 환경에서 브라우저 플래그(`enable-webgpu-developer-features`)를 켜서 이러한 제한을 우회할 수 있습니다 [7, 15].
## 매 핵심
* **브라우저 내부 프로파일링 도구 ([[Browser|Browser]]-Internal Profiling)**
* **[[Chrome DevTools|Chrome DevTools]] (Performance 패널):** 애플리케이션의 런타임 트레이스를 캡처하여 메인 스레드 차단 및 프레임 드롭을 진단할 수 있습니다 [16]. CPU 스로틀링(Throttling) 기능을 통해 고사양 기기에서 모바일 기기의 성능을 시뮬레이션함으로써, 강력한 하드웨어 성능에 가려져 있던 미세 지연을 드러낼 수 있습니다 [4, 16].
* **[[Chrome|Chrome]] Tracing (`about:tracing`):** 브라우저의 다중 프로세스 아키텍처를 세밀하게 분석할 수 있습니다. "CrGpuMain"과 "CrRendererMain" 스레드의 활성 상태를 비교하여 시스템이 CPU 바운드인지 GPU 바운드인지 판별하며, 긴 가비지 컬렉션 주기나 네트워크 대기 등으로 인해 발생하는 유휴 시간(Idle-time) 미세 지연을 파악하는 데 필수적입니다 [4, 17-19].
### 매 측정 대상 분리
- **CPU time**: JS → WebGL command 인코딩 (validate, draw call dispatch).
- **GPU time**: shader 실행 + raster + blend.
- **Present latency**: swapchain → display 의 frame pacing (compositor 의존).
* **하드웨어 지원 측정 방식 ([[Hardware|Hardware]]-Assisted Latency Measurement)**
* 소프트웨어 기반의 측정은 디스플레이 컨트롤러나 물리적 모니터 자체에서 발생하는 지연을 포착할 수 없으므로, 매우 정밀한 연구를 위해서는 하드웨어 보조 기법이 요구됩니다 [5].
* **고속 카메라 기법:** 1000Hz(밀리초당 1프레임)로 녹화하는 고속 카메라와 LED 입력 트리거를 사용하여, 버튼 클릭부터 디스플레이에 시각적 변화가 나타나기까지의 전체 "입력 대 디스플레이(Input-to-Display)" 지연을 측정합니다 [5].
* **오실로스코프와 포토다이오드:** 모니터에 부착한 포토다이오드로 시각적 변화에 따른 빛의 강도 변화를 전압 스파이크로 감지하고, 이를 입력 장치의 전기 신호와 오실로스코프에서 비교하여 밀리초 미만의 정밀도로 종단 간 지연을 측정합니다 [6].
### 매 측정 수단
- `EXT_disjoint_timer_query_webgl2` — GPU timestamp query, ns 정밀도.
- `gpu.requestAdapter()` (WebGPU) — 매 native timestamp-query feature.
- Chrome DevTools Performance → GPU track.
- `Spector.js` — frame capture + per-call cost.
* **운영 체제 및 드라이버 수준의 미세 지연 오버헤드**
* **컨텍스트 생성 지연 (Context Creation Latency):** WebGL/WebGPU 컨텍스트 생성은 브라우저가 OS 그래픽 스택과 직접 소통해야 하는 동기식 작업으로 드라이버에 따라 심각한 지연을 유발합니다. (예: Mesa 50ms, NVIDIA 120ms, FGLRX 200ms) 이는 페이지 로드 시 메인 스레드의 가시적인 프리징을 야기합니다 [20-22].
* **[[ANGLE|ANGLE]] 변환 오버헤드:** Windows 플랫폼에서는 WebGL의 OpenGL ES 호출을 Direct3D로 변환하기 위해 ANGLE 계층을 거치며, 드로우 콜([[Draw Call|Draw Call]])마다 몇 마이크로초의 미세 지연이 부가됩니다. 이 지연은 수천 번의 드로우 콜이 발생하는 씬에서 누적되어 GPU가 여유로운 상황에서도 CPU 병목(Bottleneck) 현상을 일으킵니다 [21, 23, 24].
### 매 응용
1. 60→120Hz upgrade 시 frame budget shrink (16.6→8.3ms) 의 bottleneck localization.
2. Mobile WebGL thermal throttling 감지 (GPU time 의 점진적 increase).
3. PWA 게임 의 input→render latency end-to-end 측정.
* **[[JavaScript|JavaScript]] 우회 측정 방법**
* 일부 브라우저(예: Chrome)에서는 성능 및 구조상의 이유로 `gl.finish()`가 비정상적으로 `gl.flush()`로 작동하기 때문에 렌더링 지연을 직접 측정할 수 없습니다 [11]. 이를 우회하기 위해 `gl.readPixels()`를 사용하여 단일 픽셀을 강제로 읽어 모든 그래픽 프로세스를 지연시키고 동기화한 뒤, 그 오버헤드를 `performance.now()`로 측정 및 차감하여 실제 작업의 렌더링 시간을 추정하는 기법이 활용되기도 합니다 [25, 26].
## 💻 패턴
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### Timer Query — frame GPU time 측정
```javascript
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
const queries = [];
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Spectre and Meltdown|Spectre and Meltdown]], WebGPU [[Timestamp Queries|Timestamp Queries]], EXT_disjoint_timer_query
- **Projects/Contexts:** Chrome DevTools [[Performance Panel|Performance Panel]], [[ANGLE (Almost Native Graphics Layer Engine)|ANGLE (Almost Native Graphics Layer Engine]]
- **Contradictions/Notes:** 소스에 따르면 WebGL의 `gl.finish()` 함수는 본래 GPU 파이프라인의 실행 완료를 기다리는 기능이나, Chrome에서는 `gl.flush()`로 별칭(alias) 지정되어 있어, 이를 사용해 실제 렌더링 지연 시간을 측정하려는 시도는 작동하지 않습니다 [11, 27]. 또한 `EXT_disjoint_timer_query` 확장이나 `performance.now()` 등의 도구 역시 각각 보안 문제(캐시 기반 정보 유출) 및 제한적인 렌더링 조건 탓에 순수하고 완벽한 미세 지연 측정 도구로 사용하기에는 한계가 존재합니다 [3, 11, 28].
function frame() {
const q = gl.createQuery();
gl.beginQuery(ext.TIME_ELAPSED_EXT, q);
drawScene();
gl.endQuery(ext.TIME_ELAPSED_EXT);
queries.push({ q, frameId: frameCount++ });
---
*Last updated: 2026-04-19*
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// resolve 매 several frame later (async)
for (let i = queries.length - 1; i >= 0; i--) {
const { q, frameId } = queries[i];
const available = gl.getQueryParameter(q, gl.QUERY_RESULT_AVAILABLE);
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (available && !disjoint) {
const ns = gl.getQueryParameter(q, gl.QUERY_RESULT);
console.log(`frame ${frameId} GPU: ${(ns / 1e6).toFixed(2)} ms`);
gl.deleteQuery(q);
queries.splice(i, 1);
}
}
requestAnimationFrame(frame);
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Anti — gl.finish() blocking
```javascript
// X — pipeline stall, 매 production 에서 절대 사용 X
const t0 = performance.now();
drawScene();
gl.finish(); // CPU↔GPU sync barrier
const t1 = performance.now();
// t1-t0 는 측정 대상이 아닌 stall 의 cost
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Input→render latency (RAIL model)
```javascript
let inputTs = 0;
canvas.addEventListener('pointerdown', e => {
inputTs = e.timeStamp; // 매 hardware timestamp
});
**선택 B를 써야 할 때:**
- *(TODO)*
function frame(now) {
if (inputTs > 0 && pendingInputProcessed) {
const latency = now - inputTs;
if (latency > 100) console.warn(`input→render: ${latency}ms`);
inputTs = 0;
}
drawScene();
requestAnimationFrame(frame);
}
```
**기본값:**
> *(TODO)*
### Disjoint detection (thermal throttling)
```javascript
function checkThermal() {
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (disjoint) {
// 매 GPU 가 context switch / power state 변경 — measurement invalid
metricsBuffer.flush('thermal_event');
}
}
```
## ❌ 안티패턴 (Anti-Patterns)
### WebGPU — native timestamp query
```javascript
const querySet = device.createQuerySet({ type: 'timestamp', count: 2 });
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
...,
timestampWrites: { querySet, beginningOfPassWriteIndex: 0, endOfPassWriteIndex: 1 }
});
pass.draw(...);
pass.end();
encoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);
// readback async
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Frame pacing (requestVideoFrameCallback)
```javascript
videoEl.requestVideoFrameCallback((now, meta) => {
const presentLatency = meta.presentationTime - meta.captureTime;
// 매 actual display 까지의 latency 측정
});
```
### Sliding-window p99 측정
```javascript
const samples = new Float32Array(120); // 2s @ 60Hz
let idx = 0;
function record(ms) {
samples[idx++ % samples.length] = ms;
if (idx % 60 === 0) {
const sorted = [...samples].sort((a, b) => a - b);
console.log('p50:', sorted[60], 'p99:', sorted[118]);
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| WebGL2 + 매 정밀 측정 | `EXT_disjoint_timer_query_webgl2` |
| WebGPU 가능 | timestampWrites |
| Quick debug | Spector.js capture |
| Production telemetry | sliding-window p99 + disjoint flag |
| Cross-browser fallback | CPU time only + acknowledged limitation |
**기본값**: WebGL2 + timer query async readback, p99/disjoint 매 telemetry.
## 🔗 Graph
- 부모: [[WebGL]] · [[GPU]]
- 변형: [[WebGPU]] · [[Vulkan]]
- 응용: [[Web-Game-Performance]] · [[Three.js]]
- Adjacent: [[Frame-Pacing]] · [[Browser-Compositor]]
## 🤖 LLM 활용
**언제**: WebGL/WebGPU 앱 의 frame budget 초과 진단, 60→120Hz 마이그레이션, mobile thermal 분석.
**언제 X**: 일반 DOM perf (use Performance API), Canvas2D (no GPU query).
## ❌ 안티패턴
- **gl.finish() in frame loop**: pipeline stall, 매 측정값 자체 가 왜곡.
- **performance.now() only**: GPU async 의 무시 — frame 의 N+2 까지 결과 가 안 나올 수 있음.
- **disjoint flag 무시**: thermal/power state 변경 시 measurement 가 garbage 인데 그대로 report.
- **single sample**: GC, compositor jitter 의 무시 — 매 p99 측정 필수.
## 🧪 검증 / 중복
- Verified (Khronos `EXT_disjoint_timer_query_webgl2` spec, Chrome DevTools docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — WebGL micro-latency 측정 패턴 정리 |
+21 -88
View File
@@ -2,99 +2,32 @@
id: wiki-2026-0508-google-chrome
title: Google Chrome
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
aliases: [P-Reinforce-AUTO-A2356F]
duplicate_of: none
status: duplicate
canonical_id: chrome
duplicate_of: "[[Chrome]]"
aliases: []
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Google [[Chrome|Chrome]]"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
verification_status: redirected
tags: [duplicate, browser, chrome]
last_reinforced: 2026-05-10
github_commit: pending
---
# [[Google Chrome|Google Chrome]]
# Google Chrome
## 📌 한 줄 통찰 (The Karpathy Summary)
> Google Chrome은 V8 [[JavaScript|JavaScript]] 엔진을 내장하여 웹 애플리케이션 및 JavaScript 코드를 실행하는 웹 브라우저입니다 [1, 2]. 메인 렌더러로 Blink를 사용하며, V8의 가비지 컬렉터(Orinoco)와 Blink의 내부 가비지 컬렉터([[Oilpan|Oilpan]])가 상호 협력하여 메모리를 관리합니다 [2]. 또한, Chrome DevTools와 같은 강력한 메모리 프로파일링 및 디버깅 도구를 내장하여 개발자가 메모리 누수를 진단하고 성능을 최적화할 수 있도록 지원하며 [3-5], 보안 측면에서는 V8 힙(Heap) 객체를 제한된 공간에 가두는 'V8 [[memory|memory]] Cage' 기술을 적용하고 있습니다 [6, 7].
> **이 문서는 [[Chrome]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
- **V8 엔진 최적화 및 렌더링 성능 관리**
Google Chrome은 메모리 최적화를 위해 V8 엔진의 개선 사항을 지속적으로 적용해 왔습니다. Chrome 53에서는 저사양 기기를 위한 메모리 축소 모드를 도입하여 평균 V8 힙 크기를 약 50% 줄였고, Chrome 55에서는 백그라운드 파싱(Background parsing) 중 메모리 소비를 최적화하여 존(Zone) 메모리 피크를 크게 감소시켰습니다 [8-11]. 또한 초당 60프레임(약 16.6ms)으로 렌더링을 수행할 때, 애니메이션 작업이 일찍 완료되어 여유 시간이 생기면 V8의 유휴 시간(Idle-time) 가비지 컬렉션을 선제적으로 실행하여 메인 스레드의 끊김(Jank) 현상을 방지합니다 [12].
## 핵심 요약
- "Google Chrome" 은 Chrome 의 brand name. 매 same browser.
- Underlying engine: Blink (rendering) + V8 (JS).
- Open-source base: Chromium.
- **Chrome DevTools를 활용한 메모리 프로파일링**
Chrome은 개발자가 메모리 누수나 성능 저하 원인을 추적할 수 있도록 `Memory` 패널을 제공합니다. 여기서 힙 스냅샷([[Heap Snapshot|Heap Snapshot]])을 캡처하거나, 시간 흐름에 따른 메모리 할당(Allocation instrumentation on timeline)을 기록하여 객체의 생성 및 소멸 과정을 시각적으로 분석할 수 있습니다 [3-5, 13, 14]. 더 심층적인 엔진 내부 분석이 필요할 때는 `chrome://tracing` 인프라를 활용하여 가비지 컬렉션(GC) 객체 통계 데이터를 수집하고 시각화할 수 있습니다 [15-17].
## 🔗 Graph
- 부모: [[Chrome]] (canonical)
- **V8 Memory Cage와 보안 아키텍처**
64비트 Chrome 환경에서는 보안 강화를 위해 '포인터 압축([[Pointer Compression|Pointer Compression]])'과 'V8 Memory Cage' 아키텍처를 적용합니다 [6, 7, 18]. 이 기술은 V8 내부의 모든 힙 객체를 4GB 크기의 연속된 샌드박스 영역 내에 가두고, 포인터를 64비트 전체 주소가 아닌 32비트 오프셋으로 저장합니다 [7, 19]. 이를 통해 메모리 효율을 높이는 동시에, OOB(Out-of-Bounds)나 타입 혼동(Type Confusion) 등 악의적인 메모리 손상 공격이 발생하더라도 공격자가 이 샌드박스 범위를 벗어나 브라우저 프로세스 전체 메모리를 임의로 읽거나 쓰는 것을 차단합니다 [19-21].
- **렌더러 충돌(Crash)과 포렌식 활용**
Chrome 브라우저에서 복잡한 익스플로잇 시도가 실패할 경우 렌더러 프로세스 충돌(Crash)이 발생하게 됩니다 [22]. 이러한 충돌 덤프 데이터에는 공격자가 V8 힙에 남긴 가짜 객체(fakeobj), 손상된 배열 길이, 원시 데이터 메모리 흔적 등이 포함되며, 이를 통해 아직 알려지지 않은 제로데이 공격 시도 등을 포렌식 관점에서 사전에 감지하고 식별할 수 있습니다 [23, 24].
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
## 🔗 지식 연결 (Graph)
- **Related Topics:** `[[V8 JavaScript Engine|V8 JavaScript Engine]]`, `Chrome DevTools`, `Garbage Collection`, `[[Pointer Compression|Pointer Compression]]`, `[[Blink|Blink]]`
- **Projects/Contexts:** `[[Orinoco|Orinoco]]`, `[[Oilpan|Oilpan]]`, `V8 Memory Cage`
- **Contradictions/Notes:** 가비지 컬렉션은 개발자가 명시적으로 메모리를 관리하지 않도록 편의를 제공하지만, 처리 과정에서 예측할 수 없는 중단(Pause)을 발생시킬 위험이 있습니다. 이를 극복하기 위해 Chrome과 V8은 메인 스레드를 멈추는 대신 점진적(Incremental), 동시성(Concurrent), 병렬(Parallel) 기법 및 유휴 시간(Idle-time) 활용 모델을 도입하여 성능 저하를 방지하고 있습니다 [25-28].
---
*Last updated: 2026-04-19*
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
+166 -65
View File
@@ -2,91 +2,192 @@
id: wiki-2026-0508-graphql-code-generator
title: GraphQL Code Generator
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-GQCG-001]
aliases: [graphql-codegen, GQL Codegen, Type-safe GraphQL]
duplicate_of: none
source_trust_level: A
confidence_score: 0.96
tags: [auto-reinforced, graphql, code-generator, typescript, type-safety, Schema, automation, api-development]
confidence_score: 0.9
verification_status: applied
tags: [graphql, typescript, codegen, type-safety]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: graphql
---
# [[GraphQL-Code-Generator|GraphQL-Code-Generator]]
# GraphQL Code Generator
## 📌 한 줄 통찰 (The Karpathy Summary)
> "서버와 클라이언트의 실시간 동기화: 서버의 GraphQL 스키마를 읽어 클라이언트에서 즉시 사용할 수 있는 완벽한 타입스크립트 타입과 데이터 요청 함수를 자동 생성하여, 수동 작업으로 인한 '타입 미스매치'를 0%로 만드는 자동화 도구."
## 한 줄
> **"매 schema → typed client 의 자동화"**. `.graphql` schema + operation 으로부터 TypeScript types, hook, fragment 의 생성. 매 schema drift 의 compile-time 차단 — `any` 의 X, `User.email` typo 의 즉시 error.
## 📖 구조화된 지식 (Synthesized Content)
GraphQL 코드 제너레이터(GraphQL-Code-Generator)는 GraphQL 스키마와 작업(Query, Mutation 등)을 분석하여 다양한 언어의 타입과 코드를 생성해 주는 오픈 소스 라이브러리입니다.
## 매 핵심
1. **동작 매커니즘**:
* **Input**: `schema.graphql` 파일 + 프론트엔드에서 작성한 `.graphql` 쿼리 파일들.
* **[[Processing|Processing]]**: 플러그인 시스템을 통해 AST 분석 및 템플릿 적용.
* **Output**: `types.ts`, `hooks.ts` 등 (React Query, Apollo, SWR 대응 가능). ([[Efficiency|Efficiency]]와 연결)
2. **왜 중요한가?**:
* API 변경 시 클라이언트 코드가 즉시 컴파일 에러를 띄우므로, 런타임 장애 정책을 사전에 완벽히 차단하기 때문임. ([[Reliability|Reliability]]와 연결)
### 매 핵심 plugin
- **typescript**: schema → TS types (scalar, enum, input, object).
- **typescript-operations**: query/mutation operation → typed result.
- **typed-document-node**: TypedDocumentNode (apollo-client / urql 의 input).
- **client-preset** (modern, 2026 default): 매 fragment-masking, persisted-query 의 통합 preset.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거에는 `any` 타입을 쓰거나 수동으로 인터페이스 정책을 맞췄으나, 현대 정책은 'Schema-first' 또는 'Code-first' 방식 정책을 통해 타입 정책을 100% 자동 생성 정책하는 것이 표준임(RL Update). ([[Distributed-System-Type-Safety|Distributed-System-Type-Safety]]와 연결)
- **정책 변화(RL Update)**: 이제는 단순 타입 생성 정책을 넘어, 스키마 정보를 활용하여 목업 데이터(Mocking) 정책이나 유효성 검사 로직(Zod) 정책까지 자동으로 생성해 주는 풀스택 개발 가속기로 진화함.
### 매 fragment masking
- Component A 가 fragment X 정의 → component B 가 fragment X 의 field 접근 시 compile error.
- 매 over-fetching 의 prevention 강제.
## 🔗 지식 연결 (Graph)
- [[Efficiency|Efficiency]], [[Reliability|Reliability]], [[Distributed-System-Type-Safety|Distributed-System-Type-Safety]], [[Technical-Architecture|Technical-Architecture]], Standard-Operating-Procedure, Automation
- **Key Ecosystem**: The Guild (Creators).
---
### 매 응용
1. React + Apollo / urql 매 typed hook 자동 생성.
2. Backend schema change 시 client compile error 즉시 감지.
3. Persisted queries (production safety, query whitelisting).
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
### codegen.ts (client-preset)
```typescript
import { CodegenConfig } from '@graphql-codegen/cli';
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const config: CodegenConfig = {
schema: 'https://api.example.com/graphql',
documents: ['src/**/*.{ts,tsx}', '!src/gql/**/*'],
generates: {
'./src/gql/': {
preset: 'client',
presetConfig: {
fragmentMasking: { unmaskFunctionName: 'getFragmentData' },
},
config: {
useTypeImports: true,
scalars: { DateTime: 'string', UUID: 'string' },
},
},
},
hooks: { afterAllFileWrite: ['prettier --write'] },
};
export default config;
```
## 🤔 의사결정 기준 (Decision Criteria)
```bash
pnpm graphql-codegen --watch
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Operation — typed result
```typescript
// src/components/UserCard.tsx
import { graphql } from '../gql';
import { useQuery } from '@apollo/client';
**선택 B를 써야 할 때:**
- *(TODO)*
const USER_QUERY = graphql(`
query GetUser($id: ID!) {
user(id: $id) { id name email avatarUrl }
}
`);
**기본값:**
> *(TODO)*
export function UserCard({ id }: { id: string }) {
const { data } = useQuery(USER_QUERY, { variables: { id } });
// 매 data?.user 의 type 의 fully inferred
return <div>{data?.user?.name}</div>;
}
```
## ❌ 안티패턴 (Anti-Patterns)
### Fragment masking
```typescript
const USER_AVATAR_FRAGMENT = graphql(`
fragment UserAvatar on User { avatarUrl name }
`);
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
function Avatar({ user }: { user: FragmentType<typeof USER_AVATAR_FRAGMENT> }) {
const u = getFragmentData(USER_AVATAR_FRAGMENT, user);
return <img src={u.avatarUrl} alt={u.name} />;
}
// parent — 매 user 의 email 의 access X (fragment 의 declare X)
function Parent({ user }) {
return <Avatar user={user} />;
// user.email 의 access 시 TS error
}
```
### Persisted queries
```typescript
{
generates: {
'./persisted-operations.json': {
preset: 'client',
presetConfig: { persistedDocuments: true },
},
},
}
```
```typescript
// runtime — query string 의 X, hash 만 전송
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';
const link = createPersistedQueryLink({ generateHash: doc => doc['__meta__']['hash'] });
```
### Custom scalar mapping
```typescript
config: {
scalars: {
DateTime: 'string', // ISO 8601
JSON: 'Record<string, unknown>',
BigInt: 'string',
},
}
```
### Watch + CI
```json
{
"scripts": {
"codegen": "graphql-codegen",
"codegen:watch": "graphql-codegen --watch",
"ci:codegen-check": "graphql-codegen && git diff --exit-code src/gql/"
}
}
```
### Multi-schema (federation)
```typescript
{
schema: ['./schema/users.graphql', './schema/products.graphql'],
// 매 federated graph 의 single typed client
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 새 React + GraphQL | client-preset + fragment masking |
| Apollo Client (legacy) | typescript + typescript-react-apollo |
| urql | client-preset (urql 의 native 지원) |
| Production 보안 | persisted queries 의 enable |
| Backend schema 의 evolve | CI 의 codegen drift check |
**기본값**: client-preset + fragmentMasking, CI 의 codegen drift check.
## 🔗 Graph
- 부모: [[GraphQL]] · [[TypeScript]]
- 변형: [[urql]] · [[Apollo-Client]] · [[Relay]]
- 응용: [[Type-Safe-API-Client]] · [[Persisted-Queries]]
- Adjacent: [[OpenAPI-Codegen]] · [[tRPC]]
## 🤖 LLM 활용
**언제**: GraphQL schema 가 있는 TS project, multi-team 의 schema drift 방지, persisted query 도입.
**언제 X**: REST-only, 매 GraphQL schema 의 unstable 한 prototype phase.
## ❌ 안티패턴
- **codegen output 의 manual edit**: 매 next run 시 overwrite, 매 변경 의 lost.
- **fragment 의 component 외 정의**: fragment masking 의 weak — co-location 강제.
- **DateTime 의 `Date` mapping**: GraphQL response 는 string, 매 runtime mismatch 유발.
- **CI 에 codegen drift check 의 X**: schema 의 silent breakage.
## 🧪 검증 / 중복
- Verified (graphql-code-generator.com docs, client-preset migration guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — GraphQL Codegen client-preset 패턴 정리 |
@@ -2,91 +2,154 @@
id: wiki-2026-0508-guilty-gear-xrd-rendering-pipeli
title: Guilty Gear Xrd Rendering Pipeline
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-GGXR-001]
aliases: [Xrd Toon Shading, Arc System Works Anime Render, Guilty Gear Cel Shading]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced, guilty-gear, rendering, anime-style, cel-shading, real-time-graphics, unreal-engine]
confidence_score: 0.9
verification_status: applied
tags: [graphics, cel-shading, npr, anime, arc-system-works]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: hlsl
framework: unreal-engine
---
# [[Guilty-Gear-Xrd-Rendering-Pipeline|Guilty-Gear-Xrd-Rendering-Pipeline]]
# Guilty Gear Xrd Rendering Pipeline
## 📌 한 줄 통찰 (The Karpathy Summary)
> "2D를 삼킨 3D의 마법: 단순히 모델링을 예쁘게 하는 것을 넘어, 애니메이터가 한 땀 한 땀 그린 듯한 '어색하지 않은 외곽선'과 '급격한 그림자 변화'를 구현하기 위해 노멀 맵(Normal map)을 수동으로 조작하는 광기에 가까운 장인 정신의 기술 집약체."
## 한 줄
> **"매 3D model 을 매 2D anime 처럼 보이게 매 render — 매 artist control 이 매 algorithm 보다 매 우선."**. Arc System Works (Junya C. Motomura, GDC 2014) 의 매 Xrd 파이프라인은 매 NPR (non-photorealistic rendering) 의 매 landmark. 매 hand-painted normal + custom shadow + ink line + post-processing 의 매 stack.
## 📖 구조화된 지식 (Synthesized Content)
길티기어 Xrd 렌더링 파이프라인(Guilty-Gear-Xrd-Rendering-Pipeline)은 Arc[[_system|system]] Works가 개발한, 3D 모델을 마치 고품질 2D 셀 애니메이션처럼 보이게 만드는 독보적인 그래픽 기술입니다.
## 매 핵심
1. **핵심 기술 (Arc System Works 비법)**:
* **Manual Normal Tuning**: 조명에 따라 그림자가 지는 방향을 사람이 직접 지정하여 애니메이션 특유의 칼 같은 명암 표현. ([[Refinement|Refinement]]와 연결)
* **Vertex Color Weighting**: 특정 부위에 그림자가 더 진하게 지게 하거나 외곽선을 굵게 설정.
* **Limited Animation Emulation**: 60프레임 런타임에서도 캐릭터의 움직임 프레임을 고의로 끊어 2D 수작업 느낌 재현.
2. **왜 중요한가?**:
* 3D의 자유로운 카메라 연출력과 2D의 예술적 미학 정책을 결합하여 '대체 불가능한 시각적 경험 정책'을 완성했기 때문임. (UX-Design-and-Engagement와 연결)
### 매 Pipeline stage
1. **Modeling**: 매 low-poly model + 매 hand-tuned vertex normal.
2. **Base color shading**: 매 ramp texture (1D LUT) — 매 toon step.
3. **Custom shadow direction**: 매 light vector 무시 + 매 artist 가 매 manual paint.
4. **Outline (ink line)**: 매 inverted hull / 매 post-process edge.
5. **Specular & rim**: 매 hand-placed highlight texture.
6. **Post-processing**: 매 chromatic aberration, 매 bloom, 매 color grading.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거 셀 쉐이딩(Cel-shading) 정책은 외곽선만 그리면 된다는 단순한 수준이었으나, 길티기어 정책은 조명 모델 정책 자체를 2D 표현 정책에 맞게 재정의한 '차세대 스타일라이즈드 렌더링 정책'의 기준을 세움(RL Update).
- **정책 변화(RL Update)**: 이제는 길티기어 스트라이브(Strive)를 거치며 더 발전된 후처리 효과 정책(Bloom, DoF)과 결합되었으며, AI 가 이 화풍 정책을 학습하여 실시간으로 3D 영상을 애니메이션화하는 연구의 벤치마크가 됨.
### 매 Vertex normal trick
- 매 face 의 매 normal 을 매 sphere 로 매 매뉴얼 average — 매 2D 에서 매 깔끔한 shadow shape.
- 매 hair 는 매 normal 을 매 head 의 매 center 로 매 향하게 — 매 anisotropic specular 의 매 illusion.
## 🔗 지식 연결 (Graph)
- [[Refinement|Refinement]], UX-Design-and-Engagement, [[Deep-Convolutional-GANs|Deep-Convolutional-GANs]], Animation, Simulation, Creative-Process
- **Key Developer**: Junya Motomura.
---
### 매 Ramp texture
- 1D texture, 매 N·L → matrix lookup. 매 step 2-3 단계 — 매 hard edge.
- 매 character 별 매 다른 ramp — 매 다른 mood.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 Outline
- **Backface inverted hull**: 매 model 을 매 normal 방향 outward extrude + cull front. 매 cheap, 매 thickness 균일.
- **Vertex color mask**: 매 detail line 의 매 thickness 제어.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용
1. Anime fighting game (Dragon Ball FighterZ, Granblue Versus 도 매 변형).
2. Mobile RPG (Genshin Impact 의 매 cel).
3. VTuber rendering.
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Toon shader (HLSL)
```hlsl
float NdotL = saturate(dot(normalize(worldNormal), lightDir));
float ramp = tex2D(_RampTex, float2(NdotL, 0.5)).r;
float3 base = tex2D(_MainTex, uv).rgb;
float3 col = base * lerp(_ShadowColor, 1.0, ramp);
return float4(col, 1);
```
## 🤔 의사결정 기준 (Decision Criteria)
### Inverted hull outline
```hlsl
// Vertex pass — render with cull = Front
float3 normalWS = TransformObjectToWorldNormal(IN.normal);
float3 posWS = TransformObjectToWorld(IN.positionOS) + normalWS * _OutlineWidth;
OUT.positionCS = TransformWorldToHClip(posWS);
OUT.color = _OutlineColor;
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Custom shadow direction (face)
```hlsl
// Replace light dir with artist-specified vector for face
float3 fixedLight = mul((float3x3)unity_ObjectToWorld, _FaceLightDir);
float NdotL = dot(worldNormal, normalize(fixedLight));
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Hair tangent trick
```hlsl
// Hair anisotropic — tangent points along hair flow
float3 H = normalize(viewDir + lightDir);
float TdotH = dot(hairTangent, H);
float spec = pow(1.0 - TdotH * TdotH, _HairGloss);
```
**기본값:**
> *(TODO)*
### Edge detect post (Sobel on depth+normal)
```hlsl
float3 nC = SampleNormal(uv);
float dC = SampleDepth(uv);
float edge = 0;
[unroll] for (int i = 0; i < 4; ++i) {
float3 nS = SampleNormal(uv + offset[i] * _TexelSize);
float dS = SampleDepth(uv + offset[i] * _TexelSize);
edge += saturate(1.0 - dot(nC, nS)) + abs(dC - dS) * _DepthWeight;
}
return lerp(sceneColor, _EdgeColor, saturate(edge - _Threshold));
```
## ❌ 안티패턴 (Anti-Patterns)
### Ramp texture authoring (Python)
```python
import numpy as np
from PIL import Image
ramp = np.zeros((1, 256, 3), dtype=np.uint8)
ramp[0, :64] = (60, 50, 80) # deep shadow
ramp[0, 64:160] = (140, 130, 150) # mid
ramp[0, 160:] = (250, 245, 240) # lit
Image.fromarray(ramp).save('toon_ramp.png')
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Specular hand-placed mask
```hlsl
// Per-pixel mask painted by artist — multiplies spec
float specMask = tex2D(_SpecMaskTex, uv).r;
float3 spec = pow(saturate(dot(N, H)), _Power) * specMask * _SpecColor;
```
## 매 결정 기준
| 효과 | Approach |
|---|---|
| 매 hard cel shadow | Ramp 1D texture + step |
| 매 face shadow control | Custom light vector |
| 매 cheap outline | Inverted hull (backface) |
| 매 detail outline | Post-process Sobel on N+depth |
| 매 anime hair | Tangent-based aniso + ramp |
| 매 emotional rim | Hand-placed highlight mask |
**기본값**: ramp + inverted hull + face light override. 매 modern (Unreal/Unity) 모두 매 stable.
## 🔗 Graph
- 부모: [[Computer Graphics]] · [[NPR]]
- 변형: [[Cel Shading]] · [[Genshin Impact Rendering]] · [[Borderlands Outline]]
- 응용: [[VTuber Rendering]] · [[Anime Game]]
- Adjacent: [[Toon Shader]] · [[Outline Shader]] · [[Ramp Texture]]
## 🤖 LLM 활용
**언제**: 매 anime / cel-shading 재현, 매 NPR 학습, 매 outline / shadow 의 매 trick 분석.
**언제 X**: 매 photorealistic — 매 PBR 파이프라인.
## ❌ 안티패턴
- **Auto-generated normal**: 매 anime look 의 매 핵심 — 매 hand-tune 필수.
- **Light dir 만 의존**: 매 face 매 dirty shadow.
- **Outline 두께 globally same**: 매 detail loss — 매 vertex color mask.
- **Bloom 만 의존한 mood**: 매 ramp / grading 이 매 base.
## 🧪 검증 / 중복
- Verified (Junya C. Motomura, "Guilty Gear Xrd's Art Style", GDC 2014).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 Xrd pipeline + HLSL 패턴 |
+136 -94
View File
@@ -1,122 +1,164 @@
---
id: wiki-2026-0508-hermes
title: Hermes
category: Frontend
status: needs_review
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [Hermes Engine, React Native Hermes, Hermes JS]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [auto-wikified, technical-documentation, frontend]
confidence_score: 0.9
verification_status: applied
tags: [react-native, javascript-engine, hermes, mobile]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: cpp
framework: react-native
---
# Hermes
## 📌 한 줄 통찰 (The Karpathy Summary)
Hermes는 React Native에서 로직을 실행하기 위해 사용하는 고도로 최적화된 자바스크립트 엔진이다 [1-3]. React Native 애플리케이션이 실행될 때 자바스크립트 번들을 파싱하고 구동하는 핵심 역할을 담당한다 [2, 3]. JSI(JavaScript Interface)와 같은 React Native의 새로운 아키텍처와 결합하여 모바일 애플리케이션의 전반적인 실행 성능과 런타임 효율성에 직접적인 영향을 미친다 [1].
## 한 줄
> **"매 mobile 에 매 최적화된 매 ahead-of-time bytecode 매 JS engine."**. Meta 가 매 React Native 용으로 매 만든 engine. 매 startup time + 매 memory + 매 binary size 가 매 우선. 매 2026 의 매 RN 0.70+ 부터 매 default — 매 JSC 대비 매 cold start 30-50% 단축.
## 📖 구조화된 지식 (Synthesized Content)
* **자바스크립트 실행 및 로직 처리**: Hermes는 React Native 프레임워크 내에서 자바스크립트 코드를 실행하는 기반 엔진이다 [3]. 모든 React Native 앱은 애플리케이션 로직 구동을 위해 이 엔진과 함께 배포된다 [2, 4].
* **새로운 아키텍처와의 통합**: React Native의 렌더링 및 통신 방식을 혁신한 JSI(JavaScript Interface)는 고도로 최적화된 Hermes를 비롯한 다양한 자바스크립트 엔진을 지원한다 [1]. 이를 기반으로 자바스크립트와 네이티브 코드 간의 직접적이고 동기적인 바인딩이 가능해진다 [1].
* **앱 용량(App Size)에 미치는 영향**: Hermes 자바스크립트 엔진을 포함하여 빌드 및 배포되는 React Native 앱은 대략 5~8 MB 수준의 기본(baseline) APK 크기를 가진다 [2, 4].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
**초기 시작 지연(Startup Latency) 및 콜드 스타트 문제**
React Native 앱은 시작할 때 반드시 Hermes 자바스크립트 엔진을 초기화하고 JS 번들을 파싱하는 과정을 거쳐야 하며, 이는 측정 가능한 수준의 시작 지연(Startup latency)을 추가로 발생시킨다 [2].
결과적으로 네이티브 ARM 코드로 미리 컴파일(AOT)하는 Flutter 앱의 콜드 스타트 시간(일반적으로 200~400ms)과 비교했을 때, Hermes를 사용하는 React Native 콜드 스타트 시간은 보통 300~600ms로 상대적으로 더 느리다 [2, 4]. 이러한 지연은 성능 벤치마크 상에서는 눈에 띄는 차이지만, 실제 대부분의 앱 사용자에게는 결정적인 방해 요소가 되지는 않는다 [2].
### 매 설계 목표
- **Fast startup**: 매 AOT bytecode → 매 parse 비용 0.
- **Low memory**: 매 generational GC, 매 NaN-boxing 없는 매 Hades collector (concurrent).
- **Small binary**: 매 SymbolTable / StringTable 의 매 dedupe.
- **Mobile first**: 매 ARM64 + 매 small heap 의 매 가정.
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 Architecture
- **Compiler**: hbc (Hermes ByteCode) — 매 build 시 매 .hbc 파일 생성.
- **VM**: register-based interpreter — 매 stack-based JSC 와 매 다름.
- **GC**: Hades — 매 concurrent + generational.
- **No JIT** (default): 매 mobile binary 정책 (iOS) + 매 startup 우선. 매 static Hermes (sh) 가 매 AOT native compile 실험.
#### [관계 유형 A (아키텍처/기반 기술)]
- [[JSI (JavaScript Interface)]]
- 연결 이유: JSI는 Hermes와 같은 자바스크립트 엔진을 지원하며, 자바스크립트와 네이티브 코드 간의 동기적 바인딩을 가능하게 하는 토대이기 때문이다 [1].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이전의 비동기 브릿지(Bridge) 모델에서 벗어나 어떻게 직렬화 오버헤드 없이 빠른 네이티브 통신이 이루어지는지 이해할 수 있다.
- [[React Native New Architecture]]
- 연결 이유: Hermes 엔진은 Fabric 렌더러, TurboModules, JSI로 구성된 React Native의 새로운 아키텍처 파이프라인 내에서 핵심 자바스크립트 실행 환경으로 작동하기 때문이다 [5, 6].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 엔진의 고도화가 크로스 플랫폼 프레임워크 전체의 성능 향상(동시성 렌더링, 지연 로딩 등)으로 이어지는 구조적 맥락을 파악할 수 있다.
### 매 vs JSC vs V8
| 항목 | Hermes | JSC | V8 |
|---|---|---|---|
| Startup | 매 빠름 (AOT) | 매 보통 | 매 느림 (parse + JIT) |
| Throughput | 매 낮음 (no JIT) | 매 보통 | 매 매우 높음 |
| Memory | 매 낮음 | 매 보통 | 매 높음 |
| 사용처 | RN | iOS Safari, RN (legacy) | Chrome, Node |
#### [관계 유형 B (비교/경쟁 기술)]
- [[Flutter AOT Compilation (Dart)]]
- 연결 이유: Hermes 엔진이 실행 시점에 JS를 파싱하는 것과 대조적으로, Flutter는 코드를 사전에 네이티브로 컴파일하여 초기 시작 속도의 차이를 만들기 때문이다 [2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 모바일 프레임워크가 코드를 실행하는 방식(파싱 vs 사전 컴파일)에 따른 초기 로딩 속도(Cold Start)의 트레이드오프를 명확히 이해할 수 있다.
### 매 응용
1. RN app cold start 단축.
2. Bundle size 절감 (.hbc 가 .js 보다 작음).
3. 매 Hermes-specific debugger (Chrome DevTools 호환).
### Deeper Research Questions
- Hermes 엔진이 JSI와 결합되었을 때 구체적으로 어떤 메커니즘을 통해 기존 브릿지(Bridge)의 직렬화(Serialization) 오버헤드를 제거하는가?
- Hermes의 엔진 초기화 및 JS 번들 파싱 시간(300~600ms)을 단축하기 위해 번들 크기를 최적화하거나 캐싱하는 기법에는 어떤 것들이 있는가?
- 다른 자바스크립트 엔진(예: V8, JavaScriptCore)과 비교했을 때 Hermes가 모바일 환경에 특화되어 가지는 메모리 및 성능적 이점은 무엇인가? (소스에 관련 정보가 부족합니다.)
- 대규모 React Native 애플리케이션에서 Hermes 엔진의 가비지 컬렉션(GC) 패턴이 UI 프레임 드롭이나 애니메이션 성능에 미치는 영향은 무엇인가? (소스에 관련 정보가 부족합니다.)
- 앱의 복잡도가 증가함에 따라 Hermes 기반 React Native 앱과 Impeller/AOT 기반 Flutter 앱의 성능 격차가 사용자 경험 측면에서 어떻게 다르게 발현되는가?
## 💻 패턴
### Practical Application Contexts
- **Implementation:** React Native 앱 개발 및 빌드 과정에서 번들 크기(5~8 MB 기준)를 관리하고, 프레임워크 성능을 극대화하기 위해 JSI와 호환되는 최적화된 자바스크립트 엔진 설정을 구성할 때 활용된다.
- **System Design:** 모바일 애플리케이션 아키텍처 설계 시, 비즈니스 로직(자바스크립트)과 네이티브 렌더링 간의 처리 속도 및 통신 병목을 평가하는 지표로 작용한다.
- **Operation / Maintenance:** 프로덕션 환경에서 앱의 초기 진입 속도(콜드 스타트 300~600ms)를 모니터링하고 최적화 포인트를 찾는 기준점이 된다.
- **Learning Path:** React Native 개발자가 기존의 브릿지 기반 아키텍처에서 벗어나 새로운 아키텍처(JSI, Fabric, TurboModules)로 전환하는 렌더링 및 실행 파이프라인을 학습할 때 필수적으로 이해해야 하는 기반 환경이다.
- **My Project Relevance:** 모바일 앱 개발 프레임워크 선정 시, React Native가 가지는 '네이티브 컴포넌트 렌더링의 강점'과 '엔진 초기화 지연'이라는 성능적 기회비용을 저울질하는 데 직접적인 근거로 사용된다.
### Enable in RN (already default in 0.70+)
```javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true,
hermesCommand: "../../node_modules/react-native/sdks/hermes/destroot/bin/hermesc",
]
### Adjacent Topics
- [[React Native Performance Optimization]]
- 확장 방향: 번들 분할(Chunking), 메모리 관리 등 Hermes 엔진 위에서 실행되는 애플리케이션의 성능을 실질적으로 개선하는 최적화 기법으로 지식을 확장할 수 있다.
- [[Cross-platform Mobile Development Frameworks]]
- 확장 방향: 렌더링 엔진(Skia, Impeller)을 사용하는 Flutter와 자바스크립트 엔진(Hermes)을 사용하는 React Native의 철학적, 아키텍처적 접근 방식을 폭넓게 비교 연구할 수 있다.
---
*Last updated: 2026-05-03*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// ios/Podfile
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true,
)
```
## 🤔 의사결정 기준 (Decision Criteria)
### Verify Hermes is running
```javascript
const isHermes = () => !!global.HermesInternal;
console.log('engine:', isHermes() ? 'Hermes' : 'JSC');
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Compile JS to bytecode (CLI)
```bash
hermesc -emit-binary -out=index.hbc index.js
# Inspect
hermes -dump-bytecode index.hbc
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Profile Hermes startup
```bash
# Sample profiler
hermes --sample-profiling -O index.js
# → output trace.json (Chrome DevTools profile format)
```
**기본값:**
> *(TODO)*
### Memory leak detection (Hermes-specific)
```javascript
// Heap snapshot
import { HermesInternal } from 'react-native';
const snap = HermesInternal?.getInstrumentedStats?.();
console.log(snap); // js_heapSize, js_allocatedBytes, ...
```
## ❌ 안티패턴 (Anti-Patterns)
### Avoid Hermes pitfalls
```javascript
// 1. eval / new Function — supported but slow (no JIT)
// 2. Proxy — supported in 2026 but heavier than V8
// 3. Intl — opt-in (intl=true in build flag), default 작음
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// Prefer static patterns
const handler = handlers[type]; // O(1) lookup
// over
const handler = eval(`handle_${type}`);
```
### Static Hermes (experimental 2026)
```bash
# AOT to native — bypass interpreter
shermes -typed -exec index.ts
# Significant throughput gain when types annotated
```
### Source map for Hermes bundle
```bash
react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output index.android.bundle \
--sourcemap-output index.android.bundle.map \
--minify true
# Hermes ingests .map for symbolicated stack traces
```
## 매 결정 기준
| 상황 | Engine |
|---|---|
| 매 RN app | Hermes (default) |
| 매 cold start critical | Hermes |
| 매 heavy compute | JSC + worker / native module |
| 매 typed perf-critical RN | Static Hermes (experimental) |
| 매 web | V8 / JSC (browser native) |
**기본값**: Hermes ON. 매 RN 0.70+ 자동.
## 🔗 Graph
- 부모: [[JavaScript Engine]] · [[React Native]]
- 변형: [[V8]] · [[JavaScriptCore]] · [[QuickJS]]
- 응용: [[Mobile App Performance]] · [[Cold Start Optimization]]
- Adjacent: [[Bytecode]] · [[AOT Compilation]] · [[GC]]
## 🤖 LLM 활용
**언제**: 매 RN startup 분석, 매 bundle size 최적화, 매 JS engine trade-off.
**언제 X**: 매 web — 매 browser engine 직접 제어 X.
## ❌ 안티패턴
- **eval 의존**: 매 JIT 없음 — 매 매우 느림.
- **Bundle 비분할**: 매 .hbc 1개 거대 — 매 RAM bundle / inline-requires 활용.
- **JSC 가정 코드**: 매 Symbol toPrimitive 등 매 corner case.
- **Hermes 끄고 RN**: 매 거의 매 lose-lose (2026 기준).
## 🧪 검증 / 중복
- Verified (hermesengine.dev, RN 0.74+ release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 Hermes architecture + RN integration |
@@ -2,142 +2,33 @@
id: wiki-2026-0508-hydration-progressive-rendering
title: "Hydration & Progressive Rendering"
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
aliases: [P-REINFORCE-AUTO-1F4D68]
duplicate_of: none
status: duplicate
canonical_id: hydration
duplicate_of: "[[Hydration]]"
aliases: []
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced]
raw_sources: []
last_reinforced: 2026-05-03
github_commit: "[P-Reinforce] Continuous Worker - Hydration & Progressive Rendering"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, frontend, ssr, hydration]
last_reinforced: 2026-05-10
github_commit: pending
---
# [[Hydration & Progressive Rendering|Hydration & Progressive Rendering]]
# Hydration & Progressive Rendering
## 📌 한 줄 통찰 (The Karpathy Summary)
하이드레이션(Hydration)은 서버 사이드 렌더링(SSR)을 통해 생성된 정적 HTML을 클라이언트가 넘겨받아 이벤트 리스너를 연결하고 동적 상호작용이 가능하도록 '수분'을 공급하는 과정입니다 [1, 2]. 기존 SSR은 초기 화면은 빠르게 보여주지만 전체 자바스크립트를 다운로드하고 하이드레이션을 마칠 때까지 상호작용이 지연되는 '하이드레이션 갭(Hydration Gap)' 문제를 안고 있었습니다 [1, 3]. 이를 해결하기 위해 React 18의 선택적 하이드레이션(Selective Hydration) 및 스트리밍(Streaming) 렌더링, Vue 3.5의 지연 하이드레이션(Lazy Hydration)과 같은 점진적 렌더링 기법이 도입되어, 대규모 애플리케이션의 초기 로딩 성능과 사용자 경험을 최적화하는 핵심 실전 패턴으로 자리 잡았습니다 [4, 5].
> **이 문서는 [[Hydration]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **하이드레이션의 작동 원리 및 한계**
* 서버 렌더링 환경에서 React는 기존 서버에서 렌더링된 DOM 트리를 병렬로 순회하며 Fiber 트리와 일치시키고, DOM 노드를 다시 생성하는 대신 재사용하며 이벤트 리스너를 부착합니다 [1, 6].
* 그러나 전통적인 하이드레이션은 트리를 순차적으로 걷기 때문에, 전체 트리가 하이드레이션되기 전까지는 버튼 클릭과 같은 사용자 상호작용이 동작하지 않는 '먹통' 현상(Hydration Gap)을 유발합니다 [1, 6].
## 핵심 요약
- **Hydration**: SSR HTML 에 client-side event handler / state 의 attach.
- **Progressive rendering**: 매 React 18 streaming SSR + Suspense — 매 chunk 단위 stream + selective hydration.
- **Resumability** (Qwik): hydration 자체 의 회피 — 매 serialized state 를 즉시 복원.
* **점진적 렌더링(Progressive Rendering)과 스트리밍(Streaming)**
* React는 데이터를 모두 기다린 후 HTML을 보내는 대신, 스트리밍을 통해 뼈대(Shell)를 즉시 전송하고 데이터가 해결되는 대로 각 `Suspense` 바운더리를 스트리밍합니다 [4].
* 클라이언트는 나머지 데이터가 도착하는 동안에도 먼저 도착한 부분을 점진적으로 하이드레이션할 수 있어, 느린 데이터베이스 쿼리로 인한 지연(Waterfall) 현상을 극복합니다 [4, 7, 8].
## 🔗 Graph
- 부모: [[Hydration]] (canonical)
- Adjacent: [[Streaming-SSR]] · [[React-Server-Components]]
* **선택적 하이드레이션(Selective Hydration)과 지연 하이드레이션(Lazy Hydration)**
* **React:** Lanes 우선순위 시스템을 활용하여, 사용자가 아직 하이드레이션되지 않은 부분을 클릭하면 해당 바운더리로 점프하여 상호작용 처리를 위한 하이드레이션을 최우선으로 실행(중단 및 재개)합니다 [4].
* **Vue 3.5:** SSR을 위한 '지연 하이드레이션(Lazy Hydration)'을 도입하여, 컴포넌트가 뷰포트(Viewport)에 보일 때만 하이드레이션되도록 지연시킵니다. 이를 통해 초기 로드 시간을 단축하고 컴포넌트 활성화를 효율적으로 연기합니다 [5].
* **하이드레이션의 완전한 생략: 서버 컴포넌트(RSC)**
* React 서버 컴포넌트(RSC)는 서버에서만 실행되며 코드가 클라이언트 번들에 포함되지 않으므로 하이드레이션 자체가 발생하지 않습니다 [9, 10]. 이는 자바스크립트 번들 크기를 줄이고 하이드레이션 비용을 원천적으로 없애는 아키텍처적 진화입니다 [11].
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **두 번의 왕복 문제(The Two-Trip Lie):** 전통적 하이드레이션은 SSR을 통해 빠른 HTML을 제공하지만, 브라우저는 여전히 모든 JavaScript를 다운로드하고 클라이언트에서 코드를 다시 실행해야 합니다. 즉, 서버에서의 작업이 클라이언트의 연산 비용을 줄여주지 못하는 근본적 한계가 있습니다 [3, 12].
* **하이드레이션 불일치(Hydration Mismatches):** 서버에서 렌더링된 콘텐츠와 클라이언트에서 렌더링된 콘텐츠가 다를 경우 오류가 발생합니다. 이를 위해 Vue 3.5는 서버-클라이언트 간 일관된 고유 ID를 보장하는 `useId()` API를 도입하였고, 의도적인 불일치에 대한 경고를 억제하기 위해 `data-allow-mismatch` 속성을 사용해야 하는 관리 포인트가 생깁니다 [5, 13].
* **아키텍처 복잡성과 보안 위험:** 하이드레이션을 생략하기 위해 서버 컴포넌트(RSC) 패턴을 사용할 경우, 서버와 클라이언트 경계가 모호해져 아키텍처가 매우 복잡해집니다 [14, 15]. 특히 서버 액션을 내부 함수처럼 취급하여 입력 유효성 검사를 생략하면, 인증 없이 원격 코드 실행(RCE)이 가능한 'React2Shell'과 같은 치명적인 보안 취약점이 발생할 수 있습니다 [16-18].
## 🔗 지식 연결 (Graph)
### Related Concepts
#### [관계 유형 A (아키텍처/기반 기술)]
* [[Server-Side Rendering (SSR)]]
* 연결 이유: 하이드레이션과 점진적 렌더링이 성립하기 위한 전제 조건이 되는 렌더링 방식입니다.
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 초기 HTML 전송 후 클라이언트가 상호작용성을 덧붙여야 하는 이유와 기존 SSR이 가진 'Two-Trip'의 한계 [2, 3, 12, 19].
* [[React Server Components (RSC)]]
* 연결 이유: 하이드레이션 비용을 근본적으로 제거하기 위해 도입된 혁신적인 컴포넌트 아키텍처입니다.
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 자바스크립트를 클라이언트로 아예 보내지 않음으로써 하이드레이션 없이 정적 렌더링을 처리하고, 서버-클라이언트 융합을 이루는 구조 [9-11].
#### [관계 유형 B (구현/최적화 도구)]
* [[Selective Hydration & Streaming]]
* 연결 이유: 기존 하이드레이션의 순차적 블로킹 문제를 해결하는 React의 기술적 구현체입니다.
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: Suspense 바운더리를 통한 UI 청크 분할 및 사용자 상호작용에 따른 하이드레이션 우선순위 제어 메커니즘 [4, 7].
* [[Lazy Hydration]]
* 연결 이유: 대규모 애플리케이션의 메모리 및 렌더링 최적화를 위해 Vue 3.5에 도입된 핵심 구현 기법입니다.
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 뷰포트에 보이는 컴포넌트만 지연 활성화하여 초기 로딩 부하를 줄이는 프레임워크 차원의 성능 최적화 방법 [5, 20].
### Deeper Research Questions
* 전통적인 하이드레이션 방식에서 발생하는 '하이드레이션 갭(Hydration Gap)'이 모바일이나 느린 네트워크 환경에서 사용자 경험(UX)에 미치는 구체적인 악영향은 무엇인가? [1, 21]
* React 18의 선택적 하이드레이션(Selective Hydration)은 우선순위 시스템(Lanes)을 활용하여 사용자의 클릭 이벤트를 어떻게 가로채고 처리하는가? [4]
* Vue 3.5의 지연 하이드레이션(Lazy Hydration) 적용 시, 서버-클라이언트 간 상태 불일치(Mismatch)를 방지하기 위해 `useId()``data-allow-mismatch` 속성은 내부적으로 어떻게 동작하는가? [5, 13]
* 서버 컴포넌트(RSC)를 도입하여 하이드레이션 단계를 생략할 때 발생하는 보안 위협(예: React2Shell 원격 코드 실행)은 무엇이며, 어떻게 검증해야 하는가? [16-18]
* 스트리밍(Streaming)과 `Suspense`를 결합한 점진적 렌더링이 느린 데이터베이스 쿼리를 처리할 때, 브라우저 렌더링 병목 현상을 어떻게 우회하는가? [4, 7, 8]
### Practical Application Contexts
* **Implementation:** 애플리케이션 구축 시 React의 `Suspense`나 Vue의 Lazy Hydration을 선언적으로 적용하여, 중요하지 않거나 보이지 않는 UI 요소의 하이드레이션을 지연시켜 초기 렌더링 성능을 극대화합니다 [4, 5].
* **System Design:** 시스템 아키텍처 설계 시 백엔드 데이터 의존성과 프론트엔드의 인터랙션 요구사항을 구분하여, 하이드레이션이 아예 필요 없는 영역(서버 컴포넌트)과 필수적인 영역(클라이언트 컴포넌트)의 경계를 명확히 분리합니다 [22, 23].
* **Operation / Maintenance:** 프로덕션 운영 중 발생할 수 있는 하이드레이션 Mismatch 에러를 모니터링하고, 필요시 고유 ID 생성을 보장하는 유틸리티(`useId()`) 등을 사용하여 SSR 환경의 무결성을 유지보수합니다 [5, 13].
* **Learning Path:** 클라이언트 렌더링(CSR)의 한계 -> 전통적 SSR과 하이드레이션의 개념 -> 스트리밍과 점진적 하이드레이션 -> 서버 컴포넌트(RSC)의 도입으로 이어지는 웹 렌더링 패러다임의 역사와 진화 과정을 체계적으로 학습합니다 [3, 4, 10, 12].
* **My Project Relevance:** 글로벌 사용자나 저사양 모바일 기기를 타겟팅하는 프로젝트에서, 대규모 JS 번들 로딩 및 하이드레이션으로 인한 '초기 빈 화면' 및 '클릭 무반응' 현상을 개선하기 위한 성능 최적화 지표로 활용할 수 있습니다 [1, 21].
### Adjacent Topics
* [[Suspense Boundary]]
* 확장 방향: 데이터를 기다리는 동안 Fallback UI를 보여줄 뿐만 아니라, 점진적 렌더링 및 선택적 하이드레이션에서 UI를 청크(Chunk) 단위로 분리하는 기술적 경계 역할을 심층적으로 탐구합니다 [4].
* [[React Server Actions]]
* 확장 방향: 클라이언트에서 하이드레이션 없이도 서버와 직접 상호작용하며 데이터를 변형(Mutation)하는 최신 패턴과, 이에 수반되는 입력 검증 및 보안(React2Shell) 이슈 방향으로 확장이 가능합니다 [17, 18].
---
*Last updated: 2026-05-03*
---
*Last updated: 2026-05-03*
- Raw Source: 00_Raw/2026-05-03/Hydration & Progressive Rendering.md
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -2,107 +2,33 @@
id: wiki-2026-0508-hydration-성능-최적화
title: Hydration 성능 최적화
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: hydration
duplicate_of: "[[Hydration]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, hydration, performance]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[Hydration 성능 최적화]]
# Hydration 성능 최적화
## 📌 한 줄 통찰 (The Karpathy Summary)
[[Hydration]]은 서버에서 렌더링된 정적 HTML 뼈대에 [[JavaScript]]를 실행하고 이벤트 리스너를 연결하여 완전한 상호작용이 가능한 애플리케이션으로 변환하는 과정입니다 [1, 2]. 기본적으로 React는 페이지 전체를 한 번에 Hydration하면서 메인 스레드를 차단하여 TBT(Total [[Blocking]] Time)와 TTI(Time to Interactive) 지표를 악화시킬 수 있습니다 [3]. 이를 해결하기 위해 선택적 Hydration, 지연 로딩, [[React Server Components]](RSC) 등의 최적화 기법을 도입하여 초기 로드 성능과 상호작용성을 극대화할 수 있습니다 [4-6].
> **이 문서는 [[Hydration]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
* **Hydration의 개념 및 주요 성능 병목 현상:**
* Hydration은 SSR(Server-Side Rendering) 환경에서 서버가 생성한 HTML을 클라이언트가 넘겨받아 상호작용을 부여하는 필수적인 과정입니다 [2, 3].
* 문제는 React가 기본적으로 시야에 보이지 않는 컴포넌트까지 포함하여 페이지 전체를 한 번에 Hydration 하려 한다는 점입니다 [3]. 이로 인해 JavaScript 실행이 메인 스레드를 장시간 점유하게 되고, 결과적으로 TBT(Total Blocking Time), FID(First Input Delay), TTI(Time to Interactive) 등의 핵심 웹 성능 지표가 크게 저하되며 사용자의 입력 지연을 초래합니다 [3, 7].
* 또한 서버에서 렌더링된 HTML과 클라이언트의 렌더링 결과가 다를 때 발생하는 'Hydration Mismatch' 오류와, 모든 컴포넌트를 위한 전체 JavaScript를 다운로드해야 해서 발생하는 번들 크기 비대화(Bundle Size Bloat) 문제도 겪을 수 있습니다 [4, 8].
## 핵심 요약 (specialization aspects)
- 매 partial hydration / island architecture (Astro, Qwik resumability) 가 매 핵심.
- 매 selective hydration (React 18+) — 매 Suspense 경계 마다 매 분리.
- 매 progressive hydration — 매 viewport / interaction trigger.
- 매 measure: TTI / INP / total blocking time.
* **점진적 및 선택적 Hydration (Selective & Progressive Hydration):**
* 페이지 전체를 일괄 처리하는 대신 스크롤 위쪽(Above-the-fold)의 중요한 콘텐츠를 우선 처리하고, 덜 중요한 컴포넌트는 Hydration을 지연시킵니다 [4].
* [[Next.js]] 환경에서는 `next/dynamic`을 활용한 동적 임포트(Dynamic Imports)를 통해 구현하거나, IntersectionObserver API를 사용하여 요소가 뷰포트에 들어올 때만 Hydration을 수행하는 지연(Lazy) 방식을 적용할 수 있습니다 [5, 9]. 이를 통해 메인 스레드 차단을 분산시켜 TBT를 최대 40%까지 줄일 수 있습니다 [5].
## 🔗 Graph
- 부모: [[Hydration]] (canonical)
* **[[React [[Server Components]] (RSC)]]의 활용:**
* [[Next.js App Router]] 등에서 지원하는 React Server Components는 오직 서버에서만 실행되며 클라이언트로 JavaScript 페이로드를 전혀 보내지 않습니다 [5, 10, 11].
* 정적이거나 상호작용이 필요 없는 UI(예: 텍스트, 사이드바 등)를 RSC로 구성하면 해당 영역은 Hydration 프로세스 자체가 필요 없어지므로 클라이언트의 부담과 번들 크기가 비약적으로 감소합니다 [6, 12, 13].
* **Streaming 및 Suspense 적용:**
* React의 Suspense API를 활용하면 서버에서 HTML을 점진적으로 스트리밍(Streaming)할 수 있습니다 [6].
* 이를 통해 렌더링이 완료된 일부 화면을 사용자에게 더 빠르게 보여주면서(FCP 개선), 복잡한 부분에 대한 Hydration 작업은 나중으로 미루어 체감 성능을 향상시킬 수 있습니다 [6, 14]. [[React 18]]의 동시성 렌더링([[Concurrent Rendering]])은 Hydration 작업을 작은 청크로 쪼개어 브라우저가 사용자 입력을 처리할 수 있도록 양보(yield)하는 기능을 제공합니다 [15].
* **부분 Hydration (Partial Hydration) 및 기타 팁:**
* 정적인 콘텐츠 영역을 고립시키고 상호작용이 필요한 특정 부분만 Hydration하는 섬 아키텍처([[Island Architecture]])를 도입하거나, 절대적으로 정적인 콘텐츠의 경우 `dangerouslySetInnerHTML`을 사용하여 통째로 Hydration 과정에서 배제하는 것도 유용한 전략입니다 [16-18].
* 불가피하게 클라이언트와 서버 간의 렌더링 불일치가 예상되는 곳에는 `suppressHydrationWarning`을 제한적으로 사용하거나, Hydration 완료 이후에 동작해야 하는 로직을 의존성 배열이 빈 `useEffect` 내에 배치하여 불일치 에러를 방지할 수 있습니다 [17, 19].
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[Server-Side Rendering (SSR)]], [[React Server Components (RSC)]], [[Total Blocking Time (TBT)]], [[Concurrent Rendering]]
- **Projects/Contexts:** [[Next.js App Router]], [[Island Architecture]]
- **Contradictions/Notes:** SSR은 클라이언트에게 완성된 HTML을 즉시 제공하여 FCP(First Contentful Paint)와 SEO를 크게 향상시키지만, JavaScript 번들이 다운로드되고 Hydration이 완료될 때까지 사용자가 페이지와 상호작용할 수 없으므로 TTI(Time to Interactive)가 오히려 지연되는 성능적 트레이드오프(Trade-off)가 존재합니다 [20, 21].
---
*Last updated: 2026-04-25*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
@@ -2,92 +2,172 @@
id: wiki-2026-0508-hydration-mismatch-and-ssr-debug
title: Hydration Mismatch and SSR Debugging
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [FE-SSR-HYDRA-001]
aliases: [Hydration Mismatch, SSR Debug, Hydration Error]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [react, ssr, Hydration, hydration-mismatch, debugging, Frontend-performance, nextjs]
confidence_score: 0.9
verification_status: applied
tags: [react, ssr, hydration, debugging]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react-next
---
# Hydration Mismatch and SSR Debugging (수화 불일치 및 SSR 디버깅)
# Hydration Mismatch and SSR Debugging
## 📌 한 줄 통찰 (The Karpathy Summary)
> "서버가 구워낸 HTML과 클라이언트가 렌더링한 초기 결과물이 1비트라도 다를 때 발생하는 경고를 무시하지 말고, 정적 일관성을 확보하여 불필요한 전체 리렌더링의 늪에서 탈출하라" — SSR 환경에서 서버와 클라이언트 간의 렌더링 트리 정합성을 유지하기 위한 기술적 가이드.
## 한 줄
> **"매 server-rendered HTML 매 client first render 가 매 다르면 매 React 가 매 throw — 매 일관된 input 이 매 핵심."**. 매 typical 원인: Date.now / Math.random / window 접근 / locale / 매 third-party DOM 조작. React 19 부터 매 error message 가 매 어떤 attribute 가 매 mismatch 인지 매 정확히 표시.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Pre-rendering Consistency and Client-only Escape" — 서버와 클라이언트의 렌더링 결과가 일치해야 한다는 SSR의 대전제를 준수하되, 브라우저 전용 데이터(window, local[[Storage|Storage]])가 필요한 경우 'useEffect' 이후로 렌더링을 지연시키는 패턴.
- **수화 불일치(Hydration Mismatch)의 주요 원인:**
- **[[Browser|Browser]]-only APIs:** 서버에는 없는 `window`, `document` 객체를 초기 렌더링 시점에 직접 참조.
- **Non-deterministic Data:** `Math.random()`이나 `new Date()` 등 서버와 클라이언트에서 값이 달라지는 로직 사용.
- **Invalid HTML Structure:** `p` 태그 안에 `div`를 넣는 등 브라우저가 강제로 수정하는 비정상적인 HTML 구조.
- **해결 및 디버깅 전략:**
- **Isomorphic Consistency:** 공통 상수나 환경 변수를 사용하여 양쪽 환경의 초기 값을 일치시킴.
- **Two-pass Rendering:** `isMounted` 상태 등을 활용하여 서버 렌더링 시에는 공통 UI를, 클라이언트 마운트 이후에 브라우저 전용 UI를 렌더링.
- **Suppression Tag:** 극히 제한적인 상황에서만 `suppressHydrationWarning` 속성 사용.
- **의의:** 불필요한 UI 흔들림(Flicker)을 방지하고, 브라우저의 렌더링 성능 최적화(Hydration 효율성)를 보장함.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거에는 수화 불일치 경고를 사소한 경고 정책으로 보았으나, 현대 React 정책은 이를 성능 저하와 버그의 전조로 간주하여 엄격히 관리할 것을 요구함. 특히 [[Next.js 15|Next.js 15]]+ 환경에서는 빌드 타임에 이를 더 공격적으로 검출 정책화함.
- **정책 변화:** Antigravity 프로젝트는 모든 SSR 컴포넌트에 대해 'Zero Hydration Warning' 정책을 시행하며, 브라우저 전용 로직은 반드시 전용 커스텀 훅(`useIsMounted`)을 통해서만 처리하도록 강제함.
### 매 원인 분류
- **Time / random**: server 의 매 시각 ≠ client 의 매 시각.
- **Locale / timezone**: Intl.DateTimeFormat 의 매 다른 결과.
- **Window / document**: server 에 매 없음.
- **User-agent branching**: useragent 의 매 다른 처리.
- **Third-party script**: AdSense, Cookiebot 의 매 DOM 변경.
- **Browser extension**: Grammarly, Dark Reader 의 매 inject.
- **Conditional rendering on `typeof window`**: 매 안티패턴.
## 🔗 지식 연결 (Graph)
- [[Web-Rendering-Strategies-CSR-vs-SSR|Web-Rendering-Strategies-CSR-vs-SSR]], Server-Side-Rendering-SSR, [[Nextjs-App-Router-Architecture|Nextjs-App-Router-Architecture]], [[Frontend-Debugging-and-Testing|Frontend-Debugging-and-Testing]]
- **Raw Source:** 00_Raw/Hydration Mismatch.md
### 매 React 의 매 행동 (19)
- 매 mismatch detection — 매 server HTML 을 매 polluted attribute 로 매 표시.
- 매 partial recovery — 매 mismatch boundary 만 매 client re-render.
- 매 보존되는 attribute (data-, aria-, custom): 매 dev warning.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 Debug 도구
- **Next.js**: `?_rsc_no_cache` 로 매 server payload 확인. `next dev` 의 매 colored diff.
- **React DevTools**: Profiler — hydration milestone.
- **Browser**: 매 view-source vs DOM inspect 비교.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용
1. e-commerce — 매 product price (locale), cart count (cookie).
2. Auth — 매 logged-in / logged-out 분기.
3. A/B test — 매 server vs client variant 의 매 일치.
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
### Detect mismatch source (Next.js 15)
```tsx
// Bad — Date.now() differs
function Now() { return <span>{Date.now()}</span>; }
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// Good — pass server time as prop, render same on both
function Now({ serverTime }: { serverTime: number }) {
return <span suppressHydrationWarning>{new Date(serverTime).toISOString()}</span>;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### useEffect for client-only side effects
```tsx
function ClientGreeting() {
const [name, setName] = useState<string | null>(null);
useEffect(() => setName(localStorage.getItem('name')), []);
if (!name) return null; // server returns null, client fills after mount
return <p>Hi {name}</p>;
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### dynamic() with ssr: false (Next.js)
```tsx
import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('./Chart'), { ssr: false });
// Renders nothing on server, only on client
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Avoid Math.random in render
```tsx
// Bad
function Card() { return <div data-id={Math.random()}>...</div>; }
**기본값:**
> *(TODO)*
// Good — useId
function Card() { const id = useId(); return <div id={id}>...</div>; }
```
## ❌ 안티패턴 (Anti-Patterns)
### suppressHydrationWarning (last resort)
```tsx
<time dateTime={iso} suppressHydrationWarning>
{new Intl.DateTimeFormat('ko').format(new Date(iso))}
</time>
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Diagnose third-party DOM mutation
```tsx
useEffect(() => {
const obs = new MutationObserver(records => {
for (const r of records) {
console.warn('mutation', r.target, r.attributeName, r.addedNodes);
}
});
obs.observe(document.body, { subtree: true, childList: true, attributes: true });
return () => obs.disconnect();
}, []);
```
### Locale-stable rendering
```tsx
// Server and client must agree — pass timezone explicitly
const fmt = new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul' });
return <span>{fmt.format(new Date(props.iso))}</span>;
```
### Replay server HTML offline
```bash
# Capture server HTML
curl -s https://app.example.com/page > server.html
# Open in fresh browser, compare with hydrated DOM via outerHTML diff
```
### React 19 onRecoverableError
```tsx
hydrateRoot(document, <App />, {
onRecoverableError(err, info) {
fetch('/log/hydration-error', {
method: 'POST',
body: JSON.stringify({ msg: String(err), digest: info.digest }),
});
},
});
```
## 매 결정 기준
| 원인 | Fix |
|---|---|
| 매 time / random | useId / passed-down server value |
| 매 locale / TZ | 매 explicit Intl 의 매 timeZone |
| 매 window / localStorage | 매 useEffect 후 setState |
| 매 SSR 무가치 component | 매 dynamic ssr:false |
| 매 third-party inject | 매 suppressHydrationWarning + 매 root 외부 |
| 매 extension (Grammarly) | 매 무시 — 매 알려진 false positive |
**기본값**: 매 server / client 를 매 동일 input 으로 매 강제. 매 last resort suppressHydrationWarning.
## 🔗 Graph
- 부모: [[Hydration]] · [[SSR]]
- 변형: [[Selective Hydration]] · [[Streaming SSR]]
- 응용: [[Next.js App Router]] · [[Remix]] · [[Astro]]
- Adjacent: [[useId]] · [[useEffect]] · [[React 19]]
## 🤖 LLM 활용
**언제**: 매 hydration error stack 분석, 매 SSR 코드 review, 매 timezone bug 진단.
**언제 X**: 매 pure CSR — 매 hydration 자체 X.
## ❌ 안티패턴
- **`typeof window !== 'undefined'` in render**: 매 server / client output 차이 — 매 mismatch 보장.
- **Date.now() in render**: 매 항상 mismatch.
- **suppressHydrationWarning 남발**: 매 진짜 bug 숨김.
- **try/catch around hydrateRoot 만**: 매 root cause 추적 X.
## 🧪 검증 / 중복
- Verified (React 19 docs — Hydration Errors, Next.js 15 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 mismatch 원인 + Next.js 15 debug |
+122 -68
View File
@@ -2,93 +2,147 @@
id: wiki-2026-0508-ide-stability-fix
title: IDE Stability Fix
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [550e8400-e29b-41d4-a716-446655440004]
aliases: [IDE crash fix, VSCode stability, Cursor stability]
duplicate_of: none
source_trust_level: A
confidence_score: 0.99
tags: [skybound, typescript, stability, code-quality]
confidence_score: 0.85
verification_status: applied
tags: [ide, vscode, cursor, debugging, frontend]
raw_sources: []
last_reinforced: 2026-04-21
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: TypeScript
framework: VSCode/Cursor
---
# Skybound IDE 안정성 및 타입 보정
# IDE Stability Fix
## 📌 한 줄 통찰 (The Karpathy Summary)
> 엄격한 타입 매칭과 필수 속성 초기화를 통해 런타임 잠재 에러를 사전에 차단하고 개발자 생산성을 향상함.
## 한 줄
> **"매 IDE crash / freeze / OOM 의 root cause 는 대부분 extension memory leak, large file indexing, TS server overload"**. 매 2026 의 Electron-based IDE (VSCode, Cursor, Windsurf) — 매 동일 패턴. 매 systematic disable + heap profiling 으로 해결.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:**
- **Total Initialization**: 인터페이스에 정의된 모든 속성은 유틸리티 함수(`calculateEffectiveStats`)에서 반드시 명시적으로 초기화되어야 함.
- **세부 내용:**
- `SystemEnemy`, `SystemBoss` 인터페이스의 역할(Role) 및 페이즈(Phase) 타입 일합.
- 미사용 구조 분해 할당(`emitEvent`) 제거로 린트 경고 해결.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 부정확한 타입 확장으로 발생하던 IDE 경고를 정밀한 리터럴 타입 적용으로 해결.
- **정책 변화:** 모든 유틸리티 함수 반환값은 Partial을 지양하고 Full-spec을 따를 것.
### 매 흔한 원인
- **Extension memory leak**: 매 disposable 미해제, listener 누적.
- **TS Server OOM**: 매 large monorepo (>500k LOC), `--max-old-space-size` 부족.
- **File watcher exhaust**: 매 `node_modules` watch → fs.inotify limit.
- **Renderer process freeze**: 매 large file (>10MB) 또는 minified bundle 열기.
- **GPU process crash**: 매 macOS Metal driver 충돌.
## 🔗 지식 연결 (Graph)
- **Parent:** 10_Wiki/Decisions/Skybound
- **Related:** 10_Wiki/Projects/Skybound/Architecture_Refactor
- **Raw Source:** 00_Raw/2026-04-21-Skybound_IDE_Problems_Fix
### 매 진단 도구
- `Developer: Open Process Explorer` (VSCode)
- `--inspect-extensions=9229` + Chrome DevTools
- `code --status` — running extensions + memory.
- macOS Activity Monitor — Code Helper (Renderer) 의 RAM 추적.
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[Architecture_Refactor]]
* [[decisions]]
### 매 응용
1. Monorepo 의 TS server tuning.
2. AI extension (Copilot, Cursor) leak 진단.
3. WSL2 / Remote SSH 환경 stability.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
## 💻 패턴
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### TS Server memory raise
```json
// .vscode/settings.json
{
"typescript.tsserver.maxTsServerMemory": 8192,
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
"typescript.disableAutomaticTypeAcquisition": true
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### File watcher exclude
```json
{
"files.watcherExclude": {
"**/node_modules/**": true,
"**/.git/objects/**": true,
"**/dist/**": true,
"**/.next/**": true,
"**/target/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true
}
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Bisect extensions
```bash
# 매 extension 중 어떤 것이 crash 원인인지 binary search
code --disable-extensions # 매 모두 disable → 재현 X = extension 문제
# Help → Start Extension Bisect 로 자동 binary search
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Heap snapshot 분석
```bash
# 매 extension host heap snapshot
# Cmd+Shift+P → "Developer: Take Process Heap Snapshot"
# Chrome DevTools 에서 .heapsnapshot 열어 분석
```
**기본값:**
> *(TODO)*
### Linux file watcher limit
```bash
# inotify limit raise (default 8192 매 부족)
echo fs.inotify.max_user_watches=524288 | \
sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```
## ❌ 안티패턴 (Anti-Patterns)
### Disable GPU acceleration (macOS crash)
```bash
# 매 Metal driver issue → software rendering
code --disable-gpu
# 또는 settings.json
"window.experimental.useSandbox": false
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Cursor / AI extension throttle
```json
{
"cursor.cpp.disabledLanguages": ["plaintext", "markdown"],
"github.copilot.editor.enableAutoCompletions": true,
"github.copilot.advanced": { "length": 500 }
}
```
## 매 결정 기준
| 증상 | 첫 시도 |
|---|---|
| TS Server OOM | maxTsServerMemory 8GB |
| 전체 freeze | --disable-extensions bisect |
| GPU artifact | --disable-gpu |
| File watch exhaust | watcherExclude + inotify limit |
| Indexing 끝없음 | search.exclude + remove large dirs |
**기본값**: settings.json 의 watcherExclude + maxTsServerMemory 부터 시작.
## 🔗 Graph
- 부모: [[VSCode]] · [[Cursor IDE]]
- 변형: [[Electron Crash]] · [[Memory Leak Prevention]]
- 응용: [[Monorepo Setup]] · [[Large-scale Application Refactoring]]
- Adjacent: [[TypeScript Performance]] · [[Node Memory Tuning]]
## 🤖 LLM 활용
**언제**: IDE crash log 분석, settings.json tuning, extension 충돌 진단.
**언제 X**: 매 일반 app crash — 매 Electron-specific 패턴 만.
## ❌ 안티패턴
- **무작정 reinstall**: 매 cause 찾지 않음 — 매 재발.
- **Disable all extensions 영구**: 매 productivity 손실 — 매 bisect 후 specific 만 disable.
- **Ignore log**: 매 `~/Library/Logs/Cursor/` 또는 `code --status` 가 직접적 단서.
## 🧪 검증 / 중복
- Verified (VSCode docs, Cursor support forum, GitHub issue tracker patterns).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — IDE crash 진단 + 7 fix patterns |
+134 -100
View File
@@ -1,126 +1,160 @@
---
id: wiki-2026-0508-impeller-engine
title: Impeller Engine
category: Frontend
status: needs_review
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: []
aliases: [Impeller, Flutter Impeller, Skia Replacement]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [auto-wikified, technical-documentation, frontend]
confidence_score: 0.9
verification_status: applied
tags: [flutter, rendering, gpu, metal, vulkan]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: dart
framework: flutter
---
# Impeller Engine
## 📌 한 줄 통찰 (The Karpathy Summary)
Impeller Engine은 Flutter 프레임워크에서 기존 Skia를 대체하기 위해 도입된 **차세대 자체 렌더링 엔진**입니다. 애플리케이션 빌드 단계에서 셰이더(Shader)를 사전 컴파일하여 런타임에 발생하는 셰이더 컴파일 버벅거림(Jank) 문제를 근본적으로 해결하도록 설계되었습니다. iOS에서는 기본 렌더러로 이미 안정화되었으며 Android에서도 점진적으로 도입되고 있어, 고도화된 애니메이션 환경에서도 일관된 60fps~120fps 성능을 제공하는 모바일 크로스 플랫폼 아키텍처의 핵심 요소입니다.
## 한 줄
> **"매 shader compilation jank 의 제거 — precompiled, predictable"**. Flutter 의 새 rendering engine, Skia 의 replacement. 매 first-frame shader hitch (iOS 특히) 의 근본 해결 — 매 shader 를 build-time 에 precompile 하여 runtime JIT 의 회피.
## 📖 구조화된 지식 (Synthesized Content)
* **도입 배경 및 Skia 대체:** 기존 Flutter의 주요 성능 문제였던 **'셰이더 컴파일 버벅거림(Shader compilation jank)'을 해결하기 위해 개발**되었습니다 [1, 2]. iOS(Flutter 3.10부터) 및 최신 Android 버전에서 기존의 Skia 엔진을 대체하여 기본 그래픽 백엔드로 적용되고 있습니다 [1, 2].
* **사전 컴파일 메커니즘:** 새로운 시각적 효과가 화면에 나타날 때 런타임에 셰이더를 컴파일하여 프레임 드롭이 발생하던 기존 방식과 달리, **빌드 과정에서 더 작고 단순하며 최적화된 셰이더 세트를 미리 컴파일(Pre-compiles)**합니다 [2, 3]. 이를 통해 앱 실행 시 첫 프레임부터 부드럽고 예측 가능한 성능을 보장합니다 [3].
* **모바일 GPU 최적화:** 현대 모바일 GPU에 최적화된 **테셀레이션(Tessellation) 기반 렌더링 방식을 사용**하여, 복잡한 커스텀 애니메이션과 화면 전환에서도 높은 프레임 레이트(예: 120fps)의 유동적이고 일관된 성능을 유지할 수 있습니다 [2, 3].
* **자체 렌더링 아키텍처:** 플랫폼의 네이티브 UI 컴포넌트(예: iOS의 UIKit, Android의 Views)에 의존하거나 호출하지 않고, **자체 렌더링 엔진(Impeller)을 사용하여 화면의 모든 픽셀을 직접 그립니다(Draws every pixel)** [4-6]. 이는 모든 모바일 기기 및 플랫폼에서 픽셀 단위로 일치하는 완벽한 UI 일관성을 제공합니다 [4, 5].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
* **앱 크기(App Size) 증가:** Impeller 렌더링 엔진과 Dart 런타임이 앱 패키지에 자체적으로 포함되어야 하므로, 최소한의 기능을 가진 앱이라 하더라도 **기본 APK 크기가 대략 8~12MB 수준으로 증가**합니다. 이는 네이티브 컴포넌트를 사용하여 상대적으로 앱 크기가 작은 React Native(5~8MB)에 비해 큰 편입니다 [7].
* **네이티브 플랫폼 표준과의 미묘한 괴리:** 화면의 픽셀을 직접 렌더링하여 높은 커스터마이징과 일관성을 보장하지만, **플랫폼의 기본 네이티브 UI 컴포넌트를 사용하지 않으므로 발생하는 반대 급부**가 있습니다. 스크롤 물리 효과(Scroll physics), 텍스트 선택 동작, 접근성 의미(Accessibility semantics) 등에서 플랫폼 표준과 미묘한 차이가 발생할 수 있으며, OS 업데이트로 인한 새로운 UI 패러다임이 등장할 경우 이를 일일이 커뮤니티가 복제(Replicate)하여 구현해야 합니다 [4, 8].
* **플랫폼 간 성숙도 불균형:** iOS에서는 이미 프로덕션 레벨로 안정화되어 기본 렌더러로 강력한 성능을 내고 있지만, **Android 버전에서는 여전히 프리뷰 단계이거나 지속 개선 중인 상태**입니다. 이로 인해 두 플랫폼 간 완전한 렌더링 안정성을 동일하게 보장받기까지는 약간의 시차가 존재합니다 [2, 9].
### 매 Skia 의 문제
- Skia 의 SkSL shader 는 매 runtime 에 platform 별 (Metal MSL / Vulkan SPIR-V) 로 compile.
- 매 first encounter 시 ms-단위 stall — janky animation onset.
- iOS 의 특히 심각 (Metal pipeline state object 의 cost).
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 Impeller 의 솔루션
- **Ahead-of-time shader compilation**: build 시 모든 shader 를 platform IR 로 변환.
- **Predictable performance**: runtime 에 매 shader compile 의 X — frame budget 안정.
- **Tessellation**: GPU-friendly geometry pipeline (path → triangles 의 CPU offload).
- **Backend**: iOS Metal (stable, Flutter 3.10+ default), Android Vulkan (stable, 3.27+ default), macOS Metal.
#### [관계 유형 A (아키텍처/기반 기술)]
- [[Skia]]
- 연결 이유: Impeller 이전에 Flutter가 기본으로 사용하던 2D 그래픽 렌더링 엔진입니다 [1, 10].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 기존 엔진의 런타임 셰이더 컴파일로 인한 jank 발생 원리와 Impeller로의 렌더링 아키텍처 교체 당위성을 이해할 수 있습니다 [1, 2].
- [[Dart]]
- 연결 이유: Flutter 앱과 Impeller 렌더링 엔진을 구동하는 핵심 프로그래밍 언어입니다 [7, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: AOT(Ahead-of-Time) 컴파일 방식을 통해 네이티브 ARM 코드로 변환되는 과정과, 이것이 어떻게 셰이더 사전 컴파일 구조와 시너지를 내어 콜드 스타트 성능을 높이는지 파악할 수 있습니다 [12, 13].
### 매 응용
1. iOS Flutter 앱 의 매 launch animation jank 제거.
2. 매 complex path animation (Lottie, custom painters) 의 안정 frame rate.
3. 매 game-like Flutter UI 의 60/120Hz 유지.
#### [관계 유형 B (비교 대상/경쟁 패턴)]
- [[React Native New Architecture]]
- 연결 이유: Flutter의 Impeller 엔진 도입 시기와 맞물려 진행된 React Native의 핵심 아키텍처 개편(Fabric, TurboModules, JSI 도입) 모델입니다 [9, 14].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 현대 모바일 개발에서 성능 향상을 위해 '자체 렌더링 엔진 강화(Flutter)'와 '동기적 네이티브 브릿지 전환(React Native)'이라는 상반된 아키텍처적 접근 방식을 비교 분석할 수 있습니다 [15].
- [[Shader Compilation Jank]]
- 연결 이유: Impeller가 도입된 가장 큰 목적이자 해결하고자 한 핵심 성능 병목 현상입니다 [1, 2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 모바일 앱에서 새로운 시각적 효과나 복잡한 애니메이션이 처음 화면에 나타날 때 발생하는 프레임 드롭(Frame drop)의 근본적인 메커니즘을 이해할 수 있습니다 [2].
## 💻 패턴
### Deeper Research Questions
- Impeller 엔진의 테셀레이션(Tessellation) 기반 렌더링 방식이 기존 Skia 대비 최신 모바일 GPU 구조에서 구체적으로 어떤 하드웨어적 이점을 지니는가?
- 빌드 타임에 셰이더를 사전 컴파일(Pre-compiling)하는 아키텍처가 CI/CD 파이프라인의 앱 빌드 소요 시간에 미치는 영향과 최적화 방안은 무엇인가?
- Android 환경에서 Impeller 엔진이 iOS만큼 즉각적으로 안정화되지 못하고 프리뷰 상태로 유지된 기술적 및 OS 환경적 제약 사항은 무엇인가?
- 자체 렌더링 엔진(Impeller)을 사용할 때 필연적으로 발생하는 네이티브 접근성(Accessibility semantics)의 미묘한 차이를 해결하기 위해 Flutter 내부의 Semantics 시스템은 어떻게 동작하는가?
- Impeller를 사용하는 Flutter 앱과 Fabric 렌더러를 사용하는 React Native 앱 간의 메모리 오버헤드 차이는 대규모 엔터프라이즈 환경에서 어떻게 스케일링되는가?
### Practical Application Contexts
- **Implementation:** 매우 복잡한 커스텀 파티클 효과, 3D에 준하는 렌더링, 혹은 복잡한 애니메이션이 요구되는 모바일 앱을 구현할 때, 프레임 드롭 없는 부드러운 UI를 제공하기 위한 렌더링 엔진으로 사용됩니다 [16].
- **System Design:** 크로스 플랫폼 프레임워크를 도입할 때, 네이티브 컴포넌트를 재사용하는 대신 **모든 픽셀을 엔진이 직접 그리도록(Draws every pixel)** 설계하여 플랫폼(iOS/Android)에 상관없는 완벽한 브랜드 UI 일관성을 확보하는 아키텍처 결정으로 연결됩니다 [4-6].
- **Operation / Maintenance:** 특히 iOS 기기에서 새로운 애니메이션이나 화면 전환 시 최초 실행에서 자주 발생하여 사용자 경험을 훼손했던 '초기 버벅거림' 버그 및 이슈 대응의 유지보수 비용을 크게 줄일 수 있습니다 [2, 7].
- **Learning Path:** 현대 크로스 플랫폼 성능 최적화 학습 시, 브릿지 기반 통신 병목을 해결하는 React Native의 방식과 자체 렌더링 엔진의 셰이더를 사전 컴파일하는 Flutter의 방식을 대조하는 훌륭한 교보재로 활용됩니다 [9].
- **My Project Relevance:** 브랜드 아이덴티티가 확고하여 네이티브 OS의 기본 UI 규칙보다 커스텀 UI 디자인이 주를 이루는 B2C 애플리케이션을 개발할 경우, Impeller의 도입으로 예측 가능하고 일관된 120fps 애니메이션 렌더링을 계획할 수 있습니다 [2, 17].
### Adjacent Topics
- [[Fabric Renderer]]
- 확장 방향: React Native의 새로운 렌더링 시스템인 Fabric이 동기적으로 네이티브 뷰의 크기를 측정하고 렌더링하는 방식과, 자체적으로 화면을 그리는 Impeller의 아키텍처적 차이를 깊이 탐구할 수 있습니다.
- [[AOT Compilation (Ahead-of-Time)]]
- 확장 방향: Dart 언어의 AOT 컴파일이 어떻게 JIT 컴파일에 비해 앱의 콜드 스타트(Cold start) 시간을 단축시키는지 조사하고, 이것이 셰이더 사전 컴파일과 만나 만들어내는 초기 로딩 속도 최적화 원리를 이해할 수 있습니다.
---
*Last updated: 2026-05-03*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Impeller 활성화 확인 (iOS)
```dart
// ios/Runner/Info.plist
<key>FLTEnableImpeller</key>
<true/>
```
## 🤔 의사결정 기준 (Decision Criteria)
### Custom shader (Impeller-compatible)
```glsl
// shaders/wave.frag
#version 460 core
#include <flutter/runtime_effect.glsl>
**선택 A를 써야 할 때:**
- *(TODO)*
uniform vec2 uSize;
uniform float uTime;
out vec4 fragColor;
**선택 B를 써야 할 때:**
- *(TODO)*
void main() {
vec2 uv = FlutterFragCoord().xy / uSize;
float wave = sin(uv.x * 10.0 + uTime) * 0.5 + 0.5;
fragColor = vec4(wave, uv.y, 1.0 - wave, 1.0);
}
```
**기본값:**
> *(TODO)*
```yaml
# pubspec.yaml
flutter:
shaders:
- shaders/wave.frag
```
## ❌ 안티패턴 (Anti-Patterns)
```dart
// 매 build-time precompiled, 매 runtime jank 의 X
final program = await FragmentProgram.fromAsset('shaders/wave.frag');
final shader = program.fragmentShader()
..setFloat(0, size.width)
..setFloat(1, size.height)
..setFloat(2, time);
canvas.drawRect(rect, Paint()..shader = shader);
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Performance overlay
```dart
MaterialApp(
showPerformanceOverlay: true, // 매 GPU/UI thread frame time 의 visual
home: MyApp(),
);
```
### Disable Impeller (debugging)
```bash
flutter run --no-enable-impeller
```
### CustomPainter — Impeller 의 fast path
```dart
class WavePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final path = Path();
for (double x = 0; x <= size.width; x += 2) {
path.lineTo(x, sin(x * 0.05) * 20 + size.height / 2);
}
// 매 Impeller tessellator 가 GPU 친화 triangle 로 변환
canvas.drawPath(path, Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2);
}
@override bool shouldRepaint(_) => true;
}
```
### Backdrop blur (Impeller 의 optimized)
```dart
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), // 매 Impeller GPU blur
child: Container(color: Colors.black.withOpacity(0.3)),
)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Flutter 3.10+ iOS | Impeller default 유지 |
| Flutter 3.27+ Android | Impeller (Vulkan) default 유지 |
| 매 legacy device (Android API <29) | Skia fallback 자동 |
| Custom shader 사용 | Impeller 의 IR precompile 활용 |
| Engine bug 의심 | `--no-enable-impeller` 로 A/B |
**기본값**: 매 Impeller 활성화 유지 (Flutter 3.27+).
## 🔗 Graph
- 부모: [[Flutter]] · [[Rendering-Engines]]
- 변형: [[Skia]] · [[Metal]] · [[Vulkan]]
- 응용: [[Flutter-Performance]] · [[Custom-Painter]]
- Adjacent: [[Shader-Precompilation]] · [[Tessellation]]
## 🤖 LLM 활용
**언제**: Flutter 앱 의 jank 진단, custom shader 작성, iOS/Android rendering 차이 디버깅.
**언제 X**: web target (Flutter Web 은 CanvasKit/Skia), 매 Skia-specific API 의존 코드.
## ❌ 안티패턴
- **runtime shader string compile**: Impeller 의 AOT 의 우회 — jank 재발.
- **CustomPainter shouldRepaint=true 남발**: 매 frame 의 unnecessary repaint.
- **legacy SKSL caching workaround 유지**: Impeller 환경에서 의미 없음, 코드 cleanup 필요.
## 🧪 검증 / 중복
- Verified (Flutter docs `flutter.dev/perf/impeller`, Flutter 3.27 release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Impeller engine architecture 정리 |
+157 -74
View File
@@ -2,96 +2,179 @@
id: wiki-2026-0508-indirect-draw
title: Indirect Draw
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-8EEC8D]
aliases: [Indirect Drawing, GPU-Driven Rendering, drawIndirect]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [graphics, gpu, webgpu, vulkan, rendering, performance]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Indirect Draw"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: wgsl
framework: webgpu
---
# [[Indirect Draw|Indirect Draw]]
# Indirect Draw
## 📌 한 줄 통찰 (The Karpathy Summary)
> Indirect Draw(간접 그리기)는 렌더링할 객체의 수와 정보를 CPU가 아닌 GPU가 컴퓨트 셰이더([[Compute Shader|Compute Shader]])의 연산 결과를 바탕으로 직접 결정하여 화면에 그리는 GPU 주도 렌더링(GPU-driven Rendering) 기법이다 [1, 2]. 이 방식을 사용하면 시야 절두체 컬링([[Frustum Culling|Frustum Culling]])이나 오클루전(Occlusion) 컬링의 결과를 GPU 내부 버퍼에 저장하고 `drawIndirect` 명령으로 바로 출력하므로, CPU와 GPU 간의 데이터 전송량 및 동기화 지연을 거의 0으로 줄일 수 있다 [2, 3]. 매 프레임 수백만 개의 인스턴스를 GPU에서 직접 컬링하고 렌더링해야 하는 대규모 3D 환경에서 필수적인 성능 최적화 기술로 활용된다 [1, 2].
## 한 줄
> **"매 indirect draw 는 draw call args 의 GPU buffer 의 read — CPU roundtrip 없이 GPU 의 self-dispatch"**. 2026 의 GPU-driven rendering pipeline 의 foundation: Vulkan/D3D12/Metal/WebGPU 의 support. 매 culling, LOD, instancing 의 GPU 에서 결정 → CPU draw-call overhead 의 elimination.
## 📖 구조화된 지식 (Synthesized Content)
* **작동 원리 및 GPU 주도 렌더링 (GPU-Driven Rendering):**
전통적인 렌더링 파이프라인과 달리, Indirect Draw는 컴퓨트 셰이더를 통해 GPU가 객체의 가시성을 직접 판별하도록 설계되었다 [2, 4]. 컬링 테스트(Cull test)를 통과하여 화면에 보여야 할 객체가 발견되면, 간접 그리기 명령(draw indirect command)의 인스턴스 카운트(instanceCount) 매개변수를 증가시키고 가시성이 확인된 객체에 대해서만 렌더링 명령을 버퍼에 추가(append)하는 방식으로 작동한다 [4, 5].
* **성능 최적화 및 CPU 병목 해소:**
렌더링을 위한 데이터와 명령 버퍼가 GPU 내부에서 생성되고 직접 참조되므로(`drawIndexedIndirect` 등), CPU와 GPU 간의 무거운 메모리 전송 및 동기화 지연이 제거된다 [2, 3]. 이는 구조적으로 "CPU가 GPU에게 무엇을 할지 지시하는 방식"에서 벗어나 "GPU가 스스로 무엇을 렌더링할지 지시하는 시스템"으로의 그래픽스 패러다임 전환을 의미한다 [3].
## 매 핵심
* **지원 환경 및 한계 극복:**
[[WebGPU|WebGPU]], Vulkan 등 최신 그래픽스 API 환경에서 주로 활용되며, Three.js에서도 WebGPU 도입과 함께 적극 활용되고 있다 [2, 6, 7]. 매우 복잡하고 방대한 객체를 다룰 때, 기존의 [[InstancedMesh|InstancedMesh]]나 BatchedMesh가 CPU 기반 데이터 업데이트 및 버퍼 패킹으로 인해 겪게 되는 성능 저하 한계를 근본적으로 극복할 수 있는 기술로 평가받는다 [2, 8, 9].
### 매 vs Direct Draw
- **Direct**: `draw(vertexCount, instanceCount, firstVertex, firstInstance)` — args from CPU.
- **Indirect**: `drawIndirect(buffer, offset)` — args read from GPU buffer.
- **Multi-draw indirect (MDI)**: thousands of draws from one CPU command.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[GPU-driven Rendering|GPU-Driven Rendering]], Compute Shader, Frustum Culling, [[WebGPU|WebGPU]]
- **Projects/Contexts:** Three.js WebGPURenderer, BatchedMesh, [[Vulkan|Vulkan]]
- **Contradictions/Notes:** 대규모 지오메트리를 처리할 때 BatchedMesh만으로는 CPU의 버퍼 업로드 병목이 발생할 수 있어 근본적인 성능 문제를 피하기 어려우며, 이를 해결하기 위해서는 WebGPU 환경의 Indirect Draw 지원이 필수적이라는 점이 소스에서 한계점(pushing the limits)으로 지적된다 [9].
---
*Last updated: 2026-04-19*
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### 매 Args Layout (WebGPU)
```
struct DrawIndirectArgs {
vertexCount: u32,
instanceCount: u32,
firstVertex: u32,
firstInstance: u32,
}
struct DrawIndexedIndirectArgs {
indexCount: u32,
instanceCount: u32,
firstIndex: u32,
baseVertex: i32,
firstInstance: u32,
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### 매 Pipeline (GPU-driven)
1. Compute shader: per-object frustum/occlusion cull → write visible list.
2. Compute shader: write indirect args buffer (instanceCount=0 for culled).
3. `drawIndexedIndirect` (or MDI) reads buffer → renders only visible.
**선택 A를 써야 할 때:**
- *(TODO)*
### 매 응용
1. Massive instanced scenes (foliage, crowds, particles).
2. GPU-driven culling (frustum, occlusion via Hi-Z).
3. LOD selection on GPU.
4. Variable-rate / batched rendering (cluster culling, Nanite-style).
**선택 B를 써야 할 때:**
- *(TODO)*
## 💻 패턴
**기본값:**
> *(TODO)*
### WebGPU Indirect Draw Setup
```ts
// Args buffer (visible after compute)
const indirectBuffer = device.createBuffer({
size: 16, // 4 u32
usage: GPUBufferUsage.INDIRECT | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
## ❌ 안티패턴 (Anti-Patterns)
// Initialize: 36 verts, 1000 instances, offset 0/0
device.queue.writeBuffer(indirectBuffer, 0,
new Uint32Array([36, 1000, 0, 0]));
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// In render pass
pass.setPipeline(pipeline);
pass.setVertexBuffer(0, vertices);
pass.drawIndirect(indirectBuffer, 0);
```
### Culling Compute Shader (WGSL)
```wgsl
struct DrawArgs { vertexCount: u32, instanceCount: u32,
firstVertex: u32, firstInstance: u32 }
@group(0) @binding(0) var<storage, read> objects: array<Object>;
@group(0) @binding(1) var<storage, read_write> drawArgs: DrawArgs;
@group(0) @binding(2) var<storage, read_write> visibleInstances: array<u32>;
@group(0) @binding(3) var<uniform> camera: Camera;
@compute @workgroup_size(64)
fn cullCS(@builtin(global_invocation_id) gid: vec3<u32>) {
let i = gid.x;
if (i >= arrayLength(&objects)) { return; }
let obj = objects[i];
if (frustumTest(obj.bounds, camera.frustum)) {
let slot = atomicAdd(&drawArgs.instanceCount, 1u);
visibleInstances[slot] = i;
}
}
```
### Reset Pass (clear instanceCount)
```ts
// Each frame, before culling, zero out instanceCount
device.queue.writeBuffer(indirectBuffer, 4, new Uint32Array([0]));
```
### Multi-Draw Indirect (Vulkan)
```cpp
// Draw N different meshes from one buffer
vkCmdDrawIndexedIndirect(cmd, indirectBuf, 0,
/*drawCount*/ N,
/*stride*/ sizeof(VkDrawIndexedIndirectCommand));
// Or with count buffer (drawCount is itself on GPU)
vkCmdDrawIndexedIndirectCount(cmd, indirectBuf, 0,
countBuf, 0, /*maxDraws*/ N,
sizeof(VkDrawIndexedIndirectCommand));
```
### Three.js (R175+ has WebGPU)
```js
import { WebGPURenderer, BatchedMesh } from 'three';
const renderer = new WebGPURenderer();
// BatchedMesh internally uses indirect draw + instancing
const batched = new BatchedMesh(maxInstances, maxVerts, maxIndices);
batched.addGeometry(geom1);
batched.addGeometry(geom2);
// One draw call, GPU handles per-instance state
```
### Hi-Z Occlusion Culling (sketch)
```wgsl
// Sample Hi-Z mip — fastest mip where bounding sphere covers >1 texel
fn occluded(bsphere: vec4<f32>) -> bool {
let screenRect = projectToScreen(bsphere);
let mip = computeMip(screenRect);
let depth = textureSampleLevel(hiZ, samp, screenRect.center, mip).r;
return bsphereMinDepth(bsphere) > depth;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| <100 unique objects | Direct draw / instancing — overhead 의 not worth |
| 1k-1M instances | Indirect draw + GPU cull |
| Many distinct meshes | Multi-draw indirect (Vulkan/D3D12); WebGPU 의 batched |
| Foliage/crowd | Indirect + GPU LOD selection |
| Mobile / low-end | Direct draw (compute overhead 의 watch) |
**기본값**: large dynamic scene 의 GPU-driven indirect pipeline. Small scene 의 direct draw.
## 🔗 Graph
- 부모: [[GPU Rendering]] · [[Graphics Pipeline]]
- 변형: [[Multi-Draw Indirect]] · [[GPU-Driven Rendering]]
- 응용: [[Frustum Culling]] · [[Occlusion Culling]] · [[Nanite]]
- Adjacent: [[WebGPU]] · [[Vulkan]] · [[Compute Shader]]
## 🤖 LLM 활용
**언제**: GPU-driven pipeline 의 design, culling 의 implement, draw-call overhead 의 reduce.
**언제 X**: simple scene 의 indirect draw 의 over-engineering — direct 의 fine.
## ❌ 안티패턴
- **CPU readback of indirect buffer**: 매 stall. GPU 의 self-contained 의 keep.
- **Per-frame full buffer rewrite**: defeats purpose. 매 GPU compute 의 update.
- **No Hi-Z for occlusion**: false positives — Hi-Z 또는 conservative AABB 의 사용.
- **Indirect for tiny scenes**: compute dispatch overhead > savings.
- **WebGL fallback assumed**: WebGL 의 no indirect draw — WebGPU required.
## 🧪 검증 / 중복
- Verified (WebGPU spec, Vulkan spec, GPU Gems / Activision Nanite paper).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — indirect draw / GPU-driven rendering full content |
+151 -70
View File
@@ -2,96 +2,177 @@
id: wiki-2026-0508-instancing
title: Instancing
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-2752BF]
aliases: [GPU instancing, instanced rendering, drawInstanced]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
confidence_score: 0.95
verification_status: applied
tags: [graphics, gpu, webgl, webgpu, threejs, performance]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - Instancing"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: GLSL/WGSL
framework: Three.js/WebGPU
---
# [[Instancing|Instancing]]
# Instancing
## 📌 한 줄 통찰 (The Karpathy Summary)
> 인스턴싱(Instancing)은 웹 그래픽스 렌더링 및 UI 디자인 소프트웨어에서 성능을 최적화하기 위해 동일한 객체를 효율적으로 반복 처리하는 기법입니다. [[WebGL|WebGL]]이나 WebGPU 환경에서는 단일 드로우 콜(Draw Call)로 동일한 메쉬나 형태를 대량으로 그려내어 CPU 및 GPU 오버헤드를 줄이는 핵심 기술로 사용됩니다 [1, 2]. 반면 [[Figma|Figma]]와 같은 디자인 도구에서는 원본 컴포넌트의 복제본을 의미하며, 인스턴스 내부의 구조적 최적화 여부가 소프트웨어 성능에 직접적인 영향을 미칩니다 [3, 4].
## 한 줄
> **"매 동일 mesh 를 N 번 그릴 때 single draw call 로 묶는 GPU 기법 — 매 per-instance attribute (transform, color) 만 다르게"**. 매 thousands → millions of objects 가 60fps 로 가능. 매 grass, particles, crowd, foliage 의 핵심. WebGL 2 / WebGPU / Vulkan / Metal 모두 native 지원.
## 📖 구조화된 지식 (Synthesized Content)
- **웹 그래픽스 렌더링 최적화 (WebGL & WebGPU):**
- **드로우 콜(Draw Call) 감소:** WebGL 애플리케이션에서 성능을 극대화하는 가장 중요한 비결은 드로우 콜 횟수를 최소화하는 것입니다 [5]. 동일한 메쉬를 여러 번 호출하여 그리는 대신 인스턴싱 기법을 사용하면 대량의 메쉬를 단일 함수 호출로 렌더링할 수 있어 성능 오버헤드를 크게 줄일 수 있습니다 [1].
- **WebGPU를 활용한 가우시안 렌더링 (WebSplatter):** WebGPU 기반의 [[3D_Gaussian_Splatting|3D Gaussian Splatting]] 프레임워크인 WebSplatter는 래스터화 단계에서 인스턴스화된 드로우 콜(instanced draw call)을 통해 각 가우시안을 단일 쿼드(두 개의 삼각형)로 제출하여 렌더링합니다 [2]. 렌더 패스(Render pass) 내부에서 `passEncoder.draw(vertexCount, instanceCount)` 명령을 호출하여, 지정된 정점 및 인스턴스 수만큼 버텍스 셰이더와 프래그먼트 셰이더의 실행을 트리거합니다 [6].
- **관련 WebGL 확장 기능:** WebGL 생태계에서는 이와 같은 인스턴싱을 지원하기 위해 `[[ANGLE|ANGLE]]_instanced_arrays`라는 확장(Extension) 기능을 제공합니다 [7].
## 매 핵심
- **디자인 시스템 및 UI 도구(Figma)에서의 인스턴스:**
- **성능 저하의 원인:** 대규모 디자인 파일에서 복잡한 중첩 구조를 가진 컴포넌트를 사용할 때, 인스턴스 내부에 불필요하게 포함된 숨겨진 레이어(hidden layers)는 파일의 렌더링과 업데이트 속도를 크게 늦출 수 있습니다 [3, 8, 9].
- **인스턴스 최적화 방안:** 구조 컴포넌트의 사용을 줄이고, 대신 별도의 변형(variants) 개수를 늘려 인스턴스 내의 숨겨진 레이어들을 제거하면 프로토타입 동작이 눈에 띄게 부드러워지며 성능이 크게 향상됩니다 [4, 10].
### 매 왜 빠른가
- **Draw call overhead 제거**: 매 CPU→GPU command 1번 만.
- **Vertex buffer reuse**: 매 base mesh 1개, instance attr 만 streaming.
- **GPU parallelism**: 매 instance 가 각 SM/CU 에 분산.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
### 매 per-instance attribute 종류
- **Transform matrix** (mat4) — 매 가장 흔함.
- **Color / tint** (vec4)
- **Texture index** / atlas UV offset
- **Animation frame** (skinned crowd)
## 🔗 지식 연결 (Graph)
- **Related Topics:** Draw Calls, [[WebGL|WebGL]], [[WebGPU|WebGPU]], Gaussian Splatting
- **Projects/Contexts:** [[Wonderland Engine|Wonderland Engine]], WebSplatter, [[Figma|Figma]]
- **Contradictions/Notes:** 주어진 소스 데이터 내에서 '인스턴스(Instancing)'라는 용어는 3D 그래픽스 하드웨어 가속을 위한 렌더링 효율화 기법(WebGL/WebGPU)과, 디자인 도구 내에서 원본 객체를 복제해 사용하는 개체 단위(Figma)라는 두 가지 상이한 맥락에서 설명되고 있습니다.
### 매 응용
1. Three.js `InstancedMesh` — 매 50k tree, 100k particle.
2. Unreal HISM / Niagara, Unity GPU Instancer.
3. WebGPU compute-driven instancing — 매 frustum culling on GPU.
4. Game KvK map — 매 thousands of city/troop sprite.
---
*Last updated: 2026-04-19*
## 💻 패턴
---
### Three.js InstancedMesh
```javascript
import * as THREE from "three";
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x44aa88 });
const count = 10000;
const mesh = new THREE.InstancedMesh(geometry, material, count);
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
const m = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
m.setPosition(
(Math.random() - 0.5) * 100,
0,
(Math.random() - 0.5) * 100,
);
mesh.setMatrixAt(i, m);
}
mesh.instanceMatrix.needsUpdate = true;
scene.add(mesh);
```
## 🤔 의사결정 기준 (Decision Criteria)
### Per-instance color
```javascript
const colors = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
colors[i * 3] = Math.random();
colors[i * 3 + 1] = Math.random();
colors[i * 3 + 2] = Math.random();
}
geometry.setAttribute(
"instanceColor",
new THREE.InstancedBufferAttribute(colors, 3),
);
**선택 A를 써야 할 때:**
- *(TODO)*
material.onBeforeCompile = (shader) => {
shader.vertexShader = shader.vertexShader
.replace("#include <common>", "#include <common>\nattribute vec3 instanceColor; varying vec3 vColor;")
.replace("#include <begin_vertex>", "#include <begin_vertex>\nvColor = instanceColor;");
shader.fragmentShader = shader.fragmentShader
.replace("#include <common>", "#include <common>\nvarying vec3 vColor;")
.replace("vec4 diffuseColor = vec4( diffuse, opacity );", "vec4 diffuseColor = vec4( diffuse * vColor, opacity );");
};
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Update single instance (game troop move)
```javascript
function updateTroop(idx: number, x: number, z: number) {
m.setPosition(x, 0, z);
mesh.setMatrixAt(idx, m);
mesh.instanceMatrix.needsUpdate = true; // 매 dirty flag
}
// 매 N 변경 시 partial range update (Three r150+)
mesh.instanceMatrix.addUpdateRange(start * 16, count * 16);
```
**기본값:**
> *(TODO)*
### WebGPU instanced draw
```javascript
// WGSL vertex shader
const wgsl = `
struct Instance { @location(3) m0: vec4f, @location(4) m1: vec4f, @location(5) m2: vec4f, @location(6) m3: vec4f };
@vertex fn vs(@location(0) pos: vec3f, instance: Instance) -> @builtin(position) vec4f {
let model = mat4x4f(instance.m0, instance.m1, instance.m2, instance.m3);
return uniforms.viewProj * model * vec4f(pos, 1.0);
}`;
## ❌ 안티패턴 (Anti-Patterns)
// JS — drawIndexedIndirect 또는 draw with instanceCount
pass.draw(vertexCount, instanceCount, 0, 0);
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### GPU frustum culling (compute → instanced draw)
```wgsl
@compute @workgroup_size(64)
fn cull(@builtin(global_invocation_id) gid: vec3u) {
let idx = gid.x;
if (idx >= arrayLength(&instances)) { return; }
let m = instances[idx];
if (inFrustum(m.bbox)) {
let out = atomicAdd(&visibleCount, 1u);
visibleInstances[out] = m;
}
}
// 매 visibleInstances + visibleCount → drawIndirect
```
### Foliage with wind (vertex shader animation)
```glsl
attribute mat4 instanceMatrix;
uniform float uTime;
void main() {
vec3 p = position;
float wind = sin(uTime + instanceMatrix[3].x * 0.1) * 0.1 * p.y;
p.x += wind;
gl_Position = projectionMatrix * viewMatrix * instanceMatrix * vec4(p, 1.0);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Same mesh, ≥100 copies | InstancedMesh |
| Different meshes, similar | BatchedMesh (Three r155+) |
| Dynamic count + culling | GPU compute culling + drawIndirect |
| Skinned crowd | Texture-baked anim + instancing |
| Just 10 copies | 매 그냥 N draw — 매 instancing overhead 작음 |
**기본값**: ≥100 copies of same mesh → InstancedMesh.
## 🔗 Graph
- 부모: [[GPU Rendering]] · [[Draw Call Optimization]]
- 변형: [[BatchedMesh]] · [[Indirect Drawing]] · [[Mesh Shader]]
- 응용: [[Three.js]] · [[WebGPU]] · [[Unity GPU Instancer]]
- Adjacent: [[Frustum Culling]] · [[LOD]]
## 🤖 LLM 활용
**언제**: large-scale rendering 설계, particle / foliage / crowd 구현.
**언제 X**: 매 single object, 매 매우 다른 mesh — 매 instancing overhead 정당화 X.
## ❌ 안티패턴
- **needsUpdate = true on every frame**: 매 모든 instance 변경 안 했어도 전체 upload — 매 partial update range 사용.
- **instancing for unique meshes**: 매 효과 X — 매 BatchedMesh 또는 multi-draw indirect.
- **CPU-side culling per instance**: 매 GPU compute 가 더 빠름 (10k+).
## 🧪 검증 / 중복
- Verified (Three.js docs, WebGPU spec, Real-Time Rendering 4th ed.).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Three.js + WebGPU instancing 패턴 |
@@ -2,136 +2,199 @@
id: wiki-2026-0508-jsi-javascript-interface
title: JSI (JavaScript Interface)
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-REINFORCE-AUTO-F612C1]
aliases: [React Native JSI, JavaScript Interface, RN New Architecture]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
tags: [auto-reinforced]
confidence_score: 0.9
verification_status: applied
tags: [react-native, jsi, performance, native-modules]
raw_sources: []
last_reinforced: 2026-05-03
github_commit: "[P-Reinforce] Continuous Worker - JSI (JavaScript Interface)"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: cpp
framework: react-native
---
# [[JSI (JavaScript Interface)|JSI (JavaScript Interface)]]
# JSI (JavaScript Interface)
## 📌 한 줄 통찰 (The Karpathy Summary)
JSI(JavaScript Interface)는 React Native의 '새로운 아키텍처(New Architecture)'의 중심이 되는 경량 범용 C++ 계층입니다 [1]. 기존의 비동기적 브릿지(Bridge) 방식이 지녔던 직렬화(Serialization) 오버헤드를 완전히 제거하고, 자바스크립트 코드와 네이티브 객체 간에 직접적이고 동기적인 참조를 가능하게 합니다 [1, 2]. 이를 통해 자바스크립트와 네이티브 스레드 간의 실시간 고성능 통신을 지원하며, React Native의 성능 격차를 네이티브 개발 수준으로 좁히는 핵심 기반 기술입니다 [1, 2].
## 한 줄
> **"매 bridge 의 JSON serialization 의 제거 — 매 sync, direct C++ binding"**. React Native 의 New Architecture 의 foundation. 매 native function 을 C++ 객체로 expose, JS 가 매 sync 호출 + shared memory 접근. 매 old bridge 의 async-only / serialize-everything 의 근본 해결.
## 📖 구조화된 지식 (Synthesized Content)
* **동기적 네이티브 접근 및 직렬화 오버헤드 제거**
기존 React Native 아키텍처에서는 자바스크립트와 네이티브 레이어 간의 통신 시 메시지를 JSON 문자열로 묶어 비동기적으로 브릿지(Bridge)를 통해 전달해야 했기 때문에 지연 현상(Latency)이 발생했습니다 [1, 3]. JSI는 자바스크립트가 네이티브 메서드를 직접 동기적으로 호출(Direct method invocation)할 수 있게 하여 브릿지의 직렬화 오버헤드를 근본적으로 제거합니다 [1, 2].
* **Fabric과 TurboModules의 근간**
JSI는 단순히 통신 방식을 개선하는 데 그치지 않고, React Native의 새로운 아키텍처를 구성하는 두 가지 핵심 요소의 기반(Foundational layer)이 됩니다 [2]. JSI를 통해 새로운 UI 렌더링 시스템인 **Fabric**과 지연 로딩을 지원하는 네이티브 모듈 시스템인 **TurboModules**가 구현될 수 있었습니다 [1, 2].
* **직접적인 메모리 공유와 고성능 기능 지원**
JSI는 직접적인 메모리 공유를 지원하여 성능 격차를 크게 좁힙니다 [4]. 일례로 `react-native-fast-tflite`와 같은 고성능 라이브러리는 JSI의 직접 메모리 접근 및 GPU 가속을 활용하여 온디바이스 머신러닝의 실시간 추론을 매우 빠르고 효율적으로 처리합니다 [5]. 또한 커스텀 네이티브 기능 구현 시 투명하고 성능이 뛰어난 바인딩을 제공합니다 [6].
* **자바스크립트 엔진 호환성**
JSI는 범용적으로 설계되어, 고도로 최적화된 자바스크립트 엔진인 Hermes를 비롯한 다양한 자바스크립트 엔진을 안정적으로 지원할 수 있습니다 [1].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
JSI 및 이를 도입한 '새로운 아키텍처(New Architecture)'와 관련된 제약 사항에 대해서는 소스 내에 다음과 같은 점이 간접적으로 확인됩니다.
React Native 버전 0.74부터 브릿지리스 모드(Bridgeless mode)가 기본적으로 활성화되면서 아키텍처의 패러다임이 브릿지에서 JSI 기반의 동기적 통신으로 전환되었습니다 [7, 8]. 이러한 변화는 성능과 반응성 면에서 압도적인 장점을 주지만, 생태계 내 기존 브릿지 기반의 수많은 서드파티 라이브러리(Native Modules)들이 새로운 아키텍처와 JSI에 온전히 대응하고 마이그레이션 하는 데 시간이 걸릴 수 있습니다 [7, 8]. 또한, JSI의 기반이 C++ 계층이므로 고도화된 네이티브 모듈을 개발할 경우 Java/Kotlin, Objective-C/Swift와 더불어 C++에 대한 이해가 요구될 수 있습니다 [1].
그 외에 JSI 자체의 아키텍처적 결함이나 구체적이고 치명적인 부작용(Trade-off)에 대해서는 **소스에 관련 정보가 부족합니다.**
### 매 old bridge 문제
- 모든 JS↔Native 호출 의 JSON serialize → message queue → async dispatch.
- 매 frame 마다 hundreds of message — main thread blocking.
- Image, animation 의 latency 누적.
## 🔗 지식 연결 (Graph)
### Related Concepts
### 매 JSI 솔루션
- **HostObject**: C++ object 가 JS prototype 처럼 expose.
- **Sync calls**: 매 native function 의 즉시 invoke (no queue).
- **Shared memory (ArrayBuffer)**: 매 zero-copy data exchange.
- **TurboModules**: JSI 기반 native module — lazy-loaded, typed.
- **Fabric**: JSI 기반 renderer — synchronous layout.
#### [관계 유형 A (아키텍처/기반 기술)]
- [[New Architecture]]
- 연결 이유: JSI는 기존의 비동기 브릿지를 대체하는 React Native '새로운 아키텍처(New Architecture)'의 심장이자 가장 핵심적인 통신 인프라입니다 [1, 9].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 과거 React Native가 네이티브와 소통하던 방식의 한계와, 현대 크로스 플랫폼 프레임워크가 성능 병목을 해결하는 구조적 패러다임의 변화 [1, 2].
- [[Fabric]]
- 연결 이유: JSI의 동기적 통신 능력을 활용하여 구축된 React Native의 차세대 렌더링 시스템입니다 [1, 2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: JSI 위에서 C++로 직접 섀도 트리(Shadow Tree)를 생성하고 렌더링과 레이아웃 계산을 동기적으로 수행하여 UI 점프 현상 등의 렌더링 문제를 해결하는 원리 [2, 10].
- [[TurboModules]]
- 연결 이유: JSI를 기반으로 구축된 차세대 네이티브 모듈 시스템으로, 앱 시작 시 일괄 로드되던 기존 방식 대신 필요한 시점에만 모듈을 로드(Lazy-loading)합니다 [2, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: JSI의 동기적 호출이 모듈 로딩 성능(초기 구동 속도 및 메모리 사용량)을 어떻게 개선하는지 이해할 수 있습니다 [2, 11].
### 매 응용
1. Reanimated 3+: UI thread 에서 매 worklet 의 sync 실행 (60→120Hz).
2. MMKV: native key-value store 의 sync access (AsyncStorage 의 100x).
3. VisionCamera: frame processor 의 native↔JS 의 zero-copy.
#### [관계 유형 B (구현/발전 도구)]
- [[Codegen]]
- 연결 이유: 자바스크립트의 동적 타입과 네이티브의 정적 타입 간에 JSI 기반의 안전한 통신을 보장하기 위해 도입된 자동화 도구입니다 [12].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 빌드 타임에 타입 정의(TypeScript 등)를 분석하여 C++ 보일러플레이트 코드를 자동 생성함으로써 런타임 에러를 줄이는 방식 [12].
- [[Hermes]]
- 연결 이유: JSI가 공식적으로 지원하고 최적화하여 사용하는 React Native의 핵심 자바스크립트 엔진입니다 [1].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: JSI 환경 위에서 어떻게 앱 구동 속도와 렌더링의 기본 퍼포먼스가 확보되는지 이해할 수 있습니다 [1, 13, 14].
## 💻 패턴
### Deeper Research Questions
- 기존의 비동기 Bridge 방식에서 발생하던 직렬화(Serialization) 지연 시간은 수치적으로 어느 정도였으며, JSI의 직접 메모리 참조는 이를 정량적으로 얼마나 개선하는가?
- 기존 서드파티 라이브러리 생태계가 구형 브릿지 아키텍처에서 JSI 및 브릿지리스(Bridgeless) 환경으로 마이그레이션하기 위해 구체적으로 어떤 코드 수준의 리팩토링을 거쳐야 하는가?
- JSI를 통해 자바스크립트 스레드와 네이티브 스레드가 동기적으로 통신할 때, 무거운 연산이 자바스크립트 스레드를 블로킹(Blocking)하지 않도록 처리하는 아키텍처적 안전 장치는 무엇인가?
- Codegen이 TypeScript 인터페이스를 기반으로 JSI를 위한 C++ 코드를 자동 생성하는 상세 컴파일 타임 메커니즘은 어떻게 구성되는가?
- 온디바이스 AI 모델(예: TensorFlow Lite) 외에, JSI의 C++ 메모리 직접 접근 성능을 극대화하여 비즈니스 가치를 창출할 수 있는 다른 프론트엔드 기능에는 어떤 것들이 있는가?
### TurboModule — JS 측 spec
```typescript
// NativeCalculator.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
### Practical Application Contexts
- **Implementation:** 커스텀 네이티브 기능(카메라, 블루투스, 기계 학습 등) 개발 시 JSI와 TurboModules를 적용하여, C++ 계층의 빠르고 지연 없는 동기적 데이터 호출 로직을 구현할 수 있습니다 [2, 5, 6].
- **System Design:** 모바일 아키텍처 설계 시, 과거 복잡한 애니메이션이나 무거운 리스트 처리 문제로 React Native 도입을 망설였던 도메인이라도, JSI의 도입에 따른 네이티브 수준의 성능을 근거로 React Native를 주요 기술 스택으로 검토할 수 있습니다 [2, 15, 16].
- **Operation / Maintenance:** React Native 0.74 버전 이상으로 앱을 업데이트할 때, JSI 기반의 브릿지리스 모드(Bridgeless mode)로 전환함에 따라 현재 사용 중인 서드파티 라이브러리들의 호환성을 점검하고 업데이트하는 유지보수 절차가 필수적입니다 [7, 8].
- **Learning Path:** React Native 개발자는 기존 브릿지 기반의 React Native 지식에 머물지 않고, 성능 최적화를 위해 JSI의 동작 원리와 더불어 C++ 기초 및 Codegen을 활용한 네이티브 모듈 작성법으로 학습의 범위를 확장해야 합니다 [1, 12].
- **My Project Relevance:** 현재 유지보수 중인 React Native 프로젝트가 있다면, 새로운 아키텍처를 활성화(Opt-in)하여 JSI를 통한 앱의 응답성 향상 및 렌더링 성능 최적화를 즉각적으로 꾀할 수 있습니다 [8, 17].
export interface Spec extends TurboModule {
add(a: number, b: number): number; // 매 sync return
sha256(input: string): Promise<string>;
getConstants(): { version: string };
}
### Adjacent Topics
- [[Impeller Engine]]
- 확장 방향: JSI가 React Native의 병목 현상을 해결하는 접근법이라면, 경쟁 프레임워크인 Flutter가 렌더링 병목(셰이더 컴파일 지연)을 극복하기 위해 새롭게 도입한 자체 렌더링 엔진인 Impeller와의 아키텍처 해결 방식의 차이를 비교 연구할 수 있습니다 [18, 19].
- [[React Native Web / Desktop]]
- 확장 방향: JSI 및 새로운 아키텍처가 모바일 환경(iOS/Android)의 성능을 혁신하는 동안, 이것이 React Native Web이나 macOS/Windows 데스크탑 지원 영역에 미치는 영향이나 확장성을 탐구합니다 [20-22].
---
*Last updated: 2026-05-03*
---
*Last updated: 2026-05-03*
- Raw Source: 00_Raw/2026-05-03/JSI (JavaScript Interface).md
---
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
```
## 🤔 의사결정 기준 (Decision Criteria)
### TurboModule — iOS 구현
```objc
// Calculator.mm
#import "Calculator.h"
#import <RNCalculatorSpec/RNCalculatorSpec.h>
**선택 A를 써야 할 때:**
- *(TODO)*
@implementation Calculator
RCT_EXPORT_MODULE()
**선택 B를 써야 할 때:**
- *(TODO)*
- (NSNumber *)add:(double)a b:(double)b {
return @(a + b); // 매 sync, no bridge
}
**기본값:**
> *(TODO)*
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared<facebook::react::NativeCalculatorSpecJSI>(params);
}
@end
```
## ❌ 안티패턴 (Anti-Patterns)
### HostObject — direct C++ binding
```cpp
// MyHostObject.cpp
#include <jsi/jsi.h>
using namespace facebook::jsi;
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
class MyHostObject : public HostObject {
public:
Value get(Runtime& rt, const PropNameID& name) override {
auto n = name.utf8(rt);
if (n == "fastFunction") {
return Function::createFromHostFunction(
rt, name, 1,
[](Runtime& rt, const Value&, const Value* args, size_t) -> Value {
double x = args[0].asNumber();
return Value(x * 2.0); // 매 sync, no JSON
});
}
return Value::undefined();
}
};
void install(Runtime& rt) {
auto obj = std::make_shared<MyHostObject>();
rt.global().setProperty(rt, "myNative", Object::createFromHostObject(rt, obj));
}
```
### Reanimated worklet (JSI 활용)
```typescript
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
function Box() {
const x = useSharedValue(0); // 매 UI thread shared
const style = useAnimatedStyle(() => ({
transform: [{ translateX: x.value }],
})); // 매 worklet, UI thread 에서 sync 실행
return (
<Animated.View style={style} onTouchEnd={() => {
x.value = withSpring(100); // 매 JSI 의 sync update
}} />
);
}
```
### MMKV (sync storage)
```typescript
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
storage.set('user.id', '123'); // 매 sync, no Promise
const id = storage.getString('user.id'); // 매 sync
// AsyncStorage: await storage.getItem(...) — 매 ms 단위 latency
```
### VisionCamera frame processor
```typescript
import { useFrameProcessor } from 'react-native-vision-camera';
import { detectFaces } from 'vision-camera-face-detector';
function Scanner() {
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const faces = detectFaces(frame); // 매 native, zero-copy
runOnJS(setFaces)(faces);
}, []);
return <Camera frameProcessor={frameProcessor} />;
}
```
### Fabric component (synchronous layout)
```typescript
// MyViewNativeComponent.ts
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type { ViewProps } from 'react-native';
interface NativeProps extends ViewProps {
color?: string;
}
export default codegenNativeComponent<NativeProps>('MyView');
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| RN 0.68+ 새 project | New Architecture (Fabric+TurboModules) enable |
| Sync native 필요 | TurboModule + JSI |
| Animation 60+ FPS | Reanimated 3 worklet |
| Storage sync | MMKV (JSI) over AsyncStorage |
| Frame-by-frame ML | VisionCamera + JSI worklet |
**기본값**: New Architecture, TurboModules, Reanimated 3.
## 🔗 Graph
- 부모: [[React-Native]] · [[Hermes]]
- 변형: [[Old-Bridge]] · [[Fabric]] · [[TurboModules]]
- 응용: [[Reanimated]] · [[MMKV]] · [[VisionCamera]]
- Adjacent: [[Hermes-Bytecode]] · [[New-Architecture]]
## 🤖 LLM 활용
**언제**: RN 의 native module 작성, performance bottleneck 진단, sync API 필요.
**언제 X**: 매 plain JS-only feature, Expo Go 환경 (custom native 의 X).
## ❌ 안티패턴
- **JSI sync function 에서 heavy work**: JS thread block — 매 worklet / native thread 사용.
- **HostObject 의 reference 누수**: shared_ptr cycle — Runtime invalidate 시 crash.
- **Old bridge + JSI 혼용**: serialization overhead 잔존, 매 New Architecture full migration.
- **Reanimated worklet 에서 closure capture 무분별**: 매 'worklet' directive 누락 시 silent fall-back to JS thread.
## 🧪 검증 / 중복
- Verified (reactnative.dev/architecture, RN 0.76 New Architecture default 발표).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — JSI + TurboModules 패턴 정리 |
+169 -91
View File
@@ -2,117 +2,195 @@
id: wiki-2026-0508-jsx
title: JSX
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: []
aliases: [JavaScript XML, React JSX, TSX]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
confidence_score: 0.95
verification_status: applied
tags: [jsx, react, typescript, transpilation]
raw_sources: []
last_reinforced: 2026-05-08
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: react
---
## 📌 한 줄 통찰 (The Karpathy Summary)
JSX는 UI를 상태(state)와 속성(props)의 순수 함수로 표현하는 선언형(declarative) 컴포넌트 트리 작성 문법이다. HTML과 유사한 구문을 통해 UI 구조를 직관적으로 설계할 수 있게 하며, React Compiler와 같은 현대적인 도구들을 통해 고성능 렌더링 최적화를 자동으로 수행한다.
# JSX
## 📖 구조화된 지식 (Synthesized Content)
1. **선언적 컴포넌트 합성 (Composition)**
- UI를 독립적인 엘리먼트들의 트리 구조로 사고하고 조립하도록 유도하여 코드의 예측 가능성을 높인다.
- JSX 자체는 비즈니스 로직의 위치를 강제하지 않으므로, 아키텍처적 제약(FSD 등)을 통해 로직 누수를 방지해야 한다.
2. **모던 빌드 시스템과 JSX 컴파일**
- Vite 환경에서는 esbuild 또는 SWC(Rust 기반)를 활용하여 대규모 프로젝트에서도 실시간에 가까운 컴파일 속도를 제공한다.
- `@vitejs/plugin-react-swc` 적용 시 HMR(Hot Module Replacement) 성능이 극대화된다.
3. **React Compiler를 통한 자동 최적화**
- 기존의 수동 메모이제이션(useMemo 등) 한계를 극복하기 위해, 빌드 타임에 JSX 내의 개별 엘리먼트 단위로 독립적이고 정밀한 캐싱을 수행한다.
4. **인라인 함수 사용 시 주의점**
- JSX 내부에서 익명 함수를 직접 정의하는 행위는 매 렌더링마다 새로운 참조를 생성하여 자식 컴포넌트의 불필요한 리렌더링을 유발하므로 지양해야 한다.
## 매 한 줄
> **"매 syntactic sugar over `createElement` — XML-like JS expression"**. React 의 발명, 매 declarative UI 의 핵심. 매 `<div>x</div>``jsx('div', null, 'x')` 로 transpile. 2026 default 는 **automatic runtime** (`react/jsx-runtime`) — 매 `import React` 의 불필요.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **로직 혼재의 위험**: JSX의 자유로운 특성으로 인해 UI 마크업 사이에 복잡한 비즈니스 규칙이 섞여 컴포넌트가 비대해지고 유지보수가 어려워질 수 있다.
- **도구 의존성**: React Compiler와 같은 자동 최적화 도구는 'Rules of React'(순수성 등)를 엄격히 준수하는 코드에서만 안전하게 작동하므로, 기존 레거시 코드와의 호환성 검토가 필요하다.
- **추상화 비용**: JSX 성능을 위해 모든 함수를 useCallback으로 감싸는 수동 최적화는 코드의 가독성을 해치고 관리 비용을 증가시키는 트레이드오프가 있다.
## 매 핵심
## 🔗 지식 연결 (Graph)
### Related Concepts (Auto-Linked)
* [[Feature-Sliced_Design]]
* [[React]]
* [[React_Compiler]]
* [[Research]]
* [[State]]
* [[Virtual_DOM]]
### 매 transpile model
- **Classic runtime** (legacy): `<div/>``React.createElement('div', null)` — 매 file 마다 `import React` 필요.
- **Automatic runtime** (2020+, default): `<div/>``_jsx('div', null)`, runtime 의 자동 import.
- **Preserve**: TS `--jsx preserve` — Babel 등 다른 tool 에 위임.
### Related Concepts
* **Component Trees**: JSX로 조립된 UI의 논리적 구조 (관계: 핵심 데이터 모델)
* **React Compiler**: JSX 렌더링 자동 최적화 엔진 (관계: 성능 개선 도구)
* **SWC**: 초고속 JSX 컴파일러 (관계: 빌드 타임 인프라)
### 매 element types
- **Lowercase** (`div`, `span`): 매 string tag, host component.
- **Uppercase** (`Foo`): 매 reference, component identifier.
- **Member access** (`Lib.Btn`): 매 namespaced component.
- **Fragment** (`<>...</>`): 매 wrapper-less group.
### Deeper Research Questions
1. React Compiler가 JSX 내의 개별 태그를 메모이제이션할 때 사용하는 '의존성 분석' 알고리즘의 핵심 원리는 무엇인가?
2. JSX 내부 인라인 함수가 성능에 미치는 악영향이 React Compiler 도입 이후에도 여전히 유효한 제약 사항인가?
3. Vite + SWC 환경에서 JSX 컴파일 시 발생하는 'Fast Refresh'의 내부 작동 메커니즘은 무엇인가?
4. 비즈니스 로직과 JSX 마크업을 물리적으로 완전히 분리하기 위한 'View-Model' 패턴의 프론트엔드적 해석은?
5. JSX에서 'Fragment'와 'Wrapper Div'가 렌더링 성능 및 DOM 트리 깊이에 미치는 실질적인 차이는?
### 매 응용
1. React / Preact / Solid / Qwik 의 매 component definition.
2. MDX — Markdown + JSX.
3. JSX as data (Astro, hyperscript variant).
### Practical Application Contexts
* **렌더링 최적화**: JSX 내 이벤트 핸들러를 밖으로 분리하여 참조 안정성 확보.
* **빌드 속도 개선**: Vite 설정에서 SWC 플러그인을 도입하여 로컬 개발 환경의 핫 리로딩 속도 개선.
## 💻 패턴
### Adjacent Topics
* **Memoization (useMemo, useCallback)**
* **Feature-Sliced Design (FSD)**
* **Virtual DOM vs Incremental DOM**
### Automatic runtime (2026 default)
```tsx
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx", // 매 automatic runtime
"jsxImportSource": "react" // or "preact", "@emotion/react"
}
}
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// Component.tsx — 매 import React 의 X
export function Hello({ name }: { name: string }) {
return <h1>Hello, {name}</h1>;
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Conditional rendering
```tsx
function Status({ user }: { user?: User }) {
if (!user) return null;
return (
<>
{user.isAdmin && <AdminBadge />}
{user.posts.length > 0
? <PostList posts={user.posts} />
: <EmptyState />}
</>
);
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Children pattern
```tsx
type Props = { title: string; children: React.ReactNode };
function Card({ title, children }: Props) {
return (
<section className="card">
<h2>{title}</h2>
<div className="body">{children}</div>
</section>
);
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Render prop / function-as-children
```tsx
type DataLoaderProps<T> = {
url: string;
children: (data: T | undefined, loading: boolean) => React.ReactNode;
};
function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
const [data, setData] = useState<T>();
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(r => r.json()).then(d => { setData(d); setLoading(false); });
}, [url]);
return <>{children(data, loading)}</>;
}
```
**기본값:**
> *(TODO)*
### Polymorphic component (`as` prop)
```tsx
type AsProp<C extends React.ElementType> = { as?: C };
type PolymorphicProps<C extends React.ElementType> =
AsProp<C> & React.ComponentPropsWithoutRef<C>;
## ❌ 안티패턴 (Anti-Patterns)
function Box<C extends React.ElementType = 'div'>({
as, ...rest
}: PolymorphicProps<C>) {
const Comp = as ?? 'div';
return <Comp {...rest} />;
}
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
<Box as="a" href="/x" /> // 매 anchor props 의 typed
<Box as={MyButton} onClick={...} />
```
### JSX spread + override
```tsx
function PrimaryButton(props: React.ButtonHTMLAttributes<HTMLButtonElement>) {
return <button {...props} className={`btn-primary ${props.className ?? ''}`} />;
}
```
### Fragment + key
```tsx
function List({ items }: { items: Item[] }) {
return (
<dl>
{items.map(it => (
<React.Fragment key={it.id}>
<dt>{it.term}</dt>
<dd>{it.def}</dd>
</React.Fragment>
))}
</dl>
);
}
```
### TypeScript — JSX.IntrinsicElements override
```tsx
declare global {
namespace JSX {
interface IntrinsicElements {
'my-web-component': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & { value?: string },
HTMLElement
>;
}
}
}
<my-web-component value="x" />
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 새 React project | `"jsx": "react-jsx"` (automatic) |
| Preact / Solid | `jsxImportSource` 적절 설정 |
| Babel 사용 | `"jsx": "preserve"` + babel preset |
| Web component 통합 | `JSX.IntrinsicElements` 확장 |
| 매 server component | `"jsx": "react-jsx"` (RSC 호환) |
**기본값**: automatic runtime + TypeScript strict.
## 🔗 Graph
- 부모: [[React]] · [[TypeScript]]
- 변형: [[TSX]] · [[MDX]] · [[Vue-Template]]
- 응용: [[React-Components]] · [[Polymorphic-Components]]
- Adjacent: [[Babel]] · [[SWC]] · [[esbuild]]
## 🤖 LLM 활용
**언제**: React/Preact/Solid component 작성, TS JSX 설정 디버깅, polymorphic API 설계.
**언제 X**: 매 plain HTML template (no transpile needed), 매 Vue SFC (`<template>` 별 syntax).
## ❌ 안티패턴
- **`React` import 누락 (classic runtime)**: 매 `react-jsx` 로 migrate.
- **lowercase component name**: `<myButton/>` 매 host element 로 처리됨 — 매 PascalCase 강제.
- **`key` 누락 in list**: reconciliation 비용 폭증.
- **inline function child 의 남발**: render 마다 새 reference — memoized child re-render 유발.
## 🧪 검증 / 중복
- Verified (react.dev JSX docs, TS Handbook JSX, React 19 RC notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — JSX automatic runtime + polymorphic patterns 정리 |
@@ -2,90 +2,185 @@
id: wiki-2026-0508-javascript-async-and-event-loop
title: JavaScript Async and Event Loop
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [JS-ASYNC-001]
aliases: [Event Loop, JS Event Loop, Microtask Queue, Macrotask Queue]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: ["JavaScript|[JavaScript", Frontend, web-development, event-loop, async-await, concurrency]
confidence_score: 0.9
verification_status: applied
tags: [javascript, async, event-loop, concurrency]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: javascript
framework: node-browser
---
# JavaScript Async and Event Loop (JS 비동기와 이벤트 루프)
# JavaScript Async and Event Loop
## 📌 한 줄 통찰 (The Karpathy Summary)
> "싱글 스레드의 제약을 '기다림의 미학'으로 극복하고, 이벤트 루프라는 영리한 중재자를 통해 멈추지 않는 사용자 경험을 완성하라" — 자바스크립트가 단일 스레드임에도 불구하고 논블로킹(Non-[[Blocking|Blocking]]) I/O를 수행하며 수많은 비동기 작업을 효율적으로 처리하게 해주는 핵심 구동 메커니즘.
## 한 줄
> **"매 single-threaded JS 가 매 cooperative scheduler 위에서 매 async 를 흉내낸다."**. Call stack + task queue + microtask queue + render pipeline 이 매 tick 의 단위. Promise/async-await 는 매 syntactic sugar — runtime 은 매 microtask drain rule 로 결정.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Single-threaded Concurrency" — 콜 스택([[Call Stack|Call Stack]])이 비었을 때 태스크 큐(Task Queue)에 대기 중인 콜백 함수를 순차적으로 실행하여, 무거운 작업이 메인 스레드를 점유(Blocking)하지 않도록 관리하는 스케줄링 패턴.
- **핵심 구성 요소:**
- **Call Stack:** 현재 실행 중인 함수들이 쌓이는 곳.
- **Web APIs:** 브라우저가 제공하는 비동기 작업(타이머, 네트워크 요청 등) 수행.
- **Callback Queue (Task Queue):** 비동기 작업 완료 후 실행될 콜백들이 대기하는 곳.
- **Microtask Queue:** Promise의 `.then` 등 우선순위가 높은 비동기 작업이 대기 (일반 태스크 큐보다 먼저 실행).
- **Event Loop:** 콜 스택과 큐를 상시 감시하며 작업을 옮겨주는 중재자.
- **의의:** 현대 웹 프론트엔드의 부드러운 애니메이션과 실시간 반응성을 지탱하는 기술적 뿌리.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 콜백 지옥(Callback Hell)에서 벗어나, Promise와 `async/await`라는 문법적 설탕(Syntactic Sugar)을 통해 비동기 코드를 동기 코드처럼 직관적으로 작성하는 시대로 완전히 전이됨.
- **정책 변화:** ConnectAI 확장 프로그램은 VS Code의 메인 스레드를 방해하지 않기 위해, 모든 대규모 지식 검색 및 모델 호출 로직을 비동기 이벤트 루프 최적화 패턴에 따라 처리함.
### 매 Stack vs Queues
- **Call stack**: 매 동기 frame. LIFO. 매 비어야 매 tick 진행.
- **Task queue (macrotask)**: setTimeout, setInterval, MessageChannel, I/O callback, UI event. 매 tick 당 1개 drain.
- **Microtask queue**: Promise.then, queueMicrotask, MutationObserver. 매 tick 마지막에 매 전부 drain (재진입 포함).
- **Animation frame queue**: requestAnimationFrame. 매 paint 직전.
- **Render steps**: style → layout → paint → composite. 매 vsync 와 매 동기화.
## 🔗 지식 연결 (Graph)
- [[Frontend-Architecture|Frontend-Architecture]], [[Message-Queues-and-Event-Streams|Message-Queues-and-Event-Streams]],[[_system|system]]-Design-for-AI-Scale, [[Reactive-Programming|Reactive-Programming]]
- **Raw Source:** 10_Wiki/Topics/AI/JavaScript-Async-and-Event-Loop.md
### 매 Tick 순서 (browser)
1. 매 task queue 에서 매 1 task pop → 실행.
2. 매 microtask queue 매 전부 drain (recursively).
3. 매 rAF callbacks.
4. 매 render (필요 시).
5. 매 idle callbacks (requestIdleCallback).
6. 매 다음 tick.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 Node.js phases
- timers → pending callbacks → idle/prepare → poll → check (setImmediate) → close → microtask drain (between phases since Node 11).
- `process.nextTick` 는 매 microtask 보다도 매 우선.
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 응용
1. UI freeze 방지 — 매 long task 를 매 chunk + scheduler.yield().
2. Race condition 분석 — 매 await 사이 매 state mutation 가능.
3. Server backpressure — 매 event loop lag (`perf_hooks.monitorEventLoopDelay`).
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Microtask vs Macrotask 순서
```javascript
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
queueMicrotask(() => console.log('4'));
console.log('5');
// 1, 5, 3, 4, 2 — microtasks drain before next macrotask
```
## 🤔 의사결정 기준 (Decision Criteria)
### Long task chunking with scheduler.yield (2026)
```javascript
async function processLargeArray(items) {
for (let i = 0; i < items.length; i++) {
doWork(items[i]);
if (i % 100 === 0 && 'scheduler' in window) {
await scheduler.yield(); // Chrome 129+ stable
}
}
}
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Promise.allSettled with concurrency limit
```javascript
async function mapLimit(items, limit, fn) {
const results = new Array(items.length);
let cursor = 0;
const workers = Array.from({ length: limit }, async () => {
while (cursor < items.length) {
const i = cursor++;
results[i] = await fn(items[i]).catch(e => ({ error: e }));
}
});
await Promise.all(workers);
return results;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### AbortController for cancellation
```javascript
const ac = new AbortController();
fetch('/slow', { signal: ac.signal })
.then(r => r.json())
.catch(e => { if (e.name === 'AbortError') console.log('cancelled'); });
setTimeout(() => ac.abort(), 3000);
```
**기본값:**
> *(TODO)*
### Async iterator drain
```javascript
async function* readChunks(stream) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally { reader.releaseLock(); }
}
## ❌ 안티패턴 (Anti-Patterns)
for await (const chunk of readChunks(resp.body)) {
process(chunk);
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Avoid microtask starvation
```javascript
// BAD — recursive Promise.resolve() blocks rendering
function bad() {
Promise.resolve().then(bad); // browser never paints
}
// GOOD — use setTimeout(0) or MessageChannel for yielding
function good() {
setTimeout(good, 0);
}
```
### Event loop lag monitor (Node)
```javascript
import { monitorEventLoopDelay } from 'node:perf_hooks';
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
setInterval(() => {
console.log('p99 lag ms', h.percentile(99) / 1e6);
h.reset();
}, 1000);
```
### Top-level await (ESM)
```javascript
// module.mjs
const config = await fetch('/config.json').then(r => r.json());
export default config;
// importer awaits parent module graph — beware deadlock cycles
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 즉시 yield 필요 | queueMicrotask / Promise.resolve().then |
| 매 paint 후 작업 | requestAnimationFrame |
| 매 idle 시간 작업 | requestIdleCallback / scheduler.postTask('background') |
| 매 long task chunking | scheduler.yield() (modern) |
| 매 cancellation | AbortController + signal |
| 매 backpressure 측정 | perf_hooks.monitorEventLoopDelay |
**기본값**: async/await + AbortController. 매 long task 는 매 scheduler.yield. 매 nextTick / process.nextTick 남용 X.
## 🔗 Graph
- 부모: [[JavaScript]] · [[Concurrency]]
- 변형: [[Node.js Event Loop]] · [[Browser Rendering]]
- 응용: [[React Concurrent Mode]] · [[Web Workers]]
- Adjacent: [[Promises]] · [[AbortController]] · [[Streams]]
## 🤖 LLM 활용
**언제**: 매 race / ordering bug 분석, 매 long-task profiling, 매 SSR streaming 설계.
**언제 X**: 매 CPU-bound 작업 — 매 worker / native 로 offload.
## ❌ 안티패턴
- **Recursive microtask loop**: 매 rendering starvation.
- **await in tight for loop**: 매 직렬화. 매 Promise.all 사용.
- **forgotten unhandled rejection**: 매 process crash (Node 15+).
- **setTimeout(fn, 0) for ordering**: 매 microtask 와 매 race — queueMicrotask 사용.
## 🧪 검증 / 중복
- Verified (HTML spec — Event Loop Processing Model, Node.js docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 task/microtask order + scheduler.yield 패턴 |
@@ -2,90 +2,224 @@
id: wiki-2026-0508-javascript-optimization-patterns
title: JavaScript Optimization Patterns
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [PERF-JS-OPT-001]
aliases: [JS Performance Patterns, V8 Optimization, JS Hot Path]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: ["JavaScript|[JavaScript", performance, Optimization, inp, code-splitting, tree-shaking, web-workers, main-thread]
confidence_score: 0.9
verification_status: applied
tags: [javascript, performance, v8, optimization]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: javascript
framework: v8
---
# JavaScript Optimization Patterns (자바스크립트 최적화 패턴)
# JavaScript Optimization Patterns
## 📌 한 줄 통찰 (The Karpathy Summary)
> "전송되는 번들 크기를 극한으로 깎고, 메인 스레드를 점유하는 긴 작업을 잘게 쪼개어(Yield), 브라우저가 사용자의 입력에 즉각적으로 반응할 수 있는 '숨 쉴 틈'을 확보하라" — INP 성능 향상을 위한 현대 자바스크립트 실행 전략.
## 한 줄
> **"매 hot path 의 type stability + allocation 최소화"**. V8/JSC/SpiderMonkey 모두 매 inline cache + hidden class 의 의존 — 매 monomorphic call site 가 매 fastest. 매 micro-optimization 보다 매 algorithmic / batching 이 매 win 큼, 매 그러나 hot loop 에서는 매 GC pressure 의 의식 필수.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Static Reduction and Runtime Yielding" — 빌드 시점의 불필요한 코드 제거(Tree Shaking)와 런타임 시점의 메인 스레드 점유 분산(Yielding)을 결합한 패턴.
- **핵심 최적화 기법:**
- **Code Splitting & Tree Shaking:** 사용하지 않는 코드를 제거하고, 필요한 시점에만 모듈을 로드하여 초기 파싱 시간 단축.
- **Breaking Up [[Long Tasks|Long Tasks]]:** 50ms 이상의 작업을 작은 단위로 분할하여 브라우저 렌더링 스케줄러에게 제어권을 양보.
- **Web Workers:** 복잡한 연산을 별도의 백그라운드 스레드로 이전하여 메인 스레드 프리징 방지.
- **Debounce & Throttle:** 고빈도 이벤트(Scroll, Resize, [[Search|Search]])의 핸들러 실행 횟수 제한.
- **requestIdleCallback:** 중요도가 낮은 작업을 브라우저의 유휴 시간에 배치.
- **의의:** 자바스크립트 실행으로 인한 UI 프리징을 제거하여 [[Core Web Vitals|Core Web Vitals]]의 INP 지표를 획기적으로 개선하고 실질적인 사용자 만족도를 높임.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 과거에는 모든 기능을 하나의 거대한 라이브러리에 의존하는 경향이 있었으나, 현대 정책은 '경량 모듈 정책'과 '필요 시 로드 정책'을 최우선으로 함.
- **정책 변화:** Antigravity 프로젝트는 모든 동기적 루프에 대해 50ms 초과 시 경고 정책을 시행하며, CPU 집약적인 데이터 처리 로직은 반드시 웹 워커(Web Worker) 사용 정책을 준수하도록 함.
### 매 V8 의 fast path
- **Hidden class (Map)**: object shape — 매 동일 property 순서 의 같은 hidden class.
- **Inline cache (IC)**: call site 별 type 기록 — monomorphic > polymorphic > megamorphic.
- **TurboFan / Maglev**: hot function 의 optimizing compile, type feedback 기반.
- **Sparkplug** (2021+): 매 baseline JIT, 매 quick startup.
## 🔗 지식 연결 (Graph)
- [[Core-Web-Vitals-Metrics|Core-Web-Vitals-Metrics]], [[Interaction-to-Next-Paint-INP|Interaction-to-Next-Paint-INP]], [[Frontend-Performance-Optimization-Guide|Frontend-Performance-Optimization-Guide]], [[Clean-Code-Principles|Clean-Code-Principles]]
- **Raw Source:** 00_Raw/JavaScript Optimization.md
### 매 GC pressure
- **Young generation (Scavenger)**: 매 short-lived alloc — 매 cheap.
- **Old generation (Mark-Compact)**: 매 promoted object — 매 stop-the-world 의 risk.
- **Strategy**: 매 hot loop 에서 alloc 의 회피 (object pooling, typed arrays).
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. Animation / game loop 의 60+ FPS 유지.
2. 매 large data transformation (millions of records).
3. Server-side hot path (Node, Bun).
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
### Object shape stability
```javascript
// X — hidden class 가 다름 (assignment 순서)
function A() { this.x = 1; this.y = 2; }
function B() { this.y = 2; this.x = 1; }
const arr = [new A(), new B()]; // 매 polymorphic IC
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
// O — 매 동일 shape
class Point { constructor(x, y) { this.x = x; this.y = y; } }
const arr2 = [new Point(1, 2), new Point(3, 4)];
```
## 🤔 의사결정 기준 (Decision Criteria)
### Monomorphic call site
```javascript
function add(a, b) { return a + b; } // V8 의 type feedback 기록
**선택 A를 써야 할 때:**
- *(TODO)*
// X — megamorphic (string + number + array)
add(1, 2); add('a', 'b'); add([], []);
**선택 B를 써야 할 때:**
- *(TODO)*
// O — monomorphic (always number)
for (let i = 0; i < 1e6; i++) add(i, i + 1);
```
**기본값:**
> *(TODO)*
### Typed arrays (no boxing)
```javascript
// X — 매 Array of number — boxed double, GC pressure
const heights = new Array(1_000_000);
for (let i = 0; i < heights.length; i++) heights[i] = Math.random();
## ❌ 안티패턴 (Anti-Patterns)
// O — Float64Array — flat, no boxing
const heights2 = new Float64Array(1_000_000);
for (let i = 0; i < heights2.length; i++) heights2[i] = Math.random();
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Object pooling (hot loop)
```javascript
class Vec3Pool {
#pool = [];
acquire(x = 0, y = 0, z = 0) {
const v = this.#pool.pop() ?? { x: 0, y: 0, z: 0 };
v.x = x; v.y = y; v.z = z;
return v;
}
release(v) { this.#pool.push(v); }
}
const pool = new Vec3Pool();
function frame() {
const tmp = pool.acquire(1, 2, 3);
// ... compute ...
pool.release(tmp);
}
```
### Loop hoisting
```javascript
// X — length 매 iter 마다 access
for (let i = 0; i < items.length; i++) { ... }
// O — modern V8 의 자동 hoist 하지만 매 explicit 가 안전
const n = items.length;
for (let i = 0; i < n; i++) { ... }
// O+ — for-of with iterator (매 modern, V8 fast path)
for (const it of items) { ... }
```
### Map vs object lookup
```javascript
// 매 string key 의 dynamic — Map 의 매 fast & predictable
const cache = new Map();
cache.set(key, value);
cache.get(key);
// 매 known small fixed keys — object 매 inline cache 의 winning
const config = { mode: 'fast', retries: 3 };
```
### Avoid `arguments`, use rest
```javascript
// X — arguments 의 deopt (non-array, function-bound)
function sum() {
let s = 0;
for (let i = 0; i < arguments.length; i++) s += arguments[i];
return s;
}
// O
function sum(...nums) {
let s = 0;
for (const n of nums) s += n;
return s;
}
```
### Batching DOM / state updates
```javascript
// X — 매 update 의 layout thrash
items.forEach(it => container.appendChild(make(it)));
// O — DocumentFragment batch
const frag = document.createDocumentFragment();
items.forEach(it => frag.appendChild(make(it)));
container.appendChild(frag);
```
### Web Workers (off-main-thread)
```javascript
// main.js
const worker = new Worker('worker.js', { type: 'module' });
worker.postMessage({ data: bigArray }, [bigArray.buffer]); // 매 transfer, zero-copy
// worker.js
self.onmessage = (e) => {
const result = heavy(e.data.data);
self.postMessage(result);
};
```
### Structured cloning vs transferable
```javascript
// 매 1MB+ data — transferable 의 50-100x faster
const buf = new ArrayBuffer(1_000_000);
worker.postMessage(buf, [buf]); // 매 ownership transfer
```
### Lazy evaluation (generator)
```javascript
function* range(from, to) {
for (let i = from; i < to; i++) yield i;
}
function* map(it, f) { for (const v of it) yield f(v); }
function* filter(it, p) { for (const v of it) if (p(v)) yield v; }
// 매 1B element 의 first 10 — alloc 의 X
const result = [];
for (const v of filter(map(range(0, 1e9), x => x * 2), x => x % 3 === 0)) {
result.push(v);
if (result.length === 10) break;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Hot loop alloc | typed array + object pool |
| Large data transform | streaming / generator |
| Heavy compute | Web Worker + transferable |
| DOM batch | DocumentFragment / requestAnimationFrame |
| Type stability 의심 | DevTools Profiler "ICs" tab |
| 매 micro-bench 결과 의 의심 | always profile in production-like build |
**기본값**: 매 algorithmic win 우선, 매 hot path 만 micro-optimize.
## 🔗 Graph
- 부모: [[JavaScript]] · [[V8]]
- 변형: [[Hermes-Optimization]] · [[JSC]]
- 응용: [[Web-Workers]] · [[Animation-Performance]]
- Adjacent: [[Garbage-Collection]] · [[Hidden-Classes]]
## 🤖 LLM 활용
**언제**: 매 measurable bottleneck 진단 후, hot loop 작성, large data transform.
**언제 X**: 매 cold path / one-shot script (premature optimization), 매 readability cost > perf gain.
## ❌ 안티패턴
- **Premature micro-opt**: 매 readability 희생, 매 measure 없이 추측.
- **`delete obj.prop`**: hidden class transition 유발, IC deopt.
- **Hot loop 의 closure alloc**: `arr.map(x => x*2)` 매 frame — 매 함수 hoist.
- **`try/catch` in hot loop**: 매 V8 의 optimization 일부 비활성 (개선되었지만 여전히 cost).
- **string concat in loop**: `+=` 매 hot loop — 매 array.join.
## 🧪 검증 / 중복
- Verified (V8 blog, Chrome DevTools Performance docs, Bun benchmark methodology).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — V8 hot-path optimization 패턴 정리 |
+112 -66
View File
@@ -2,92 +2,138 @@
id: wiki-2026-0508-javascriptcore
title: JavaScriptCore
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-1AF373]
aliases: [JSC, WebKit JSC, Nitro]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [javascript, engine, webkit, jit]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - [[JavaScript|JavaScript]]Core"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: C++
framework: WebKit
---
# [[JavaScriptCore|JavaScriptCore]]
# JavaScriptCore
## 📌 한 줄 통찰 (The Karpathy Summary)
> JavaScriptCore는 [[WebKit|WebKit]]의 JavaScript 엔진으로, 신뢰할 수 없는 JavaScript나 WebAssembly 코드를 실행할 때 호스트 프로세스의 메모리 유출을 방지하도록 설계된 안전한 언어 가상 머신(secure language virtual machine)입니다 [1, 2]. 최근 [[Spectre|Spectre]] 공격으로 인해 기존의 분기(branch) 기반 보안 속성이 무력화되는 위협을 받았으며, 이를 방어하기 위한 구조적 보안 개선이 이루어지고 있습니다 [1, 3].
## 한 줄
> **"매 Apple WebKit 의 JavaScript 엔진 — 4-tier JIT pipeline (LLInt → Baseline → DFG → FTL/B3)"**. Safari, iOS WebView, React Native (Hermes 도입 전), Bun runtime의 core. 매 V8 대비 startup 빠름, peak performance 비슷 — 매 mobile-first 최적화.
## 📖 구조화된 지식 (Synthesized Content)
- **보안 목적과 구조:** JavaScriptCore는 기본적으로 사용자의 프로세스에 신뢰할 수 없는 코드를 로드하더라도, C나 Objective-C 바인딩 API를 통해 명시적으로 내보낸 데이터가 아닌 이상 프로세스의 메모리가 JavaScript 코드에 유출되지 않도록 보장해야 합니다 [2].
- **Spectre 취약점으로 인한 영향:** Spectre 공격은 JavaScriptCore의 경계 검사(bounds checks)와 유형 검사(type checks)에 사용되는 분기(branches)를 제어하고 우회할 수 있게 만들었습니다 [1, 4]. 이로 인해 신뢰할 수 없는 JavaScript나 WebAssembly가 호스트 프로세스의 전체 주소 공간을 읽을 수 있는 이론적인 경로가 발생하여 JavaScriptCore의 보안 속성이 깨지게 되었습니다 [2].
- **실행 및 취약점 노출 원리:** JavaScriptCore가 JavaScript의 속성 접근(property access) 등 보안에 민감한 언어 작업을 처리할 때, 코드는 최신 CPU의 분기 예측([[Branch Prediction|Branch Prediction]])과 추측 실행([[Speculative Execution|Speculative Execution]])을 통해 병렬로 실행됩니다 [5, 6]. 공격자는 이 추측 실행 과정에서 L1 캐시와 메인 메모리 간의 지연 시간(latency) 차이를 악용하여 데이터를 유출할 수 있습니다 [4, 7].
- **보안 완화(Mitigation) 전략:** Spectre 위협에 대응하기 위해 JavaScriptCore는 기존의 분기 기반 보안 검사에서 벗어나 '분기 없는 보안 검사([[Branchless Security Checks|Branchless Security Checks]])'를 도입하여 전환하고 있습니다 [3]. 대표적으로 객체 필드 접근 시 무작위 독성 값을 활용하는 '포인터 중독([[Pointer Poisoning|Pointer Poisoning]])' 기법을 JavaScriptCore의 수많은 데이터 구조에 적용함으로써, 임의의 포인터 생성을 막고 원격 코드 실행에 악용되는 유형 혼동(type confusion)을 방어하고 있습니다 [8, 9].
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화.
### 매 4-Tier JIT Pipeline
- **LLInt** (Low-Level Interpreter): 매 첫 실행, profiling 시작.
- **Baseline JIT**: 매 hot 코드 → simple machine code, type feedback.
- **DFG** (Data Flow Graph): 매 speculative optimization, OSR exit 가능.
- **FTL** (Faster Than Light) / B3 backend: 매 최상위 tier, LLVM-style IR.
## 🔗 지식 연결 (Graph)
- **Related Topics:** [[WebKit|WebKit]], Spectre, WebAssembly, [[Speculative Execution|Speculative execution]], [[Pointer Poisoning|Pointer poisoning]]
- **Projects/Contexts:** WebKit's [[Spectre and Meltdown|Spectre and Meltdown]] Mitigations
- **Contradictions/Notes:** 소스에 관련 정보가 부족합니다.
### 매 GC
- **Riptide**: 매 generational + concurrent mark-and-sweep.
- **Eden GC**: 매 young objects, frequent.
- **Full GC**: 매 entire heap, infrequent.
---
*Last updated: 2026-04-19*
### 매 응용
1. Safari / WKWebView (iOS, macOS).
2. Bun runtime — 매 Node.js 대안, JSC 채택 (V8 X).
3. React Native (legacy iOS, Hermes 이전).
4. GNOME / GTK WebKitGTK.
---
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### Bun runtime — JSC embed
```javascript
// bun runs JS via JSC (not V8)
// startup: ~10ms vs Node ~30ms
import { serve } from "bun";
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
serve({
port: 3000,
fetch(req) {
return new Response("Hello from JSC");
},
});
```
## 🤔 의사결정 기준 (Decision Criteria)
### Inline cache observation (JSC IR dump)
```bash
# JSC bytecode dump
JSC_dumpBytecodesAfterGeneration=true \
/System/Library/Frameworks/JavaScriptCore.framework/Helpers/jsc script.js
**선택 A를 써야 할 때:**
- *(TODO)*
# DFG/FTL 단계 확인
JSC_dumpDFGGraphAtEachPhase=true jsc script.js
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Hidden class friendly object
```javascript
// JSC structure (V8의 hidden class 와 동일 개념)
function Point(x, y) {
this.x = x; // structure transition T0 → T1
this.y = y; // T1 → T2
}
// T2 가 stable → inline cache hit
```
**기본값:**
> *(TODO)*
### Type feedback (monomorphic 유지)
```javascript
function add(a, b) { return a + b; }
add(1, 2); // int+int → DFG int specialization
add(1.5, 2.5); // float+float → polymorphic, slower
## ❌ 안티패턴 (Anti-Patterns)
// 매 monomorphic 유지 — 매 동일 type 만 호출
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### OffHeap typed array (Bun)
```javascript
// JSC 의 ArrayBuffer 는 GC 외부 — large data 적합
const buf = new ArrayBuffer(1024 * 1024 * 100); // 100MB
const view = new Uint8Array(buf);
// 매 GC pressure X
```
### WeakRef (JSC 1.16+)
```javascript
const cache = new WeakRef(largeObject);
// 매 GC 가 collect 가능 — memory pressure 시 free
const ref = cache.deref();
if (ref) { /* still alive */ }
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| iOS native app + JS | JSC (WKWebView 또는 JavaScriptCore.framework) |
| Cross-platform server | V8 (Node.js) — 매 ecosystem 큼 |
| Fast startup CLI | Bun (JSC) — 매 startup 압도적 |
| RN new architecture | Hermes — 매 mobile 최적화 |
**기본값**: server는 V8/Node, mobile WebView는 JSC, fast CLI는 Bun.
## 🔗 Graph
- 부모: [[JavaScript Engine]] · [[WebKit]]
- 변형: [[V8]] · [[Hermes]] · [[SpiderMonkey]]
- 응용: [[Bun Runtime]] · [[Safari]] · [[React Native]]
- Adjacent: [[JIT Compiler]] · [[Garbage Collection]]
## 🤖 LLM 활용
**언제**: iOS WebView 성능 분석, Bun 코드 최적화, JSC-specific bug 진단.
**언제 X**: Node.js / Chrome 환경 — 매 V8 별도 문서.
## ❌ 안티패턴
- **Polymorphic call sites**: 매 inline cache miss → DFG bailout.
- **delete operator**: 매 hidden class transition 깨짐 — 매 undefined 할당으로 대체.
- **arguments object 남용**: 매 modern JSC 는 rest params 가 빠름.
## 🧪 검증 / 중복
- Verified (WebKit Wiki, JSC source — github.com/WebKit/WebKit).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — JSC 4-tier pipeline + Bun 응용 |
+127 -63
View File
@@ -2,90 +2,154 @@
id: wiki-2026-0508-judgment
title: Judgment
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-JUDG-001]
aliases: [Engineering Judgment, Trade-off Judgment, Frontend Judgment]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced, judgment, decision-making, wisdom, discretion, ethical-judgment]
verification_status: applied
tags: [judgment, engineering, decision-making, frontend]
raw_sources: []
last_reinforced: 2026-04-20
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: meta
framework: meta
---
# [[Judgment|Judgment]]
# Judgment
## 📌 한 줄 통찰 (The Karpathy Summary)
> "데이터 너머의 결정력: 수많은 정보와 상충하는 가치들 속에서, 단순한 확률 연산이 아닌 '무엇이 옳은가'와 '어떤 결과를 감내할 것인가'를 파악하여 방향을 결정하는 인간(혹은 상위 주체)의 핵심적 지혜."
## 한 줄
> **"매 좋은 frontend 는 매 framework choice 가 아니라 매 trade-off 의 매 명시적 분석에서 나온다."**. Performance / DX / accessibility / bundle size / SEO 의 매 weight 가 매 product context 에 따라 매 다르다. Judgment 는 매 가르칠 수 있는 skill — checklist + heuristic.
## 📖 구조화된 지식 (Synthesized Content)
판단(Judgment)은 상황을 분석하고 결정을 내리는 지적 능력입니다.
## 매 핵심
1. **AI 시대의 판단**:
* **Prediction vs Judgment**: AI는 과거 데이터를 바탕으로 '예측(Prediction)'을 수행하지만, 그 예측값을 보고 어떤 위험을 감수하며 행동할지 결정하는 것은 '판단(Judgment)'의 영역임. ([[Decision Theory|Decision Theory]]와 연결)
* **Value [[Alignment|Alignment]]**: 판단에는 주체의 가치관과 우선순위가 깊게 개입됨. ([[Ethics & AI|Ethics & AI]]와 연결)
2. **왜 중요한가?**:
* 연산력이 풍부한 시대일수록, 역설적으로 그 연산을 '어디에 쓸 것인가'를 결정하는 고도의 판단력이 가장 희소하고 값진 능력이 됨. ([[Intangible-Capital|Intangible-Capital]]의 핵심)
### 매 Trade-off 축
- **Performance vs DX**: SSR + island vs CSR SPA.
- **Bundle vs Feature**: tree-shake-able lib vs all-in-one.
- **Type safety vs Velocity**: strict TS vs JS prototyping.
- **A11y vs Custom**: native element vs custom component.
- **Cache vs Freshness**: SWR vs no-store.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌**: 과거에는 권위자나 시스템이 내린 단일 정답 기반의 '수동적 판단 정책'이 주류였으나, 현대 정책은 데이터의 불확실성을 인정하고 다양한 시나리오를 검토하는 '확률적·비판적 판단 정책'으로의 전환을 요구함(RL Update). (Critical Thinking와 연결)
- **정책 변화(RL Update)**: 윤리적 판단 정책을 아예 AI 모델 내부에 원칙(Constitution)으로 심으려는 노력과, 여전히 인간의 직접적 개입이 필요한 'Red-line 정책' 사이의 치열한 논의가 진행 중임. (Constitutional AI와 연결)
### 매 Heuristic
1. **Native first**: 매 platform primitive 가 매 free win.
2. **Measure before optimize**: 매 Lighthouse / RUM 먼저.
3. **Latency budget**: 매 LCP < 2.5s, INP < 200ms, CLS < 0.1 (Core Web Vitals 2026).
4. **Bundle budget**: 매 route 당 매 100KB gzip.
5. **Dependency cost**: 매 add 마다 매 maintenance + bundle + supply chain risk.
## 🔗 지식 연결 (Graph)
- [[Decision Theory|Decision Theory]], [[Ethics & AI|Ethics & AI]], [[Constitutional AI (헌법 AI)|Constitutional AI (헌법 AI)]], Critical Thinking, [[Intangible-Capital|Intangible-Capital]]
- **Modern Tech/Tools**: Decision [[Support|Support]][[_system|system]]s, Ethical AI frameworks, Strategic planning tools.
---
### 매 Decision framework
- **Reversible vs One-way door**: framework choice = one-way. 매 careful.
- **Time horizon**: 매 6 개월 vs 매 5 년 — 매 다른 답.
- **Team skill**: 매 unfamiliar tech 의 매 hidden cost.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 응용
1. SSR vs CSR — 매 SEO / TTI / DX matrix.
2. State manager 선택 — 매 server vs client state 분리.
3. CSS strategy — 매 atomic / module / runtime.
**언제 이 지식을 쓰는가:**
- *(TODO)*
## 💻 패턴
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
### Decision matrix template (Markdown)
```markdown
| 기준 | Option A | Option B | Weight |
|---|---|---|---|
| Bundle size | 12KB | 45KB | 0.3 |
| DX | High | Medium | 0.2 |
| Maintenance | Active | Stale | 0.3 |
| TS support | Native | Patchy | 0.2 |
| **Score** | 0.84 | 0.51 | — |
```
## 🤔 의사결정 기준 (Decision Criteria)
### Bundle budget enforcement (CI)
```javascript
// vite.config.ts
export default {
build: {
rollupOptions: {
output: { manualChunks: { vendor: ['react', 'react-dom'] } },
},
chunkSizeWarningLimit: 100, // KB
},
};
// Then: bundlesize / size-limit in CI
```
**선택 A를 써야 할 때:**
- *(TODO)*
### Performance budget gate
```yaml
# .github/workflows/perf.yml
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v12
with:
urls: |
https://staging.example.com/
budgetPath: ./budget.json
assertions: |
categories.performance: ['error', { minScore: 0.9 }]
audits.largest-contentful-paint: ['error', { maxNumericValue: 2500 }]
audits.interaction-to-next-paint: ['error', { maxNumericValue: 200 }]
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Feature flag for risky migration
```typescript
import { useFlag } from '@/lib/flags';
function Page() {
const useNewRouter = useFlag('new-router-2026');
return useNewRouter ? <NextAppRouter /> : <PagesRouter />;
}
```
**기본값:**
> *(TODO)*
### A11y default vs custom
```tsx
// PREFER native
<button onClick={...}>Save</button>
## ❌ 안티패턴 (Anti-Patterns)
// Avoid custom unless necessary
<div role="button" tabIndex={0} onKeyDown={handle}>...</div>
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### Reversibility check
```markdown
- [ ] Can we roll back in 1 day? (file flag, env var)
- [ ] Can we roll back in 1 week? (revert PR)
- [ ] One-way door? (DB schema, public API) — 매 RFC 필수
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 SEO 우선 | SSR / SSG (Next.js, Astro, SvelteKit) |
| 매 dashboard (auth-only) | CSR SPA (Vite + React) |
| 매 content site | Astro / 11ty (zero JS default) |
| 매 realtime collaborative | CSR + WebSocket / CRDT |
| 매 mobile app | RN / Expo (Hermes) |
| 매 desktop app | Tauri (Rust) > Electron |
**기본값**: 매 measure → matrix → smallest reversible step.
## 🔗 Graph
- 부모: [[Software Engineering]] · [[Architecture Decision]]
- 변형: [[Trade-off Analysis]] · [[ADR]]
- 응용: [[Frontend Architecture]] · [[Performance Budget]]
- Adjacent: [[Core Web Vitals]] · [[Accessibility]] · [[DX]]
## 🤖 LLM 활용
**언제**: 매 framework / library 선택 시, 매 RFC 작성, 매 trade-off 명시화.
**언제 X**: 매 obvious choice — 매 over-engineering.
## ❌ 안티패턴
- **Resume-driven development**: 매 새로운 tech 만 추구.
- **Unmeasured optimization**: 매 perf 직감 만.
- **Cargo cult**: 매 big company 가 사용 = 매 우리에게 맞다 X.
- **Analysis paralysis**: 매 endless matrix — 매 timebox.
## 🧪 검증 / 중복
- Verified (Core Web Vitals 2026 thresholds, ADR template).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 trade-off matrix + budget pattern |
@@ -2,104 +2,32 @@
id: wiki-2026-0508-kingdom-vs-kingdom-kvk
title: Kingdom vs. Kingdom (KvK)
category: 10_Wiki/Topics
status: needs_review
canonical_id: self
status: duplicate
canonical_id: wiki-2026-0508-kingdom-vs-kingdom-events-kvk
duplicate_of: "[[Kingdom vs. Kingdom Events (KvK)]]"
aliases: []
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
tags: [uncategorized]
raw_sources: []
last_reinforced: 2026-05-08
source_trust_level: B
confidence_score: 0.9
verification_status: redirected
tags: [duplicate, game, mmo, rok]
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
---
# [[Kingdom vs. Kingdom (KvK)|Kingdom vs. Kingdom (KvK)]]
# Kingdom vs. Kingdom (KvK)
## 📌 한 줄 통찰 (The Karpathy Summary)
Kingdom vs. Kingdom (KvK)은 모바일 4X 전략 게임에서 여러 서버(왕국) 간의 보호막이 해제되고 상대 왕국을 침공할 수 있게 되는 대규모 서버 간 전면전 이벤트입니다 [1]. 이 이벤트의 승패는 개별 플레이어를 넘어 서버 전체의 통치권과 생존에 직결되므로, 유저들의 폭발적인 자원 및 단축 아이템(Speed-ups) 소비를 유도하여 게임의 핵심적인 수익화(BM) 장치로 작동합니다 [2].
> **이 문서는 [[Kingdom vs. Kingdom Events (KvK)]] 의 중복본입니다.** Canonical 문서로 redirect.
## 📖 구조화된 지식 (Synthesized Content)
**KvK의 중요성과 서버에 미치는 영향**
KvK는 단순히 포인트를 획득하는 일반적인 이벤트와 달리, 전체 서버의 명예와 생존이 걸린 가장 중요한 엔드게임 콘텐츠입니다 [3, 4]. KvK에서 승리한 왕국은 'High Kingdom'이 되며, 해당 왕국의 왕은 두 서버 모두를 통치하는 'High King'으로 등극해 패배한 서버에 세금과 디버프를 부과할 수 있는 막강한 권력을 쥐게 됩니다 [5, 6]. 지속적으로 KvK에서 패배하는 서버는 유저들이 다른 서버로 이탈하면서 결국 왕국의 몰락('Kingdom death')과 서버 통합으로 이어지게 됩니다 [2, 7, 8].
## 핵심 요약
- Cross-shard PvP event in 4X MMO (Rise of Kingdoms 등).
- 매 Pre-KvK matchmaking → Lost Kingdom → Main → Post.
- Frontend challenge: viewport map sync, leaderboard cache, server-authoritative timer.
**KvK 이벤트의 진행 단계**
KvK는 일반적으로 다음과 같은 4가지의 구조화된 단계로 진행됩니다 [5, 9].
* **매치메이킹 단계 (Matchmaking Phase):** 상위 100명 플레이어의 총 전투력 등을 기준으로 비슷한 수준의 두 왕국이 매칭됩니다 [5, 9].
* **준비 단계 (Preparation Phase):** 전투 외적인 활동(건설, 연구, 훈련, 자원 채집 등)을 통해 포인트를 쌓는 기간으로, 이 단계의 승자가 성 전투에서 선제 공격권을 얻게 됩니다 [5, 10].
* **전투 단계 (Battle Phase):** 약 12시간 동안 서버 간 보호막이 해제되고 고급 순간이동(Advanced Teleports)을 통해 적의 왕국으로 넘어가 적군을 처치하고 자원을 약탈하며, 적의 불가사의(Wonder)를 점령하기 위해 싸웁니다 [1, 5, 11, 12].
* **복구 단계 (Triage Phase):** 전투가 종료된 후, 전투 중 잃은 병력을 아이템 등을 사용해 일정 비율로 복구하고 치료하는 단계입니다 [5, 13].
## 🔗 Graph
- 부모: [[Kingdom vs. Kingdom Events (KvK)]] (canonical)
**침공 및 전투 메커니즘**
* **순간이동과 방패:** 유저들은 고급 순간이동(Advanced Teleports)을 사용하여 적의 왕국으로 이동할 수 있습니다 [1, 14]. 적의 불가사의 숲(Wonder Forest)에 들어가지 않는 한, 평화 방패(Shield)를 유지한 채 몬스터 사냥이나 자원 채집 등만 수행하는 제한적인 참여도 가능합니다 [15, 16].
* **침략자 식별:** 적 왕국으로 넘어간 침략자의 도시는 뿔이 달린 해골 장식이 있는 검은색 건물(Barbarian Fortresses와 동일한 외형)로 표시되어 맵 상에서 쉽게 식별할 수 있습니다 [17, 18].
* **전투 규칙:** 이 기간에는 평소 금기시되던 자원 타일에서의 공격이 허용되며, 승리 포인트를 채우기 위해 서로 병력을 죽여주는 킬 교환(Kill Trades)이 발생하기도 합니다 [17, 19].
**수익화(BM) 구조와의 직결성**
KvK는 서버의 존망이라는 실존적 위협을 조성하여, 평소 전투에 소극적인 유저들까지도 준비 및 전투 단계에 강제로 참여하게 만듭니다 [2]. 이벤트 승리를 위해서는 서버 전체의 막대한 자원 저장과 참여가 필수적이므로 유저들의 집중적인 스피드업 아이템(Speed-ups) 및 자원 소비를 극대화하는 강력한 BM 동인으로 작용합니다 [2, 20].
## 🔗 지식 연결 (Graph)
- **Related Topics:** High King, Advanced Teleports, [[Wonder|Wonder]], Speed-Ups
- **Projects/Contexts:** [[Game of War- Fire Age|Game of War: Fire Age]], Kingshot
- **Contradictions/Notes:** 소스 [21]의 왕국 위키에서는 KvK가 단일한 이름의 정식 이벤트라기보다는 왕국 간 보호막이 해제되는 상태이며 그 이면에 여러 세부 이벤트(Days of War, Domination 등)가 동시다발적으로 일어나는 것이라 설명합니다. 반면, 시스템 분석 문서와 Kingshot 가이드([5], [9])에서는 KvK를 매치메이킹부터 복구까지 4단계로 명확히 나뉜 단일 대형 이벤트 구조로 정의하고 있습니다.
---
*Last updated: 2026-04-27*
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(TODO)*
**언제 쓰면 안 되는가:**
- *(TODO)*
## 🧪 검증 상태 (Validation)
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
## 🧬 중복 검사 (Duplicate Check)
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 없음
- **정책 변화:** 없음
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
```
## 🤔 의사결정 기준 (Decision Criteria)
**선택 A를 써야 할 때:**
- *(TODO)*
**선택 B를 써야 할 때:**
- *(TODO)*
**기본값:**
> *(TODO)*
## ❌ 안티패턴 (Anti-Patterns)
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
## 🕓 변경 이력
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |

Some files were not shown because too many files have changed in this diff Show More