diff --git a/CLAUDE.md b/CLAUDE.md
index 76da158..0037d41 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,37 +1,23 @@
-# drawing3d-web — 작업 규칙 (Haiku 세션용)
+# drawing3d-web — 작업 규칙 (Haiku)
-원형 수직구 일반도를 라이브러리 없이 Canvas 2D 로 보여 주는 3D 뷰어. 설계는 `SPEC.md`, 할 일은 `FEATURES.json`.
+규약은 `SPEC.md`. **작업 목록과 설계 배경은 Gitea 이슈(tdc_engineer/drawing3d-web)에 있다.**
-## 시작할 때마다
-1. `PROGRESS.md` 마지막 5줄과 `git log --oneline -5` 를 읽는다.
-2. `FEATURES.json` 에서 `"passes": false` 인 **맨 앞 기능 하나**만 고른다. 두 개를 같이 하지 않는다.
-3. 그 기능의 `steps` 와 SPEC 의 해당 장을 읽고 시작한다.
+## 시작
+1. 지시받은 이슈를 **제목이나 번호로 찾아 그 이슈만** 읽는다. 다른 이슈·긴 문서를 미리 다 읽지 않는다.
+2. `git log --oneline -5` 를 본다.
-## 실행과 검증
-- 화면 보기: `explorer.exe index.html` (Windows 브라우저로 열림). 수석이 화면을 확인한다.
-- 판정: `bash check.sh F0n` (n = 지금 기능 번호). 그 기능과 앞 기능 항목이 전부 `[PASS]` 여야 끝이다.
-- 끝났다고 말할 때는 **check.sh 출력 전체를 그대로 붙인다.** 요약하거나 고쳐 쓰지 않는다.
-
-## 끝낼 때 (기능 1개 = 커밋 1개)
-1. `FEATURES.json` 에서 그 기능의 `passes` 만 `true` 로 바꾼다. 다른 글자는 건드리지 않는다.
-2. `PROGRESS.md` 에 한 줄 추가(양식은 파일 첫 줄).
-3. `git add -A` 후 커밋. 메시지 첫 줄 `F0n: 한 일`, 본문에 check.sh 마지막 줄.
-4. 다음 기능으로 넘어가지 말고 수석에게 보고하고 멈춘다.
+## 끝 (이슈 하나 = 커밋 하나)
+1. `bash check.sh` 가 FAIL 0 이어야 끝이다. 아니면 커밋하지 않고 멈춰 보고한다.
+2. 커밋 메시지 첫 줄 끝에 `(#이슈번호)`, 본문에 check.sh 마지막 줄과 `Co-Authored-By` 줄.
+3. 이슈 댓글(완료 기준 확인 표·검사 결과·커밋 해시·경위 한 줄)과 push·이슈 닫기는 **지시가 있을 때만** 한다.
## 금지
-- `check.sh`, `SPEC.md`, `CLAUDE.md` 수정 금지. 틀렸다고 생각되면 고치지 말고 수석에게 말한다.
-- three.js 등 라이브러리, CDN, `import`, `require`, 외부 URL 금지. 파일은 index.html, viewer.js, model.js, README.md, .gitignore, guide/ (구동설명서 HTML), tools/prep_drawing.py, tools/extract_from_dxf.py, model_extracted.js, compare.html. F33~F34 에서는 model.js 를 고치지 않는다.
-- 도면은 `private/` 의 공개용 정리본만 커밋한다: `drawing.dxf`·`drawing.svg`·`drawing_gen.svg` (SPEC 34장). 원본 DWG·`full.dxf`·지명·과업명·실제 좌표가 든 파일은 절대 커밋하지 않는다. `git add -A` 전에 `git status` 로 확인한다.
-- `model.js` 는 `const MODEL = ` 뒤에 순수 JSON(따옴표 키, 주석·끝 쉼표 없음) 그리고 `;`.
-- 커밋 메시지의 `Co-Authored-By` 줄을 지우지 않는다. `--no-verify`, `--amend`, `rebase`, 날짜 지정 금지.
-- 실패한 시도도 커밋을 지우지 않는다. 되돌릴 때는 새 커밋으로.
-- 원본 도면 파일(DWG·정리 전 DXF), 회사 파일명, 비밀값을 리포에 넣지 않는다.
-
-## 코드
-- 순수 JavaScript 한 파일(viewer.js). 함수 이름은 SPEC 7장 목록을 쓴다.
-- 길이 단위는 mm, z 위로 +. 각도는 X축에서 반시계, 도.
-- 면 = 점 배열 + 색 + alpha. 먼 면부터 그린다.
+- `check.sh`·`SPEC.md`·`CLAUDE.md` 수정. 틀렸다고 생각되면 고치지 말고 보고한다.
+- 검사를 통과시키려고 파일을 숨기거나 검사를 우회하기.
+- 화면 코드의 라이브러리·CDN·import·외부 URL. 도구는 표준 라이브러리만.
+- 정리본 3개(`private/drawing.dxf`·`drawing.svg`·`drawing_gen.svg`) 밖의 도면, 원본 DWG, 지명·과업명·실제 좌표, 비밀값 커밋. `git add -A` 전에 `git status`.
+- `model.js` 는 `const MODEL = ` 뒤 순수 JSON 과 `;`.
+- `Co-Authored-By` 줄 지우기, `--no-verify`·`--amend`·`rebase`·날짜 지정, 실패한 커밋 지우기.
## 막히면
-- 같은 문제를 두 번 고쳐도 안 되면 멈추고 수석에게 무엇이 안 되는지 보고한다.
-- 모르는 치수는 지어내지 않는다. SPEC 에 없으면 수석에게 묻는다.
+같은 문제를 두 번 고쳐도 안 되면 멈추고 무엇이 안 되는지 보고한다. 모르는 치수는 지어내지 않는다.
diff --git a/SPEC.md b/SPEC.md
index 9179f27..4d0d7cd 100644
--- a/SPEC.md
+++ b/SPEC.md
@@ -1,615 +1,40 @@
-# SPEC — 전력구 수직구 3D 뷰어 (MVP)
+# drawing3d-web 설계 규약
-> 🔒 사내교육용 — 열람 외 재배포 등의 활동을 금함 (회사 도면의 치수를 옮겨 적음)
-> 설계 면담(수석 + 코치 세션, 2026-10-19~20)으로 확정. 이 파일은 하이쿠가 고치지 않는다.
+지금 지켜야 할 규약만 둔다. **작업 목록·설계 배경·결정 이력은 Gitea 이슈**에 있고, 옛 설계서(34장)는 git 이력(9068b6c)에 남아 있다.
-## 1. 목적
-원형 수직구 일반도 한 장을 **라이브러리 없이** 브라우저 3D 화면으로 보여 준다.
-청중은 교육 담당자와 동료이고, 3분 시연에서 아래 세 문장을 화면을 돌려 가며 말할 수 있으면 끝이다.
-1. 외경 11m, 깊이 70.3m 원통이다.
-2. 안에 슬래브 19장 + 하부 슬래브가 있고, 층마다 계단이 지그재그로 내려간다.
-3. 바닥 근처 19B 층에서 4시 방향으로 TBM 터널(내경 2.6m)이 나가고, 터널 바닥 패드와 19B 패드 상면 높이가 같다.
+## 1. 무엇
+원형 수직구 일반도(DWG) 한 장을 도구가 읽어 3D 데이터(`model_extracted.js`)와 도면 그림(`private/drawing_gen.svg`)을 만들고, `index.html` 이 라이브러리 없이 Canvas 2D 로 보여 준다. `model.js` 는 손으로 만든 정답 모델 — 검사 기준이자 `answer.html` 화면.
-## 2. 범위
-| 넣는 것 | 빼는 것 (범위 밖) |
+## 2. 좌표·단위
+mm, z 위 +, 지표 z 0. 각도는 X축에서 반시계, 도. 모델 XY 는 슬래브 평면 틀이다(평면도는 −30.3° 돌아 있어 views 의 `rot_deg`). 도면 DXF 좌표는 공개용으로 평행이동된 값이다.
+
+## 3. 데이터 형식
+`const MODEL = {순수 JSON};` — `units` "mm", `parts[]`, `drawing{src, viewBox, fit, section, plan, views[]}`.
+부재 공통 `id·kind·type·name·color`. type 별:
+
+| type | 필드 |
|---|---|
-| 벽체, 중간 슬래브 19장, 19B 패드, 하부 슬래브, 바닥콘크리트 | 상부 분기구·환기구·관로, 지표→1B 구간의 계단·설비 |
-| 계단 18런(1B→19B) | 슬래브 개구부(계단·케이블 slot·펌프 배출구 구멍), 방호 난간 |
-| TBM 터널 세그먼트(속 빈 원통) + 터널 안 잡석·패드 2단 | 집수정 사다리, 집수조·침사조·월류벽, 배관 |
-| 등각 초기 화면, 드래그 회전, 휠 확대, 벽 반투명 | 프리셋 뷰, 클릭 선택·속성 패널, 표시/숨김, 축·그리드, 단면, 치수 라벨, PNG 저장 |
-
-## 3. 좌표계와 단위
-- 데이터의 길이는 모두 **mm**, 각도는 **도**.
-- 원점 = 수직구 축 중심 × 지표면(구조물 상단). **Z 위로 +**, 땅속은 음수.
-- X = 평면도 오른쪽, Y = 평면도 위쪽. 수평 각도는 **X축에서 반시계**(시계의 3시 = 0°, 12시 = 90°, 4시 = 330°).
-
-## 4. 부재와 치수
-### 4.1 벽체·바닥
-| 부재 | 형태 | 치수 |
-|---|---|---|
-| 벽체 | 속 빈 원통 | 외경 11,000(r 5,500), 내경 9,700(r 4,850), z −70,200 ~ 0 |
-| 하부 슬래브(BOTTOM, 20B) | 원판 | r 4,850, z −70,200 ~ −69,000 (두께 1,200, 벽 안쪽) |
-| 바닥콘크리트 | 원판 | r 5,500(= 벽 외경, 슬러리월 안에서 타설), z −70,300 ~ −70,200 (두께 100) |
-
-### 4.2 중간 슬래브 (원판, r 4,850, 두께 300)
-슬래브 상면 z. 하면 = 상면 − 300.
-
-| 층 | 상면 z | 층 | 상면 z | 층 | 상면 z |
-|---|---|---|---|---|---|
-| 1B | −7,400 | 8B | −30,500 | 15B | −53,600 |
-| 2B | −10,700 | 9B | −33,800 | 16B | −56,900 |
-| 3B | −14,000 | 10B | −37,100 | 17B | −60,200 |
-| 4B | −17,300 | 11B | −40,400 | 18B | −63,500 |
-| 5B | −20,600 | 12B | −43,700 | 19B | −66,200 |
-| 6B | −23,900 | 13B | −47,000 | | |
-| 7B | −27,200 | 14B | −50,300 | | |
-
-규칙: 1B = −7,400(지표에서 5,400+500+1,300+200). 1B~18B 는 3,300 간격. 18B→19B 2,700. 19B→하부 슬래브 상면 2,800. 총높이 70,300.
-
-### 4.3 19B 패드
-원판, 벽 안쪽면에서 100 떨어짐 → r 4,750(지름 9,500), z −66,200 ~ −66,100 (두께 100).
-
-### 4.4 계단 (18런)
-- 런 i 는 i 층 슬래브(위)에서 i+1 층 슬래브(아래)로 내려간다. i = 1~18 (마지막 런은 18B→19B).
-- 단 높이 200, **맨 아래 첫 단만 100**. 디딤판 깊이 300. 폭 1,000.
- - 층고 3,300 → 단 수 17(= 100 + 200×16), 디딤판 16장, 런 길이 4,800
- - 층고 2,700(런 18) → 단 수 14(= 100 + 200×13), 디딤판 13장, 런 길이 3,900
-- 계단은 디딤판마다 **블록**(아래 슬래브 상면부터 그 디딤판 높이까지 꽉 찬 상자)으로 쌓는다.
-- 위치 (🔶 확인 필요 — 코치 추론):
- - 런의 윗끝 = 위 슬래브의 계단 개구부 가장자리. 개구부(4,200)는 X 가운데 −2,100 ~ +2,100 으로 본다.
- - 홀수 런: 윗끝 x = −2,100, 내려가며 +X 방향, Y 띠 −1,000 ~ 0.
- - 짝수 런: 윗끝 x = +2,100, 내려가며 −X 방향, Y 띠 0 ~ +1,000.
-- 블록 k(아래부터 1, 2, …, 단 수−1)의 윗면 z = 아래 슬래브 상면 + 100 + 200×(k−1). 맨 위 단(200)은 위 슬래브로 올라선다.
-- 블록 k 의 X 구간: 윗끝 x 에서 (단 수−1−k)×300 ~ (단 수−k)×300 만큼 내려가는 방향으로 떨어진 곳.
-- 개구부를 그리지 않으므로 맨 위 블록이 위 슬래브 두께에 100 겹친다. MVP 에서는 받아들인다.
-
-### 4.5 TBM 터널
-- 방향 330°(평면도 4시). 축 높이 z −65,050.
-- 세그먼트: 속 빈 원통, 두께 200, 내경 2,600(r 1,300), 외경 3,000(r 1,500).
-- 원통은 **벽 안쪽면(r 4,850)에서 시작**해 벽을 관통하고 벽 바깥면에서 20,000 더 나간다 → 길이 20,650. 시작점 = (4,850·cos330°, 4,850·sin330°, −65,050).
- - 근거(수석): 세그먼트가 벽체 개구부의 거푸집 역할을 해 18B 슬래브와 19B 벽체부를 동시 타설한다. 그래서 세그먼트 천장 외면(−63,550)이 18B 슬래브 두께(−63,800 ~ −63,500) 안에 들어가는 것은 실제 형태다.
-- 높이 검산: 세그먼트 바닥 외면 −66,550(= 19B 슬래브 하면 −66,500 − 50) → 내면 −66,350 → 잡석 상면 −66,225 → 패드 상면 −66,100 = **19B 패드 상면**.
-- 터널 안 채움(누운 원통 속을 높이까지 채움). 높이 v 는 터널 축에서 잰 값(위 +).
-
-| 채움 | v 범위 | 폭 제한 |
-|---|---|---|
-| 잡석 | −1,300 ~ −1,175 (125) | 세그먼트 안쪽 벽까지 |
-| 패드 2단(아래) | −1,175 ~ −1,100 (75) 🔶 | 세그먼트 안쪽 벽까지 |
-| 패드 1단(위) | −1,100 ~ −1,050 (50) 🔶 | 축 중심 폭 800 |
-
-🔶 확인 필요: 패드 합계 125 를 「양측 트렌치 깊이 50」에 맞춰 75 + 50 으로 나눈 것은 코치 추론.
-
-## 5. 데이터 파일 `model.js`
-- 첫 줄은 `const MODEL = ` 로 시작하고 그 뒤는 **순수 JSON**(따옴표 있는 키, 주석·끝 쉼표 없음), 마지막은 `;`. check.sh 가 이 꼴을 python 으로 읽는다.
-- 최상위: `units`("mm"), `parts`(배열).
-- 모든 부재 공통 필드: `id`(겹치지 않음), `name`(한글 이름), `kind`, `type`, `color`("#rrggbb"), `alpha`(0~1, 없으면 1).
-- `kind` 값: `wall`, `slab`, `pad`, `bottom`, `lean`, `stair`, `tunnel`, `fill`.
-
-| type | 쓰는 kind | 필드 |
-|---|---|---|
-| `ring` (세운 속 빈 원통) | wall | `cx, cy, z0, z1, r_out, r_in` |
-| `disc` (세운 원판) | slab, pad, bottom, lean | `cx, cy, z0, z1, r` (z0 아래, z1 위) |
-| `pipe` (누운 속 빈 원통) | tunnel | `x, y, z`(축 시작점), `angle_deg, length, r_out, r_in` |
-| `stair` (계단 런) | stair | `z_low, z_high, risers, first_riser, riser, tread, x_top, dir(+1/−1), y0, y1` |
-| `fill` (누운 원통 속 채움) | fill | `x, y, z, angle_deg, length`(pipe 와 같은 축), `r`(세그먼트 안쪽 반지름), `v0, v1, half_width`(0 이면 제한 없음) |
-
-부재 수: wall 1 · slab 19 · pad 1 · bottom 1 · lean 1 · stair 18 · tunnel 1 · fill 3 = 45.
-색은 자유. 단 벽은 `alpha` 0.25.
-
-## 6. 화면
-- `index.html` 을 브라우저로 **더블클릭해서 열면** 바로 보인다(서버·인터넷 불필요). 캔버스 하나가 창을 채운다.
-- 처음 화면: **등각 정사 투영**, 모델 전체(지하 70m 원통과 20m 터널)가 화면에 들어온다.
-- 마우스 드래그: 궤도 회전(좌우 = Z축 둘레, 위아래 = 기울기). 휠: 확대/축소.
-- 면은 방향에 따라 밝기가 다르다(면 음영). 먼 면부터 그린다(화가 알고리즘).
-- 원은 32각형. 벽만 반투명(0.25), 나머지는 불투명.
-
-## 7. 그리기 방식 (함수 이름 목록 — 구현은 하이쿠)
-- 부재 → 면: `facesRing`, `facesDisc`, `facesPipe`, `facesStair`, `facesFill`, `facesBox`
-- 모든 면 모으기: `buildFaces`
-- 카메라: `rotatePoint`, `project`
-- 그리기: `shadeColor`, `sortFaces`, `draw`
-- 입력: `onMouseDown`, `onMouseMove`, `onMouseUp`, `onWheel`
-- 라이브러리·외부 파일 불러오기 금지. 파일은 `index.html`, `viewer.js`, `model.js` 셋(+ README.md).
-
-## 8. 합격 기준
-### 8.1 check.sh (기계 판정)
-`bash check.sh` → 항목마다 `[PASS]`/`[FAIL]`, 전부 PASS 면 종료 코드 0. 항목 이름 앞에 기능 ID(F01…)가 붙는다.
-- 파일 셋이 있고 `index.html` 이 `model.js` 다음에 `viewer.js` 를 읽는다.
-- 외부 라이브러리 흔적이 없다(`http://`, `https://`, `import `, `require(`).
-- `model.js` 가 위 꼴의 JSON 이고, 부재 수·치수가 4장 표와 같다(허용 오차 1mm).
-
-### 8.2 수석 육안 체크리스트 (check.sh 로 못 재는 것)
-- [ ] 더블클릭으로 열린다(Chrome, Edge)
-- [ ] 첫 화면이 등각이고 모델 전체가 보인다
-- [ ] 드래그 회전·휠 확대가 된다
-- [ ] 벽 너머로 슬래브·계단·터널이 보인다
-- [ ] 계단이 층마다 방향을 바꾼다
-- [ ] 터널이 평면 4시 방향, 19B 높이에 붙어 있다
-- [ ] 1장의 세 문장을 화면으로 말할 수 있다
-
-## 9. 나중 (MVP 뒤, 시간이 남으면)
-프리셋 뷰·리셋 → 클릭 선택·속성 패널 → 부재별 표시/숨김 → 축·그리드·단위 → 슬래브 개구부 → 단면·거리·치수 라벨·PNG.
-
-## 10. 추가 — 도면 분할 화면과 도면 클릭 연결 (2026-10-20 수석 지시, F13~F15)
-### 10.1 화면 배치 (F13)
-- `index.html` 본문: 왼쪽 `#drawPane` · 가운데 세로 막대 `#splitter`(폭 6px) · 오른쪽 `#viewPane`(기존 캔버스).
-- 처음 비율 50:50. 막대를 끌면 왼쪽 폭이 바뀐다(창 폭의 15%~85%). 바뀔 때마다 캔버스 크기를 오른쪽 칸에 맞추고 다시 그린다.
-- 도면 파일은 `private/drawing.svg` 고정. `private/` 는 `.gitignore` 로 커밋하지 않는다(제출 압축에만 넣는다). 파일이 없으면 왼쪽 칸에 「도면 파일 없음 — private/drawing.svg 를 넣으세요」.
-
-### 10.2 도면 표시·확대·이동 (F14)
-- `#drawPane` 안에 `#drawStage` 하나, 그 안에 ``(도면)과 같은 크기로 겹친 인라인 `