사양 목업 (Spec mockups)
이 스킬은 그리는 방법을 설명합니다. lw-spec-write는 사양이 어디에 위치하고 페이지가 어떻게 렌더링되는지를 설명합니다.
제품 사실 (Product facts)
어댑터 폴더는 설정(config)에서 가져옵니다. 먼저 읽으세요:
ah config get harness.adapterDir
그런 다음 <adapterDir>/spec-mockup/을 읽으세요. 프로젝트가 소유하고 있습니다. 다음을 명명합니다:
| 사실 | 예시 |
|---|---|
| 각 앱의 토큰 파일 (순서대로) | apps/console/src/styles/tokens.css |
| 라이트/다크 값의 선택자 | :root, .dark |
| Lucide 아이콘 폴더 | node_modules/lucide-react/dist/esm/icons |
| 사이드바가 있는 각 앱의 내비게이션과 그 출처 | 콘솔의 라우트 테이블 |
| 실제 카피의 출처 | 앱의 i18n 카탈로그 |
어댑터가 없으면, 그리기 전에 사용자에게 토큰 파일을 요청하세요. 절대 색상을 임의로 만들지 마세요.
형식 (The format)
하나의 라이브러리로 그려진 생성된 SVG입니다: 이 파일 옆에 있는 boards.py입니다. 각 스펙에는
하나의 스크립트 docs/specs/assets/<date>-<topic>-boards.py가 있습니다. 이 스크립트는 라이브러리를 임포트하고
docs/specs/assets/<date>-<topic>/ 디렉토리에 씁니다. 생성된 SVG를 직접 수정하지 마세요: 스크립트를 변경하고
다시 실행하세요. 라이브러리에 빠진 부분이 있으면, 스크립트 옆에 있는 프로젝트 자체 헬퍼 모듈에 추가하여
다음 스펙에서도 사용할 수 있게 하세요.
example.py는 완성된 보드의 예시입니다: 데스크탑과 휴대폰에서의 페이지, 핀과 범례(legend)가 있습니다. 실행하여 모양을 확인하세요:
python3 .claude/skills/lw-spec-mockup/example.py <scratchpad>/mock --render
스펙 스크립트는 다음과 같이 시작합니다:
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
sys.path.insert(0, str(ROOT / ".claude/skills/lw-spec-mockup"))
from boards import GUTTER, Board, render, tokens
t = tokens("apps/console/src/styles/tokens.css", "light")
b = Board(1440 + 2 * GUTTER, 1200, icons="node_modules/lucide-react/dist/esm/icons")
b.title("Dashboard: the empty state")
f = b.sidebar_app(
GUTTER,
160,
t["bg"],
t["sidebar"],
t["ink"],
t["muted"],
t["active"],
["Dashboard"],
"Dashboard",
"Console",
)
b.pin(f.x + f.left + 24, f.top + 30, 1)
b.legend(
GUTTER, 1100, [(1, "The empty state", "No widget until the product names one.", "R1")], 1440
)
b.save("docs/specs/assets/<date>-<topic>/desktop-empty.svg")
| 호출 | 그리는 대상 |
|---|---|
tokens(files, theme, base=, dark=, overlay=) | 토큰 파일의 해석된 --* 값. t["accent"]. 누락된 토큰은 오류를 발생시킴. overlay는 제안된 리스타일 |
phone(x, y, bg, ink, surface, url), desktop(x, y, bg, url) | 휴대폰 (web 또는 app), 브라우저 창 |
sidebar_app(x, y, ...) | 콘솔과 같은 왼쪽 사이드바가 있는 앱. 앱의 라우트 테이블에서 nav를 복사 |
screenshot(path, x, y), crop(path, ...) | 출시된 화면의 실제 캡처 또는 그 일부 영역 (오늘 Today 컬럼용) |
icon(name, x, y, size, color) | 보드의 icons 폴더에서 가져온 Lucide 글리프 |
image(path, ...), embed_font(family, path) | 리포지토리의 실제 아트와 브랜드 폰트 |
pin, legend, caption, column_head, row_label, title | 노트. 두 줄을 초과하는 범례 노트는 오류를 발생시킴 |
render(svg, png, w, h) | 아래 확인을 위한 헤드리스 Chrome 스크린샷 |
충실도 (Fidelity)
- 색상은 토큰입니다.
tokens()을 통해 가져옵니다. 스펙 스크립트의 16진수 값은 잘못된 것입니다. 단, 토큰 파일에 없는 아트는 예외입니다. - 카피는 실제입니다. 앱의 카탈로그에 있는 문자열이 있으면 그것을 사용하세요. 새로운 문자열은 짧아야 합니다: 레이블, 값, 빈 상태, 오류 또는 한 줄 힌트여야 합니다.
- 데이터는 현실적입니다. 가능한 값과, 발생할 수 있는 긴 값도 사용하세요.
캔버스 (Canvas)
| 표면 | 프레임 |
|---|---|
| 휴대폰 | 390 x 844, 여백 48px |
| 데스크탑 | 1440 x 900 |
| 보드 | 프레임만큼 넓게, 행이 필요한 만큼 높게 |
스펙이 그리는 대상
- 오늘, 그다음 대상. "오늘"은 출시된 화면의 실제 스크린샷입니다 (
today-*.png). "대상"은 SVG입니다. 마크다운 테이블에 나란히 배치합니다. - 상태별 한 행씩 적용됩니다: 기본, 빈, 로딩, 오류, 긴 텍스트, 가장 작은 콘텐츠와 가장 큰 콘텐츠.
- 핀과 범례. 변경되는 각 요소에 번호가 매겨진 핀. 프레임 아래에 번호가 매겨진 범례: 굵은 제목, 최대 두 줄, 그리고 그것이 속한 스펙 ID.
- 스펙 내 보드 옆의 컴포넌트 목록: 각 요소, 재사용된 컴포넌트, 그리고 각각의 새로운 컴포넌트와 그 이유.
이름 (Names)
docs/specs/assets/<YYYY-MM-DD>-<topic>-boards.py
docs/specs/assets/<YYYY-MM-DD>-<topic>/<surface>-<state>.svg
docs/specs/assets/<YYYY-MM-DD>-<topic>/today-<surface>-<state>.png
스펙은 assets/에 있는 모든 파일의 기본 이름(base name)을 명명합니다.
커밋하기 전에 모든 보드를 확인하세요 (Look at every board before you commit it)
보드의 결함은 소스에서는 보이지 않고 그림에서 명확히 드러납니다. 각 보드를 렌더링하고
Read 도구로 PNG를 읽으세요. PNG는 docs/가 아닌 스크래치패드에 쓰세요.
- 텍스트가 프레임 밖으로 나가지 않고, 핀이 값을 덮지 않습니다.
- 그려진 UI의 모든 문자열은 레이블, 값, 빈 상태, 오류 또는 힌트입니다.
- 대체 아트가 없고, 눈으로 고른 색상이 없습니다.
- 스펙이 다루는 각 상태와 표면에 해당 프레임이 있습니다.
- 오늘과 대상이 나란히 있습니다.
render는 PATH에 google-chrome 또는 chromium이 필요합니다.
빌드 후 (After the build)
빌드는 승인된 보드와 일치해야 합니다. 빌드된 화면을 캡처하여 보드 옆에 놓으세요. 차이는 빌드의 결함이지, 보드를 다시 그릴 이유가 아닙니다.