102 lines
12 KiB
Markdown
102 lines
12 KiB
Markdown
# SW Header 창 이동 Motion — GIF 기준 최종 검증 (2026-10-16)
|
||
|
||
## 1. 최종 판정: PARTIAL
|
||
|
||
GIF 기준 모션 수정과 Chrome 브라우저 검증 **PASS**, Root Typecheck / SW Build / Root Build / Storybook Build **PASS**입니다. 실제 호스트의 OS 창 이동·최소화·종료, 다른 브라우저·보조기술과 독립 SW 패키지의 Guard coverage는 **NOT VERIFIED**이므로 전체 PASS로 확대하지 않습니다. GIF 이전 검증은 [과거 기록](./sw-header-window-motion-verification-2026-10-16.md)으로 보존합니다.
|
||
|
||
## 2. 시작 Git 상태
|
||
|
||
- Worktree: `D:\디자인시스템\HMDesign-SW`, branch `feature/sw-package`.
|
||
- HEAD: `9407c8567f57301659e591c03451cca1b828733c`.
|
||
- 기존 변경: ` M package-lock.json`, ` M package.json`, `?? docs/sw/`, `?? packages/sw/`, `?? src/sw/`.
|
||
- `_local/sw-motion-gif-qa/baseline.json`에 기존 SW·Story·문서와 root manifest/Lockfile의 SHA-256을 보존하고, 변경 전 CSS·창 제어 TSX·Story 사본도 저장했습니다. 기존 미추적 파일을 삭제·초기화하지 않았습니다.
|
||
|
||
## 3. 기존 구현과 GIF의 차이
|
||
|
||
기존 구현은 2.7265658초 1회 재생이며, 커서가 이미 위쪽에 있는 별도 SVG로 fade-in하고 창을 축소한 뒤 오른쪽으로 이동했습니다. 문구가 이른 시점부터 나타났고 마지막에 dissolve로 Default로 복귀했습니다. 이 방식은 이번 GIF의 ‘아래쪽 커서 상승 → 문구 → 전체 이동 → 유지 → 즉시 반복’과 달랐습니다. 수정 전에 같은 40ms 간격의 41개 실제 브라우저 프레임을 캡처했습니다.
|
||
|
||
## 4. 추가 수정 범위
|
||
|
||
기존 모션 CSS만 GIF 표본으로 바꾸고 기존 `Window Move Motion` Story의 설명·고정 시간·반복 로그를 갱신했습니다. 기존 Default SVG, Hover용 SVG 두 개, 줄무늬, Tooltip box·색상·크기, 공개 API와 TSX 이벤트 연결은 유지했습니다. Tooltip 글꼴 선언만 Figma의 Inter를 우선하고 기존 SW 글꼴을 fallback하도록 명시했습니다. 폰트 파일이나 의존성은 추가하지 않았습니다.
|
||
|
||
누르는 동안 CSS `:active`로 3개 애니메이션을 일시정지하고 Tooltip을 숨깁니다. 전역 이벤트·포인터 캡처·preventDefault·React 상태는 추가하지 않았습니다.
|
||
|
||
## 5. 프레임별 비교 결과
|
||
|
||
기준 파일: `D:\디자인시스템\ani_hover_move.gif`, SHA-256 `c7d22819cfb8f8cd8593684ce1e5c676a545fa09fa9fc7573d59f0f237d28026`. 640 × 192px, 41프레임, 각 40ms, 1640ms, 무한 반복입니다.
|
||
|
||
GIF 높이 192px를 48px Header bar의 4배로 환산했습니다. 창의 녹색 폭도 96 / 4 = 24px로 기존 SVG와 일치합니다. GIF의 여분 가로 캔버스는 UI에 넣지 않았습니다. 비교 이미지에서만 가로 여백 32px를 잘라 기존 아이콘의 시작 위치를 정렬했습니다. 비교 결과는 Header 크기의 CSS px로 표시합니다.
|
||
|
||
- 0–520ms: 창은 제자리, 커서는 오른쪽 아래에서 위로 약 12.5px 이동하고 왼쪽으로 0.75px 이동합니다.
|
||
- 520ms: 문구가 처음 나타납니다. 41개 프레임 전체에서 문구 표시 여부가 일치했습니다.
|
||
- 약 600–1040ms: 창은 오른쪽 28px / 위 4.5px 이동합니다. 커서는 최초 위치 대비 오른쪽 27.25px / 위 17px입니다. 40ms 표본 사이를 선형 보간하여 원본의 가속·감속을 따라가며 GIF에 없는 spring overshoot를 제거했습니다.
|
||
- 1040–1640ms: 600ms 동안 창·커서·문구의 끝 자세를 유지합니다. 1640ms에 첫 프레임으로 즉시 반복합니다.
|
||
- 최종 41개 캡처의 녹색 도형 좌상단 비교: 창 위치 최대 오차 0px, 커서 최대 오차 0.5px. 문구 glyph 좌상단 최대 오차 0.5px입니다.
|
||
- 커서와 문구의 보이는 간격: GIF 9px, 구현 9.25–9.5px이며 프레임별 차이는 0.5px 이내입니다.
|
||
|
||
위 수치는 색이 있는 도형/glyph의 경계 좌표 비교이며 전체 픽셀 동일성 판정은 아닙니다. 기존 Figma SVG의 검정 외곽선·녹색 줄무늬·Tooltip 배경을 유지했으므로 GIF의 검정 캔버스와 외관 전체를 복제하지 않았습니다. 현재 동작은 Figma Prototype의 1.022/0.744/0.958초 spring·1회 정책보다 GIF의 시간과 반복을 우선합니다.
|
||
|
||
## 6. Drag 검증
|
||
|
||
실제 공개 `@hm-design/sw`를 React로 렌더링한 QA fixture에서 확인했습니다. `onWindowMoveStart`가 원래 div의 PointerEvent를 한 번 받았고 `target/currentTarget`, `pointerId`, `pointerType=mouse`, `buttons=1`, `defaultPrevented=false`를 유지했습니다. 호스트 모의 코드가 설정한 Pointer Capture를 통해 Tooltip·창 제어 버튼 위로 이동해도 pointermove와 pointerup이 전달됐습니다.
|
||
|
||
포인터를 누르는 동안 애니메이션은 paused이며 200ms가 지나도 currentTime이 변하지 않았고 Tooltip은 숨겨졌습니다. Drag 중 최소화·종료 콜백은 발생하지 않았고, 이후 각 버튼 클릭은 자신의 콜백만 호출했습니다. Reduced Motion에서도 드래그 콜백·해제가 유지됐습니다. 실제 OS 창 이동과 네이티브 호스트 통합은 NOT VERIFIED입니다.
|
||
|
||
## 7. Tooltip · 반복 · Reduced Motion · Focus
|
||
|
||
- PASS: 45 × 17px, 검정 80% 배경, 흰색 12px/400, Inter 우선 + SW fallback 선언. 한글 또는 Inter가 없는 환경은 기존 Noto Sans KR 등으로 표시되며 Inter 파일 로드를 보증하지 않습니다.
|
||
- PASS: 장식 자식 전체의 `pointer-events: none`, Tooltip 겹침 위치에서 최소화 버튼 hit test, 최소화·종료 Callback 전달.
|
||
- PASS: 실제 Hover를 유지해 1.64초 간격의 iteration 2회, 중복 animationstart 없음. 12회 빠른 진입·이탈에서 start/cancel 각 12회, 잔여 애니메이션 0개.
|
||
- PASS: Hover 해제 즉시 Default SVG·위치·문구 숨김, 재진입 시 처음부터 시작.
|
||
- PASS: 재생 중 reduce 전환 시 애니메이션 0개, 원래 Default SVG와 정적 Tooltip 유지. 누르는 동안 Tooltip 숨김, 이탈하면 숨김. 24px 단계의 기존 그림 숨김 정책도 유지.
|
||
- PASS: 최소화 → 종료 Tab 이동, 2px Focus 윤곽선, Enter로 종료 콜백.
|
||
- 기존 제한: 이동 div는 role=presentation/Tab 비대상이며 키보드 창 이동·Focus Tooltip을 제공하지 않습니다. 호스트의 키보드 대안과 보조기술은 미검증입니다.
|
||
|
||
## 8. 반응형
|
||
|
||
1920 / 1440 / 1280(추가) / 1080 / 1079 / 768 / 640 / 639 / 390px에서 실제 viewport와 Header 폭을 검사했습니다. 모두 높이 49px, Header 및 문서의 가로 overflow 0px, Tooltip은 Header 경계 안이었습니다. 1080px 이상 이동 영역 88px, 640–1079px는 24px와 정적 Tooltip만, 639px 이하는 영역 숨김을 유지합니다. 최소화·종료의 배치와 클릭은 유지했습니다.
|
||
|
||
Tooltip은 기존처럼 이동 영역 밖으로 나와 최소화·종료 일부에 시각적으로 겹칩니다. 시각적 겹침이 없다고 판정하지 않았으며, 포인터 차단이나 가로 스크롤이 없음을 확인했습니다. 기존 문서명·레이어명의 말줄임 구조는 변경하지 않았습니다.
|
||
|
||
## 9. Typecheck · Build · Storybook · Guard
|
||
|
||
- PASS: `npm.cmd run typecheck` — root·SW를 포함한 workspace 타입 검사와 기존 pretypecheck의 theme 확인·package build. 최종 CSS와 Story 변경 뒤 실행했습니다.
|
||
- PASS: `npm.cmd run build:sw` 및 최종 pretypecheck에 포함된 SW Build.
|
||
- PASS: `npm.cmd --ignore-scripts run build`, `npm.cmd --ignore-scripts run build-storybook`. 이미 통과한 공통 prerequisite을 중복 실행하지 않았습니다.
|
||
- PASS: Chrome `155.0.8059.79`, 실제 CSS 애니메이션·9개 Story 단계·520ms 등장/1640ms 반복 경계·motion cycle/Drag/최소화/종료 로그·Reduced Motion. 브라우저 통합 검사 41개 PASS, pageerror 0건, HTTP 오류 0건.
|
||
- 기존 경고: 문서 예시 `bg-[var(...)]` CSS 최적화, Storybook `:host-context` minifier, 500kB 초과 chunk와 plugin timing 안내. exit 0이며 범위 밖의 기존 코드를 수정하지 않았습니다.
|
||
- 개발 서버의 기존 포트·프로세스를 건드리지 않고 빌드된 Storybook과 QA fixture를 임시 localhost 서버에서 검사하고 종료했습니다.
|
||
- Guard 1회: `node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope PARTIAL --files src/sw/sw-header.stories.tsx,packages/sw/src/theme/sw.css --json`. 원본 status/staticStatus **NOT VERIFIED**, FAIL 없음. SW styles export 미해석 `ENTRY-002`, 패키지 graph 밖 `SCOPE-001`, 연결에 의존한 Token/동적 값 미검증이 남았습니다. Guard를 수정하거나 PASS로 덮어쓰지 않았습니다.
|
||
- Guard 원본 styleEvidence는 STATIC PASS / RUNTIME NOT VERIFIED / DESIGN_INTENT PASS / FINAL NOT VERIFIED이며 checks=[]입니다. SW 실검사 완료라는 뜻은 아닙니다. 별도 Runtime은 위 Chrome 범위 PASS, 디자인 의도는 GIF 프레임 좌표·순서 및 Figma 자산·Tooltip 규격 범위에서 확인했고, 전체 검증은 호스트 등의 미검증 때문에 PARTIAL입니다.
|
||
|
||
## 10. 변경 파일 · 근거
|
||
|
||
1. `packages/sw/src/theme/sw.css` — 창 이동 모션 블록만 수정.
|
||
2. `src/sw/sw-header.stories.tsx` — 기존 모션 Story 블록만 갱신.
|
||
3. `docs/sw/sw-header-design-spec.md` — 과거 §11.3을 보존하고 현재 GIF 기준 §11.4 추가.
|
||
4. `docs/sw/sw-header-usage.md` — 현재 모션·Drag·반복·Story 사용법 반영.
|
||
5. `packages/sw/README.md` — 현재 GIF 기준과 검증 링크 반영.
|
||
6. 이 검증 기록 — 신규 문서.
|
||
|
||
Git 무시 경로 `_local/sw-motion-gif-qa/`에 원본 분석 JSON, 전/후 41개 PNG 및 좌표 JSON, `frame-comparison.json`, 비교 이미지 `gif-before-after.png`, 실제 React 캡처 미리보기 `window-move-preview.gif`, 폭별 PNG, `storybook-final.png`, `verification.json`, build 로그, 원본 `guard.json`, 시작 해시와 사본을 보존합니다. GIF는 QA 미리보기일 뿐 제품 Header에 사용하지 않습니다.
|
||
|
||
## 11. 기존 디자인 · 작업 보호
|
||
|
||
모션 블록 밖 CSS와 기존 TSX/이벤트 연결이 시작 사본과 동일함을 확인했습니다. SVG·나머지 Story·기존 반응형·다른 Header 요소·root package.json/Lockfile·과거 검증 문서도 시작 해시와 일치합니다. 다른 패키지 소스·다른 Worktree·DWG/DXF 뷰어를 변경하지 않았습니다. Root의 기존 package build는 Git 무시 dist만 재생성했습니다. 의존성 설치는 없습니다.
|
||
|
||
## 12. 남은 항목
|
||
|
||
실제 Electron/설치형 호스트의 OS 창 이동·최소화·종료, 터치/펜, 다른 브라우저, 키보드 창 이동 대안과 스크린리더, 전용 SW Guard coverage는 NOT VERIFIED입니다. Tooltip의 기존 시각적 버튼 겹침은 명시한 채 유지했습니다.
|
||
|
||
## 13. 종료 Git 상태
|
||
|
||
브랜치 `feature/sw-package`, HEAD `9407c8567f57301659e591c03451cca1b828733c`를 유지합니다. 기존 status 그룹 ` M package-lock.json`, ` M package.json`, `?? docs/sw/`, `?? packages/sw/`, `?? src/sw/`도 유지하며 이번 변경은 그 미추적 그룹 내부에 포함됩니다. Index 변경·Commit·Push·PR·Merge·Publish·배포는 수행하지 않았습니다. `git diff --check`와 문서 링크/공백 검사를 확인했습니다.
|
||
|
||
작업 시간(KST, GIF 수신 후 실제 작업): Started At 2026-10-16 13:38:28 / Completed At 2026-10-16 13:52:16 / Actual Duration 13분 48초 / Estimated Duration 20~30분 / Variance 20분 대비 −6분 12초, 30분 대비 −16분 12초.
|
||
|
||
## 14. 후속 변경 — 1400ms 및 Composed Controls Hover
|
||
|
||
위 1.64초·41프레임 검증은 당시 결과로 보존합니다. 이후 사용자 요청으로 경로·Keyframes 비율을 유지한 채 주기만 1400ms로 변경했습니다. 현재 문구 등장 약 444ms, 이동 완료 약 888ms, 유지 약 512ms입니다. 원본 GIF의 시간과 다른 의도적인 변경입니다.
|
||
|
||
같은 후속 작업에서 그룹 필드의 Hover 텍스트 및 지정 선/폰트/치수 미리보기를 `#FFC600`으로 추가 강조했습니다. 검정 외곽선과 기존 Gradient Hover Border·색상 견본·레이어 상태를 유지하고 상세보기는 제외했습니다. 이 변경의 새로운 검증 결과와 미검증 범위는 [속도·Composed Hover 통합 검증](./sw-header-speed-composed-hover-verification-2026-10-16.md)에 별도로 기록합니다. 위 과거 수치와 판정을 소급 변경하지 않습니다.
|