Figma 대조 — 기기 · 원본 연결 · 엄격 차이 보고

목표는 화면마다 엄격 픽셀 차이 3% 미만이다(Figma 「Cocode Scaffold App v1.0」 페이지 49:6). 이 문서는 그 차이를 어떤 기기로 찍고, 무엇을 가리고, 어떻게 세고, 어디서 판정하는지를 정한다. 판정 규칙의 정본은 figma-fidelity.json 하나다 — 기준 · 세는 법을 바꾸는 것은 그 파일을 바꾸는 PR 이다.

구성 자리 하는 일
화면 대장 docs/product/figma-screens.json Figma 프레임 56개 — 노드 · 크기 · 기기 · 원본 PNG · insets(띠)
원본 PNG docs/design/figma/reference/<키>.png Figma 에서 1배율로 내보낸 정본. 구현 캡처로 덮어쓰지 않는다
Figma 기기 FigmaDevices (package:test_driver/golden.dart) 폰 · 태블릿 · 데스크톱 — DPR 1
대장 → 골든 FigmaLedger · FigmaScreen 키 하나 → 기기 · co_golden 원본(GoldenDesignReference)
화면 등록 FigmaGoldenScreens capture 전용 시나리오 + 대장 연결 기록
수락 보고 tool/design/check_visual_acceptance.dart 화면마다 엄격 차이를 다시 세어 판정 → build/visual-acceptance.json
판정 정책 docs/product/figma-fidelity.json 기준 3%(미만) · 세는 법 · Δ 의 N · 글자 밖 판정(선택 textMask)
CI .github/workflows/golden.yml 의 Figma 대조 (수락 보고) 요약 · 아티팩트 — 지금은 보고만

기기

Figma 프레임 그대로 찍는다. 원본 PNG 가 1배율이므로 기기도 DPR 1 이다 — 캡처와 원본이 같은 픽셀 격자에 놓여야 co_golden 이 견준다(크기가 다르면 sizeMismatch 로 견주지 않는다).

기기 크기 플랫폼 기본 안전 영역
FigmaDevices.phone (figma-phone) 390×844 iOS 위 44 · 아래 34
FigmaDevices.tablet (figma-tablet) 1024×768 iOS(가로) 위 44 · 아래 34
FigmaDevices.desktop (figma-desktop) 1440×900 macOS(웹 화면) 없음

가림

가리는 것은 띠 둘뿐이다 — 위 상태 바(insets.top)와 아래 홈 인디케이터(insets.bottom). 둘 다 기기(OS)가 그리고 앱은 그리지 않는다. 띠마다 사유가 기록된다(상태 바 띠(위 44px) — 기기(OS)가 그리고 앱은 그리지 않는다).

가림 예외

화면 영역(논리 px) 사유 이슈
(없음)

세는 법

분모는 띠 밖의 픽셀(comparable = 전체 − 띠)이다. 두 이미지를 8비트 RGBA 로 풀어 픽셀마다 견준다.

이름 「다르다」로 세는 픽셀 보고 키
exact RGBA 네 채널 중 하나라도 다르다 — 엄격(정확) 차이 exact
Δ≤N 무시 네 채널 차이의 최댓값이 N 을 넘는다(N 이하는 세지 않는다) — 기본 N = 16 delta

글자 밖 — 글자 잉크 상자를 빼고 세기

같은 글자를 같은 자리에 그려도 두 렌더러가 가장자리를 다르게 칠해, 글자 상자(+2 px) 픽셀의 26–32% 가 Δ>8 로 남는다 (아래 「글자 바닥값」). 그래서 글자는 구조로 엄격하게, 픽셀은 글자 밖에서 센다. 오너가 2026-11-02 에 판정에 쓰기로 했다 — figma-fidelity.json 의 "textMask": {"padding": 2}.

판정

상태 뜻
accepted ✅ 정책의 세는 법으로 기준 미만
above-threshold ⛔ 기준 이상
unverified ⚠️ 판정 못 함 — 캡처 실패 · 넘침 · 크기 불일치 · 원본 · 대장 없음 · 대장 연결 기록 없는 디자인 대조 · 검산 실패 · 글자 밖으로 판정하는데 사양을 읽지 못함. 통과가 아니다
stale 🕰 낡음 — 캡처 뒤 원본 PNG 나 대장 항목(노드 · 크기 · 띠 …)이 바뀌었거나 --since 보다 이른 캡처. 다시 찍는다

비교는 대장 연결 기록(build/co_golden/figma/**)마다 한 줄이다. 기록은 그리기 전에 남으므로 그리다 실패한 화면도 보고에서 사라지지 않는다. coverage 는 대장 화면 중 몇 개를 견줬는지와 빠진 키를 보인다(대장이 없으면 세지 않는다). 수락은 비교마다의 지표다 — 커버리지 · 실제 앱 동작 · 디자인 승인은 따로 본다.

화면 등록

화면 패키지의 test/golden/ 에서 대장 키로 등록한다. 원본과 같은 상태(같은 데이터 · 선택 · 스크롤)를 만들어 찍는다.

import 'package:test_driver/golden.dart';

final FigmaGoldenScreens figma = FigmaGoldenScreens(suite: 'clinic');

void main() {
  figma.screen('HP-01@390', build: (_) => const HomePage());
  figma.screen('HP-03+HP-04@1440', build: (_) => const ServiceDetailPage(), interact: …);
}

로컬 실행

# 1) 캡처 — 모든 골든 패키지(Figma 대조 포함) → build/co_golden
tool/golden/capture.sh
#    Figma 대조만, 한 패키지에서(출력을 저장소 build/co_golden 으로):
(cd <패키지> && TZ=Asia/Seoul CO_GOLDEN_MODE=capture \
  CO_GOLDEN_OUTPUT="$(git rev-parse --show-toplevel)/build/co_golden" \
  flutter test --no-pub --tags figma test/golden)

# 2) 수락 보고 — 보고만(종료 코드 0) · Markdown 요약까지
tool/design/check_visual_acceptance.sh --report-only --summary build/visual-acceptance.md
#    판정으로(수락이 아닌 비교가 있으면 1): --report-only 를 뺀다
#    보정 탐색 — 정책은 그대로 두고 보고에 덮어쓰기로 남긴다
tool/design/check_visual_acceptance.sh --report-only --count delta --delta 8
#    글자 밖으로 판정(정책에 textMask 가 있으면 이미 켜져 있다 — 「세는 법」의 「글자 밖」)
tool/design/check_visual_acceptance.sh --report-only --count delta --delta 8 --text-mask

# 3) 갤러리
tool/golden/gallery.sh   # → build/golden-gallery/index.html

tool/design 은 별도 pub 루트다(PNG 를 푸는 image 의존 — 루트 워크스페이스 의존을 늘리지 않는다). 래퍼 check_visual_acceptance.sh 가 lock 그대로 받고 저장소 루트에서 돌린다. 도구 시험: (cd tool/design && dart test).

출력

build/co_golden/                        # capture.sh (co_golden)
├── images/<suite>/<scenario>/<변형>.png        캡처
├── references/<suite>/<scenario>/<변형>.png    원본 사본(바이트 그대로)
├── differences/<suite>/<scenario>/<변형>.png   co_golden 정확 차이(띠 안 포함, 자홍)
├── analysis/<suite>/<scenario>/<변형>.{json,png} co_golden 허용 오차 분석 · 지도
├── figma/<suite>/<scenario>/<변형>.json        대장 연결 기록(키 · 대장 · 띠) — FigmaGoldenScreens
└── runs/<suite>/<scenario>.json               실행 기록
build/visual-acceptance.json            # 수락 보고(정책 · 수 · 커버리지 · 비교마다 exact · delta · 글자 밖 · 분석)
build/visual-acceptance.md              # --summary
build/visual-acceptance/<suite>/<scenario>/<변형>.png  # 보정 지도
build/golden-gallery/index.html         # gallery.sh

보정 지도는 수락 보고가 쓴다 — 회색 같음 · 파랑 가린 띠 · 노랑 exact 로만 세는 픽셀(Δ≤N) · 자홍 두 규칙 모두 세는 픽셀(Δ>N) · 초록 글자 가림(사양이 있는 화면 — 진한 초록은 그 안의 Δ>N). 노랑이 글자 · 모서리 가장자리뿐이면 Δ 규칙이 래스터 차이만 빼는 것이다.

갤러리 읽는 법

gallery.sh 의 갤러리에서 Figma 대조가 있는 변형은 원본과 캡처를 함께 보인다.

CI

golden.yml 의 골든 (compare) 가 PR(준비 완료) · dispatch 에서 확인용 capture 를 돌린 뒤 출력을 아티팩트 co-golden-capture 로 올리고, Figma 대조 (수락 보고) 잡이 그것을 받아 도구 시험 → 수락 보고를 돌려 잡 요약과 아티팩트 visual-acceptance(JSON · Markdown · 보정 지도)로 남긴다.

보정 — HP-01 첫 측정 (끝났다 — 오너 확정 2026-11-02)

엄격 3% 를 무엇으로 셀지는 HP-01 을 구현해 처음 잰 뒤 정했다(figma-fidelity.json 의 calibration). 세는 법은 오너가 확정했다(2026-11-02) — 「글자 밖 Δ≤8 3% 미만」(count: delta · maxChannelDelta: 8 · textMask.padding: 2, co_golden 구조 오류 0건 지향). exact · Δ≤8 전체는 참고로 계속 보고한다.

  1. HP-01@390 을 구현하고 FigmaGoldenScreens 로 등록한다. 원본과 같은 데이터 · 상태로 찍는다(브랜드 테마 반영 뒤).
  2. 수락 보고에서 exact · Δ≤16 · co_golden 허용 오차(안티에일리어싱 픽셀 수)를 함께 읽는다.
  3. --count delta --delta N 으로 N = 0 · 4 · 8 · 16 · 32 의 비율을 표로 만든다. 보정 지도에서 노랑(Δ≤N 이라 빠지는 픽셀)이 글자 · 모서리 가장자리뿐인지 본다 — 레이아웃 · 색 · 크기 차이가 노랑에 숨으면 N 이 너무 크다.
  4. 기준선(Figma 끼리 exact 14.1% · Δ≤16 4.7%, 오케스트레이터 측정 2026-11-01)과 견준다 — 구현이 아무리 맞아도 exact 로는 3% 아래로 내려가지 않을 수 있다는 근거다.
  5. 오너가 count · maxChannelDelta 를 정한다 → figma-fidelity.json 을 바꾸는 PR(calibration.status: decided, 측정 표 링크). 그다음 FIGMA_ACCEPTANCE_BLOCKING 을 "true" 로 바꿀지 정한다(아직 아니다 — Figma NavigationBar 수정 뒤).

먼저 잰 앱 — scaffold-booking (2026-11-01)

단골 예약의 SH-01 세 크기를 같은 도구로 잰 결과(Δ≤N 표 · 원인별 분해 · 글자 바닥값 · 사진 보정 · CoUI NavigationBar 높이 차이)와 권고(exact 는 쓰지 않는다 · Δ≤8 을 권한다, 결정은 오너)는 coco-de/scaffold-booking docs/product/figma-fidelity.md 「보정」에 있다. 같은 Figma 파일 · 같은 CoUI 부품이라 이 앱에도 그대로 들어맞는 것(글자 가장자리 래스터 차이 · 사진 ±1 잡음 · 하단 탭 높이 차이)이 많지만, 숫자는 이 앱의 화면으로 다시 잰다.

파일럿 (지웠다)

처음에는 package/test_driver/test/golden/figma_pilot_golden_test.dart 가 HP-01 로그인의 구현이 아닌 자리표시로 파이프라인 (캡처 → 원본 → 차이 → 분석 → 수락 보고)이 끝까지 도는지만 보였다(대장은 파일럿 픽스처 figma-screens.pilot.json). HP-01 로그인을 구현하면서(R2 ③) 그 화면 패키지(feature/clinic/app)의 골든에서 FigmaGoldenScreens 로 HP-01@390 · @1440 과 HP-02 두 크기를 등록했으므로 파일럿 시험 · 픽스처 · 원본 PNG 를 지웠다. package/test_driver 의 대장 시험은 정본 대장(docs/product/figma-screens.json)을 읽는다. 측정 숫자는 이 앱의 화면으로 잰 값이 R2 ③ PR 본문의 「Figma 대조」 표에 있다.