# 10 · 에디터 설계 핵심 규칙

**언제 읽나**: 캔버스/문서 편집기를 만들거나, 좌표계·저장구조를 정할 때.
**이 파일이 보장하는 것**: 아래 7개 규칙을 지키면 "화면과 출력이 다른" 문제가 구조적으로 발생하지 않는다.

---

## 규칙 1. 좌표는 절대 "디자인 px". 레이아웃 폭은 상수.

- 요소 좌표 `{x, y, w, h}`와 폰트 `size`는 **아트보드 기준 절대 px**로 저장한다.
- 아트보드 엘리먼트의 `width`/`height`는 **문서의 디자인 px 그대로** 둔다.
- 화면 맞춤은 **부모 엘리먼트의 `transform: scale()`만** 사용한다.

❌ 금지: 아트보드 폭을 `100%`, `vw`, `calc()` 등 창 크기 종속 값으로 두는 것.
❌ 금지: 줌을 구현할 때 폭·폰트 크기를 직접 계산해 바꾸는 것.

**이유**: 폭이 창에 종속되면 줄바꿈 위치가 창 크기마다 달라진다. 그러면 규칙 2·3이 불가능해진다.

---

## 규칙 2. 내보내기는 화면 DOM을 캡처하지 않는다.

- 같은 문서 JSON을 **화면에 보이지 않는 별도 영역**에 같은 컴포넌트로 다시 렌더한 뒤 캡처한다.
- 캡처 코드는 UI 레이어(패널·툴바·핸들)를 **import하지 않는다**.

❌ 금지: 편집 중인 실제 화면을 캡처하는 것.

**이유**: 화면 캡처 방식은 아래 5개 문제를 동시에 만든다 — 캡처 중 편집 차단 필요, 선택 핸들 숨김 필요, 편집 오버레이 숨김 규칙 동기화 필요, DOM 참조 수명 관리 필요, 페이지 전환 깜빡임. 오프스크린 방식은 이 5개가 **발생하지 않는다**.

---

## 규칙 3. 텍스트를 자르지 않는다.

- 텍스트 맞춤 옵션은 **`grow`(상자가 커짐) | `shrink`(글자가 작아짐) 둘뿐**이다.
- 아트보드 안의 어떤 요소에도 텍스트용 `overflow: hidden`을 쓰지 않는다.

❌ 금지: `overflow:hidden` + "넘쳤다는 배지 표시" 조합.

**이유**: 배지를 못 보면 내용이 사라진 결과물이 그대로 나간다. 넘쳐서 보기 나쁜 것이 내용이 사라진 것보다 낫다.

---

## 규칙 4. 저장과 Undo를 요소 기능보다 먼저 만든다.

순서를 고정한다: **스캐폴드 → 저장·Undo → 조작 → 요소 → 템플릿 → 내보내기 → 배포**

- 저장: 자동저장 3중 장치 — 디바운스 1.5초 + 10초 강제 저장 + 페이지 이탈 직전 저장.
- Undo: 스냅샷 방식, 상한 50단계.

❌ 금지: "요소를 다 만들고 저장은 나중에" 순서.

**이유**: 실제로 이 순서를 어긴 프로젝트는 7단계를 모두 완료하고도 새로고침 시 전부 사라져 실사용이 불가능했다.

---

## 규칙 5. 바이너리를 문서에 넣지 않는다.

- 업로드 이미지는 **별도 저장소(에셋 슬라이스)** 에 두고, 요소는 `assetId` 문자열만 가진다.
- 업로드 시 긴 변 2048px로 리샘플한다.

❌ 금지: 문서 JSON 안에 base64 이미지 데이터를 넣는 것.

**이유**: Undo가 스냅샷 방식이라, 문서에 base64가 있으면 되돌리기 한 번마다 수 MB가 복제된다.
실측: 분리 후 4000×3000 사진을 넣어도 문서 1KB, 히스토리 6단계 3KB.

---

## 규칙 6. 테마는 고정된 키 집합의 토큰으로만 만든다.

- 모든 테마가 **정확히 같은 키**를 갖는다. 예: `bg, surface, fg, muted, mutedBg, primary, pfg, line, r, font` (10개).
- 요소는 `"@primary"` 같은 **토큰 이름**을 저장하고, 실제 색으로 바꾸는 코드는 **파일 하나**에만 둔다.

❌ 금지: 테마마다 키 개수가 다른 것.
❌ 금지: 여러 파일에서 색을 직접 해석하는 것.

**이유**: 키가 다르면 "어떤 테마에서만 깨지는" 상태가 된다. 테마 교체는 **색만** 바꿔야 하고 좌표·폰트 크기는 그대로여야 한다.

---

## 규칙 7. 캡처 라이브러리가 못 그리는 CSS는 스키마에 넣지 않는다.

제외 목록: `filter`, `mix-blend-mode`, `mask`, `backdrop-filter`.

추가하고 싶으면 **먼저 캡처해서 재현되는지 실제로 확인**한 뒤 넣는다.

---

## 폰트 규칙

- 재배포 가능한 라이선스(OFL 등) 폰트만 **파일로 직접 포함**한다.
- ❌ CDN 금지: 캡처 시점에 폰트가 도착하지 않을 수 있다.
- ❌ unicode-range 분할 금지: 로드되지 않은 구간의 글자만 다른 폰트로 찍힌다.
- ❌ 맑은 고딕·바탕·돋움 금지: 재배포 불가 라이선스다.

---

## 확인 절차 (완료라고 말하기 전에 실행)

```bash
# 1. 저장 경로가 존재하는가 — 0건이면 규칙 4 위반
grep -rn "localStorage\|beforeunload\|undo" src/ | head

# 2. 내보내기가 UI를 import하는가 — 결과가 있으면 규칙 2 위반
grep -rn "from '../panels\|from \"../panels" src/export/

# 3. 텍스트 clip이 있는가 — 결과가 있으면 규칙 3 위반
grep -rn "overflow: *hidden" src/ | grep -i "text\|artboard\|page"

# 4. 문서에 base64가 들어가는가 — 결과가 있으면 규칙 5 위반
grep -rn "base64" src/model/ src/store/
```

4개 모두 통과하지 못했으면 **완료가 아니다**. 어느 규칙을 위반했는지 보고한다.
