/cc-pixel-loop:verify — 화면이 디자인대로 나왔는지 "계산으로 대조"
화면이 Figma 시안대로 나왔는지 상태 프레임마다 라이트 · 다크로 결정적 픽셀 비교해 통과 · 실패 · 판정 불가를 정하고, 차이 이미지 · 영역별 보고서 · PR 본문용 요약을 남깁니다(코드 수정 없음). 화면 구현의 완료 판정이나 PR 전 디자인 확인에 쓰세요 — 고치며 맞추려면 /cc-pixel-loop:loop.
| 항목 | 내용 |
|---|---|
| 실행 명령 | /cc-pixel-loop:verify |
| 분류 | Flutter |
| 난이도 | ●●○ 보통 |
| MCP 서버 | figma |
한마디로#
디자이너가 그린 화면(Figma)과 앱이 그린 화면을 같은 크기 · 같은 배율로 찍어 프로그램이 점 단위로 비교하고, "같다 · 다르다 · 비교할 수 없다"를 정해 주는 검사기입니다. 코드는 고치지 않고, 어디가 어떻게 다른지 그림과 보고서로 남깁니다.
누가·언제 쓰나요#
- 디자이너 · 기획자: "지금 앱 화면이 Figma 시안과 정말 같은가?"를 눈대중이 아니라 숫자로 확인하고 싶을 때
- 개발자: 화면 구현을 끝냈다고 말하기 전, PR 을 올리기 전
- 한 화면의 상태(기본 · 로딩 · 빈 화면 · 오류)와 밝은 · 어두운 테마를 한 번에 점검할 때
무엇을 해주나요#
- 상태 프레임마다 밝은 · 어두운 테마로 비교하고, 비교마다 차이를 빨갛게 칠한 이미지(
Figma | 앱 | 차이)를 남깁니다 - 다른 곳마다 "어느 부품의 어디가 어떤 색에서 어떤 색으로" 를 적은 보고서와, PR 본문에 그대로 붙이는 요약표를 남깁니다
- 비교하지 못한 것(서체가 없다, 시안이 어두운 테마를 그릴 수 없다 …)은 통과로 바꾸지 않고 이유와 함께 남깁니다
- 차이를 직접 고치지는 않습니다 — 고치는 일은
/cc-pixel-loop:loop에 넘깁니다
어떻게 쓰나요#
# 화면 레지스트리의 섹션 하나 — 그 섹션의 상태 프레임 전부 × 라이트 · 다크
/cc-pixel-loop:verify --section "https://www.figma.com/design/<key>/<file>?node-id=12-340" --app <앱 경로>
# 섹션 여러 개 + 렌더 테스트가 사는 feature 패키지 지정
/cc-pixel-loop:verify --section <url1>,<url2> --app <앱 경로> --test-package <feature 패키지>
# 라이트만 내는 앱 — 빼는 이유를 함께
/cc-pixel-loop:verify --section <url> --app <앱 경로> --exclude-theme "dark:라이트 전용 제품(DDR-12)"
# 진단 — 이미 찍은 사진 한 장을 프레임 하나와 비교(완료 판정이 아니다)
/cc-pixel-loop:verify --frame <프레임 url> --screenshot <png> --scale 2
안에서 무슨 일이 벌어지나요#
- Figma 에서 섹션의 상태 프레임과 그 크기 · 테마 · 서체 · 상태 바를 읽습니다(읽기 전용).
- 앱이 그 서체를 갖고 있는지, 앱이 어떤 CoUI 판을 쓰는지 확인합니다.
- Figma 에서 프레임을 같은 배율로 내려받습니다. 어두운 테마는 프레임의 임시 복제본을 찍고 바로 지웁니다.
- 앱 쪽은 위젯북 상태와 같은 데이터로 같은 크기 · 배율의 사진을 그립니다(기기 없이 테스트로).
- 스크립트가 두 사진을 비교해 통과 · 실패 · 판정 불가를 정하고, AI 는 남은 차이를 설명하고 어디서 고칠지 가립니다.
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
절차 · 규칙 · 기본값의 정본은 cc-pixel-loop:visual-verify 스킬이다 — 이 커맨드는 그 스킬을 로드해 순서대로 실행하고 결과를 보고한다.
Parameters#
| Parameter | Required | Description |
|---|---|---|
--section | ✅ (또는 --frame) | 화면 레지스트리 섹션의 Figma URL(node-id) · use_case designLink 의 프레임 URL(그 섹션 전체를 읽는다). 쉼표로 여럿 |
--frame | ❌ | 단건 진단 — 프레임 하나를 --screenshot 한 장과 diff 한다. 그 프레임에 고정한 밝기 하나만, summary 없이 — 완료 판정이 아니다 |
--app | ✅ (단건 진단 제외) | 앱(워크스페이스) 루트 — fonts · coui · literals 가 읽는다 |
--test-package | ❌ | 렌더 테스트를 둘 패키지(기본: 섹션의 feature 패키지) — flutter_test_config.dart 의 글꼴 로드를 본다 |
--source | ❌ | render(기본 — 테스트 렌더) · browser(Jaspr) · device(실행 중인 앱 — 게이트의 근거로 쓰지 않음) |
--exclude-theme | ❌ | '<theme>:<이유>' — 밝기는 늘 라이트 · 다크 둘이고, 빼는 것은 이유와 함께만 |
--ignore-frame | ❌ | '<프레임 id>=<이유>' — 섹션 안의 화면이 아닌 프레임(메모 류). 이름이 「플랫폼-상태」 가 아닌 프레임은 이것 없이는 판정 불가로 남는다 |
--mask-node | ❌ | '<노드 id>=<이유>' — 계속 바뀌는 노드(스피너 · 시계 류)를 가린다 |
--scale | ❌ | 비교 배율(기본 Mobile 2 · Web 1) |
--tolerance | ❌ | pixel=1,color_delta_e=3,text_pixel=2,text_delta_e=10 (기본) |
--budget | ❌ | ratio=0.002,region=32 (기본) |
--screenshot | ❌ | 이미 찍은 PNG — 캡처를 생략하고 --frame 과만 비교 |
--base | ❌ | literals 기준 ref (기본 origin/main) |
--run-id | ❌ | 기존 실행 폴더로 다시 — Figma 쪽(plan · 내보내기)은 재사용하고 렌더 · 보고서 · 요약은 다시 만든다. 시안을 고쳤으면 새 실행 |
Phase Flow#
- 입력 —
figma:figma-use로드 후 섹션마다cc-blueprint의compare-frames.figma.js→frames-<섹션>.json. Figma 를 읽지 못하면(whoami·get_metadata실패) 아무것도 비교하지 않고undetermined:figma-unreadable로 끝낸다. - 계획 —
figma_compare.py plan. 비교가 0 이면 판정 불가로 끝낸다. - 확인 —
fonts(빠진 서체 → 판정 불가) ·coui(앱의 CoUI 릴리스 · 라이브러리와 달라진 컴포넌트). - Figma 이미지 —
download_assets(png, defaultScale)로figma/<label>.png.clone:<밝기>는dark-frames.figma.jscreate(MODE= 그 밝기 —Dark·Light) → 받기 → remove(실패해도).unthemable은 받지 않는다. - 렌더 —
--source에 따라render/<label>.png. co_golden 캡처는figma_compare.py ingest로 옮긴다. Jaspr 는 페이지가 불러온 서체를 읽어fonts --browser-fonts로 판정한다. - 비교 —
figma_compare.py diff --run --label(비교마다). - 판정 — 실패한 비교의 영역마다 고칠 자리를
judgement.json에(visual-verify5절). 이 커맨드는 고치지 않으므로app·style-slot영역은 남은 채로 보고된다. - 합계 —
literals뒤summary --check-issues.summary.md를 결과 보고에 그대로 싣는다.
Output#
.claude/docs/visual-verify/<run_id>/
├── frames-<섹션>.json · plan.json · nodes/
├── fonts.json · coui.json · literals.json · judgement.json
├── figma/<label>.png · render/<label>.png
├── reports/<label>.report.json · <label>.diff.png
└── summary.json · summary.mdFigma 대조 — fail · 비교 8 · 통과 6 · 실패 1 · 판정 불가 1
| 상품 목록 | Mobile-Default | dark | fail | 0.412% | 96.5 | 3 | 0 |
- 남음 12-345__dark node:12:357 (96.5 px²) — app: 제목 색이 라이트 값으로 남았다
- 사유: fail:diff · undetermined:comparison상태#
summary.json 의 status 는 pass · fail · undetermined 이고, 이유는 reasons[], 비교마다의 사유는 rows[].status 에 있다(visual-verify §6). 판정 불가는 통과가 아니다 — 부른 쪽(cc-dev:run Step 7.3, /cc-blueprint:build Step 5)은 그것을 실패와 따로, 정지(BLOCKED)나 사람이 확인한 스킵으로 다룬다.
단건 진단(--frame + --screenshot)은 diff 의 결과(pass · fail · undetermined:<사유>)만 보고한다 — 서체 · 덧대기 검사와 다른 밝기가 없으므로 완료 판정에 쓰지 않는다.
Related#
- Skill:
cc-pixel-loop:visual-verify— 절차 · 규칙 · 기본값의 정본 - Edit loop:
/cc-pixel-loop:loop - Figma 쪽 입력:
cc-blueprint의references/recipes/compare-frames.figma.js·dark-frames.figma.js