bodalab/doc/figma-specs/README.md

100 lines
7.6 KiB
Markdown

# Figma 섹션별 스펙 JSON 모음
## 왜 이 폴더가 있는가
`figma-mcp``add_figma_file` 도구는 **항상 문서 전체**(`01_HOME`부터)를 JSON으로 덤프하고, URL에 `node-id`를 넣어도 무시한다. 파일이 커서 도구 결과 토큰 한도(약 25,000 토큰)에 걸려 `03_HISTORY` 중반에서 항상 잘리기 때문에, `04_VISION`부터는 이 방법으로 데이터를 받은 적이 없었다.
대신 Figma REST API의 `nodes` 엔드포인트는 `ids` 파라미터로 **노드 하나만 스코프해서** 받을 수 있다. `.mcp.json`에 이미 설정된 `FIGMA_API_KEY`로 직접 호출하면 섹션당 수십 KB 수준이라 잘리지 않는다.
```bash
curl -s -H "X-Figma-Token: $FIGMA_API_KEY" \
"https://api.figma.com/v1/files/MnwN1Uzg5F6ks9Clr1brLW/nodes?ids=<node-id>" \
-o "<name>.json"
```
`$FIGMA_API_KEY`는 프로젝트 루트 `.mcp.json``mcpServers.figma.env.FIGMA_API_KEY` 값이다 (`.mcp.json`은 `.gitignore` 대상이라 이 문서에는 실제 키를 적지 않는다).
## 파일 구성
섹션마다 두 파일이 있다:
- `*.json` — Figma REST API 원본 응답 (필요시 정확한 수치를 다시 뽑을 수 있는 원천 데이터)
- `*.txt` — 그 안의 모든 TEXT 노드를 `"내용" — 폰트크기 / weight / 색상` 형태로 평탄화한 요약 (빠르게 훑어볼 때 사용)
`.txt`는 아래 스크립트로 재생성한다 (JSON을 재호출할 필요 없이 로컬에서 즉시 재실행 가능):
```bash
python3 << 'EOF'
import json, glob
def rgb(c):
a = c.get('a', 1)
return f"#{round(c['r']*255):02x}{round(c['g']*255):02x}{round(c['b']*255):02x}" + (f" a{a}" if a < 1 else "")
def walk(node, depth=0, out=None):
out = out if out is not None else []
if node.get('type') == 'TEXT':
style = node.get('style', {})
fills = node.get('fills', [])
color = rgb(fills[0]['color']) if fills and fills[0].get('color') else '?'
chars = node.get('characters', '')[:40].replace('\n', '\\n')
out.append(f"{' '*depth}- \"{chars}\" — {style.get('fontSize')}px / weight {style.get('fontWeight')} / {color}")
for child in node.get('children', []):
walk(child, depth + 1, out)
return out
for f in sorted(glob.glob("*.json")):
with open(f) as fh:
data = json.load(fh)
node_id = list(data['nodes'].keys())[0]
doc = data['nodes'][node_id]['document']
lines = walk(doc)
with open(f.replace('.json', '.txt'), 'w') as fh:
fh.write(f"# {f} (node {node_id})\n\n")
fh.write('\n'.join(lines))
EOF
```
## 섹션 / 노드 ID 매핑
File key: `MnwN1Uzg5F6ks9Clr1brLW`
| 섹션 | PC node-id | PC 파일 | Mobile node-id | Mobile 파일 |
|---|---|---|---|---|
| 01 HOME | `2247:2094` | [01-home-pc.json](01-home-pc.json) / [.txt](01-home-pc.txt) | `2319:2232` | [01-home-mobile.json](01-home-mobile.json) / [.txt](01-home-mobile.txt) |
| 02 ABOUT US (Expertise 포함) | `2247:2230` | [02-about-pc.json](02-about-pc.json) / [.txt](02-about-pc.txt) | `2319:2288` | [02-about-mobile.json](02-about-mobile.json) / [.txt](02-about-mobile.txt) |
| 03 HISTORY | `2247:2121` | [03-history-pc.json](03-history-pc.json) / [.txt](03-history-pc.txt) | `2319:2433` | [03-history-mobile.json](03-history-mobile.json) / [.txt](03-history-mobile.txt) |
| 04 VISION | `2247:2183` | [04-vision-pc.json](04-vision-pc.json) / [.txt](04-vision-pc.txt) | `2319:4183` | [04-vision-mobile.json](04-vision-mobile.json) / [.txt](04-vision-mobile.txt) |
| 05 PROJECT | `2247:2202` | [05-project-pc.json](05-project-pc.json) / [.txt](05-project-pc.txt) | `2319:4231` | [05-project-mobile.json](05-project-mobile.json) / [.txt](05-project-mobile.txt) |
| 06 CONTACT/FOOTER (문서상 라벨은 "Expertise"지만 실제 내용은 CONTACT/FOOTER) | `2247:2253` | [06-contact-pc.json](06-contact-pc.json) / [.txt](06-contact-pc.txt) | `2319:5082` | [06-contact-mobile.json](06-contact-mobile.json) / [.txt](06-contact-mobile.txt) |
| GNB 모바일 드로어 (열린 상태) | — | — | `2319:5998` | [gnb-drawer-mobile.json](gnb-drawer-mobile.json) / [.txt](gnb-drawer-mobile.txt) |
## Components 캔버스 (디자인 시스템 원본)
문서에는 `Screen Pages` 캔버스 말고 **`Components` 캔버스(id `12:92`)**가 별도로 있다. 버튼/인풋/체크박스/GNB/footer/프로젝트 카드/배지/아이콘 등 32개 컴포넌트의 "원본" 정의가 여기 있고, 페이지 정적 렌더에는 안 보이는 호버/액티브 같은 variant도 포함되어 있다.
- [07-components.json](07-components.json) — 캔버스 전체 원본 (32개 컴포넌트, ~600KB)
- [07-components.txt](07-components.txt) — 컴포넌트별로 배경색/보더/radius/padding/gap/텍스트 스타일을 평탄화한 요약
`.txt`는 위 스크립트와 다른(배경·보더·radius·padding까지 같이 뽑는) 별도 스크립트로 생성했다 — 필요하면 같은 패턴으로 재생성 가능 (`fills`/`strokes`/`cornerRadius`/`paddingLeft` 등 노드 속성을 그대로 읽으면 됨).
## NEW 섹션의 형제 노드 (footer / 팝업 모달 / 동작 주석)
`MAIN_NEW_PC`, `MAIN_NEW_MO` 프레임 말고도 `NEW` 섹션 바로 아래에 화면에는 안 보이는 노드들이 더 있었다 (문서 전체를 `depth=4`로 한 번 훑어서 발견함). 자세한 내용과 구현 영향은 **[11-interaction-notes.md](11-interaction-notes.md)** 참고.
- [08-footer-instance-pc.json](08-footer-instance-pc.json) — footer 전용 인스턴스 (`2247:2294`). 예전 기록엔 "footer 전용 노드 없음"이라 되어있었는데 실제로는 있었음 (내용은 기존 구현과 일치, 수정 불필요).
- [09-privacy-modal-pc.json](09-privacy-modal-pc.json) / [09-privacy-modal-mobile.json](09-privacy-modal-mobile.json) — 개인정보 수집·이용 동의 모달 (`2319:2118` / `2376:2184`). **현재 코드에 미구현.**
- [10-history-duplicate-ref.json](10-history-duplicate-ref.json) — HISTORY 중복 프레임(`2301:1896`, 참고용 사본으로 추정, 내용은 03-history-pc와 동일).
- [11-interaction-notes.md](11-interaction-notes.md) — 디자이너가 텍스트 노트로 남긴 동작 스펙 모음 (아코디언 단일열림, PROJECT/태그 더보기 페이지네이션, SEND 버튼 유효성 검증 등). **다수가 현재 코드에 미구현 상태.**
## 완전성 체크 (2026-06-28 기준)
- `GET /v1/files/:key?depth=4` 로 문서 전체 캔버스/섹션 구조를 확인함 → 캔버스는 `Screen Pages`, `Components` 2개뿐, `NEW` 섹션의 직계 자식도 전부 나열해서 확인함 (위 footer/모달/주석 포함).
- 이미 받은 13개 섹션 `.txt` 안에 동작 주석이 섞여있는지 `grep`으로 재검색함 → 없음 (06-contact의 "동의" 매칭은 이미 아는 체크박스 라벨 텍스트).
-**스타일(폰트/색상/간격/보더) 스펙은 사실상 전부 확보**, **동작(behavior) 스펙도 이번에 전부 찾아서 11-interaction-notes.md에 정리**. 단, 이미지/비트맵 자산은 여전히 미포함(사용자가 직접 export), 이 모든 건 캡처 시점 스냅샷이라 Figma 원본이 바뀌면 재동기화 필요.
## 사용 시 주의
- 좌표는 모두 Figma 캔버스 절대좌표(`absoluteBoundingBox`)다. CSS 값으로 옮길 때는 같은 프레임 안의 다른 좌표와의 **차이**(간격, 오프셋)로 환산해서 써야 한다 — 절대값 자체를 그대로 px로 쓰면 안 된다.
- 프레임 폭은 PC 1920px / Mobile 390px 캔버스 기준이다. `clamp()`로 반응형 값을 만들 때는 `(figma px / 캔버스 폭) * 100` 으로 `vw` 비율을 환산한다.
- 이 JSON은 캡처 시점(2026-06-28) 스냅샷이다. Figma 원본이 그 뒤에 수정됐다면 재호출해서 갱신해야 한다.