designpaca 초기 구현 — 스킬 · 설치 CLI · 배포 파이프라인

웹 디자인 파이프라인 스킬과 이를 5개 에이전트에 설치하는 CLI 를 담은 모노레포.

스킬 (packages/skill)
- SKILL.md 261줄 + 참조 문서 16개 3,349줄. progressive disclosure 로
  본문은 절차와 인덱스만, 지식은 references/ 로 분리
- 0~6단계 파이프라인. 규모에 따라 전체·연장·국소 세 경로로 분기
- 하드 게이트 12개는 grep·카운트로 검증 가능한 것만. 취향 판단은 제외
- 미학 프리셋 5종, AI 슬롭 지문 목록, 한글 조판 규칙,
  SVG 필터·three.js·인터랙티브 모션·HTML-in-Canvas 실전 지침

설치 CLI (packages/cli, packages/core)
- npx designpaca 온보딩 TUI. Claude Code · Codex · Cursor · Windsurf · AGENTS.md
- 매니페스트에 설치 시점 해시를 기록해 사용자가 고친 파일은 update 가 건너뛴다
- 타깃별로 본문의 references/ 경로를 실제 설치 위치로 재작성
- AGENTS.md 는 항상 로드되므로 본문 대신 303자 포인터만 주입
- Windsurf 는 12,000자 상한 초과 시 설치를 차단

배포 (build/ci, .forgejo/workflows)
- 태그 v* → 검사·테스트·빌드 → npmjs 배포 + Forgejo 레지스트리 미러
  → draft 릴리스 → Cloudflare Pages. 재실행 멱등

근거 (research/)
- 약 250개 웹 소스 조사 결과와 도그푸딩 검증 2건. 스킬의 모든 수치는 여기서 나온다

테스트 22개 통과 (core 16 · cli 6)
This commit is contained in:
Yun Chan 2026-08-20 10:48:00 +09:00
commit 8808c672dc
135 changed files with 38838 additions and 0 deletions

View file

@ -0,0 +1,86 @@
# 노마드코더 「이게 진짜 HTML이라고?」 분석
- **URL**: https://www.youtube.com/watch?v=8ucoskmA1yg
- **채널**: 노마드 코더 Nomad Coders
- **주제**: Chrome 신규 **HTML in Canvas** API
- 원문 자막: `transcript-ko.txt` / 압축본 `transcript-ko-compact.txt` / 영문 `nomad-html.en.srt`
## 목차 (영상 챕터)
| 시간 | 내용 |
|---|---|
| 0:002:29 | 이게 진짜 HTML이라고? (데모 쇼케이스) |
| 2:302:50 | 왜 지금까지 불가능했을까? |
| 2:513:51 | HTML in Canvas는 어떻게 작동할까? |
| 3:526:02 | 직접 만들어보자 (반사 버튼 구현) |
| 6:036:37 | 아직 당장 쓸 수는 없다 |
## 핵심 주장
> "웹사이트와 비디오 게임의 경계를 허무는 새로운 API"
> "2D 페이지라기보다는 비디오 게임이나 예술 설치 작품처럼 느껴지는 웹사이트"
**기존의 딜레마**: 캔버스는 다른 HTML 요소를 전혀 알지 못한다. 캔버스 안에 버튼을 그리려면 사각형+글자를 직접 그리고, 클릭 좌표를 히트테스트하고, 호버 시 다시 그려야 한다. 그렇게 해도 접근성·키보드 지원·CSS 스타일링이 전부 없는 "버튼 그림"일 뿐이다. → **픽셀(canvas)이냐 HTML이냐 둘 중 하나만** 골라야 했다.
**해결**: 같은 요소가 DOM(상호작용)과 캔버스(픽셀)에 **동시에 존재**한다. 셰이더가 그 픽셀을 붙잡아 비틀고, 왜곡하고, 혼합하고, 3D 형태에 매핑한다. 접근성과 폼 동작은 DOM이 그대로 유지한다.
## API 구조
> ⚠️ **영상이 쓰는 API 이름은 전부 구 명칭이다.** 조사 결과 확정된 현재 이름으로 아래를 정정했다.
> 근거와 전체 스펙: `research/canvas/01-api-spec.md`
1. `<canvas layoutsubtree>` 속성 → 캔버스가 **직계 자식** 요소를 인식 (철자는 전부 소문자, IDL은 `layoutSubtree`)
2. 그리고 싶은 HTML을 캔버스 자식으로 넣는다 (평범한 HTML/CSS 그대로)
3. **`ctx.drawElementImage(el, x, y)`** — 요소 + 좌표를 주면 실시간 복사본을 그 자리에 그린다
- 이름 변천: `drawElement``drawHTMLElement``drawHTML`**`drawElementImage`**(2025-09-11 확정). 영상은 첫 이름을 쓴다
4. **반환값이 핵심**: 그려진 위치를 나타내는 `DOMMatrix` 를 돌려준다 → 그것을 요소의 `style.transform` 에 넣으면 실제 DOM 요소가 그려진 위치로 이동한다 → **클릭이 맞아떨어진다**
- 구 API의 `setHitTestRegions()` 는 2025-11-08 폐기되고 이 방식으로 대체됐다
- **매 프레임 반영하지 않으면 클릭이 전부 어긋난다** — 이 API의 필수 계약이다
5. WebGL **`gl.texElementImage2D(...)`** / WebGPU **`device.queue.copyElementImageToTexture(...)`**
- 2026-04~06에 두 시그니처 모두 바뀌어 **Chrome 공식 블로그 예제조차 구버전**이다. WICG 공식 데모도 try/catch 로 신·구 양쪽을 지원한다
6. 캔버스 내부 HTML이 바뀔 때(포커스·호버 등) **`paint` 이벤트** 발생 → 듣고 다시 그린다 (중첩 시 역트리 순서)
### 보안 모델 — "read-back-allowed rendering"
캔버스 픽셀은 읽을 수 있으므로, **저자가 원래 볼 수 없던 것은 아예 그리지 않는다**: cross-origin 콘텐츠, 시스템 색상, 맞춤법 마커, **`:visited`(히스토리 스니핑 차단)**, 자동완성 미리보기, 서브픽셀 AA, IME 팝업. same-origin iframe은 그려진다.
### 데모 구현 흐름 (반사 버튼, JS 약 20줄)
```
매 프레임(rAF):
캔버스 clear
ctx.save()
translate(아래로) + 상하 반전 + globalAlpha 0.3
drawElement(button) ← 흐릿한 뒤집힌 반사
ctx.restore()
drawElement(button) ← 원본
반환된 변환값 → button.style.transform 에 적용 (히트박스 정렬)
requestAnimationFrame(render)
```
클릭 이벤트에서 클릭 좌표로 `ripple()` 호출 — 픽셀을 샘플링해 위치를 조정하는 건 기존 캔버스 연산이라 새로울 게 없다. **요점은 HTML이 일단 캔버스에 올라가면 무엇이든 할 수 있다는 것.**
## 영상에 나온 데모들
- 3D 씬의 **천 조각 위에 그려진 포트폴리오** — 찌르면 천이 실제처럼 반응하고 폼이 천에 녹아든다
- HTML `range` 입력 → **젤리 슬라이더**
- 폼 제출 시 셰이더로 **HTML이 왜곡되는** 효과
- 라이트/다크 모드 전환 시 **페이지가 타들어가는** 애니메이션
- 웹에서 구현한 **Apple Liquid Glass**
## 한계
영상이 밝힌 것:
- Chrome **Canary + 플래그** 뒤에 있다 (`chrome://flags/#canvas-draw-element`)
- 아직 **제안(proposal) 단계**, 전부 초안
- **API 시그니처와 기본 형태조차 바뀔 수 있다** — 실제로 조사 기간에만 4번 바뀌었다
- → "당장 내일 프로덕션에 투입할 것은 아니지만, 오늘 실험을 시작할 가치는 충분하다"
조사로 보강한 것 (영상이 말하지 않은 것):
- **Origin Trial이 진행 중이다** (M148~M150, M154까지 연장 승인). OT 토큰을 등록하면 **Chrome Stable 사용자에게도 동작한다** — 영상은 이 부분을 "플래그뿐"으로 축소해서 말한다. 다만 2026-10 초 만료 예정
- **Firefox·Safari 모두 "No signal"**(입장 미표명), WHATWG PR #11588은 2025-08 개설 후 여전히 미머지
- 실전 제약 둘: ① cross-origin iframe 미지원 ② **캔버스 안 콘텐츠는 컴포지터 스레드 스크롤/애니메이션을 잃고 JS에 묶인다** — Chrome은 캔버스 안에 스크롤 영역을 넣지 말고 캔버스 전체를 스크롤시키라고 명시
- **three.js는 이미 정식 지원한다**: `THREE.HTMLTexture(element)` + `InteractionManager`, **r184 포함**(2026-04-10 머지), WebGL/WebGPU 렌더러 양쪽
- **폴백이 존재한다**: `three-html-render` 폴리필(MIT)이 동일 API 표면을 `foreignObject`로 제공하고 네이티브가 있으면 자동으로 fast path를 탄다. three.js 공식 예제가 이걸 쓴다
## designpaca 에의 함의
1. **이 API는 스킬의 "실험 레이어"에 넣는다** — 기본 경로가 되어선 안 된다. 프로덕션 기본값은 SVG 필터 + three.js. 단 조사 결과 위상이 조금 올라갔다: **three.js `HTMLTexture`(r184 정식) + `three-html-render` 폴리필** 조합이면 *점진적 향상*으로 오늘 쓸 수 있다. "쓰지 마라"가 아니라 **"폴백을 먼저 만들고, 그 위에 얹어라"**로 규칙을 정한다
2. **폴백 필수**: 미지원 브라우저에서 같은 인상을 주는 대안 경로를 항상 같이 설계한다 (`foreignObject` 폴리필, SVG displacement, backdrop-filter, CSS3DRenderer 등 — 비교표는 `research/canvas/04-fallbacks.md`)
3. **"DOM은 살려두고 픽셀만 왜곡한다"는 원칙**은 이 API 없이도 유효하다 — 접근성을 포기하지 않고 화려함을 얻는 designpaca의 기본 철학으로 삼는다
4. 영상의 문제의식("웹이 다시 재밌어질 수 있다", "플래시 시절처럼")이 곧 스킬의 방향성 — **안전하고 지루한 템플릿의 반대편**