Communitygithub.com

Sketch 검사기

AI 친화적인 Sketch 디자인 파서입니다. Sketch 문서를 구조화된 JSON, 내보낸 에셋, 구현 준비가 완료된 LayoutIR(flex/grid/absolute/leaf)로 변환하여 모든 LLM 에이전트가 Sketch 디자인을 HTML/CSS, React 또는 Vue로 변환할 수 있도록 합니다. Claude Code, Cursor, opencode와 호환됩니다.

Sketch 검사기란 무엇인가요?

이 스킬은 Sketch 디자인 파일을 AI 에이전트가 즉시 사용할 수 있는 구조화된 데이터로 변환하는 전문 파서입니다. Sketch 문서를 열면 MCP(MCP 서비스 주소: http://localhost:31126/mcp)를 통해 문서와 레이어 정보에 접근하여, 디자인을 JSON 형식의 레이아웃 IR(중간 표현)로 추출합니다. 추출된 IR은 flex, grid, absolute, leaf와 같은 CSS 레이아웃 유형을 포함하여, LLM이 디자인을 정확히 재현할 수 있도록 돕습니다. 이 스킬은 특히 Claude Code, Cursor, opencode와 같은 AI 코딩 에이전트와 함께 사용하도록 설계되었으며, Sketch 디자인을 HTML/CSS, React, Vue 등으로 변환하는 전체 워크플로우를 안내합니다. 대용량 파일 처리를 위해 자동 분할 및 조립 기능을 제공하며, '작은 파일 직접 구현'과 '큰 파일 분할 처리' 두 가지 모드를 지원합니다.

지원 대상✓Claude Code~Codex CLI✓Cursor✓OpenCode
npx skills add gslvly/sketch-inspector

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Sketch 검사기은(는) 무엇을 하나요?

Sketch 디자인을 구조화된 데이터, 이미지 리소스, 구현 가능한 페이지 섹션으로 변환합니다.

사용 시나리오

  • 열려 있는 Sketch 문서 또는 특정 레이어 검사
  • 구조, 스타일, 텍스트, 색상, 레이아웃 및 리소스 정보 추출
  • Sketch 영역을 기반으로 HTML/CSS, React, Vue 또는 기타 페이지 구현

전제 조건

  • Sketch가 실행 중이고 대상 문서가 열려 있어야 함
  • Sketch MCP 활성화: 일반 → AI 도구가 열린 문서와 상호 작용하도록 허용
  • MCP 서비스 주소: http://localhost:31126/mcp
  • Sketch Run Code는 일반 Node.js가 아닌 JavaScriptCore/CocoaScript 환경에서 실행됨

페이지 구현 필수 프로세스

Sketch에서 페이지를 생성할 때는 다음 프로세스를 엄격히 따라야 합니다. 이것이 작업을 완료하는 가장 빠른 유일한 방법이며, 단계를 누락하면 실패로 간주합니다.

1. 스캔

페이지 또는 대상 컨테이너의 얕은 윤곽을 추출하고 루트 노드 layerId를 확인합니다.

2. 경로 결정

  • imageOutputDir: 프로젝트 이미지 디렉토리, 기존 images/, assets/images/, public/images/ 등을 우선 사용
  • workTmpDir: 임시 디렉토리, 최소 result.json을 저장합니다. 큰 파일을 분할할 때는 manifest.json, 섹션 JSON, 섹션 HTML도 저장합니다.

3. 내보내기

sketch_run_code에서 내보내기 스크립트를 실행합니다.

const sketch = require('sketch');

// 매개변수 준비
const layerId = '<대상 레이어의 layerId>'; // 1단계 스캔에서 얻은 대상 루트 노드 ID
const outputDir = '<imageOutputDir 절대 경로>';  // 예: '/Users/edy/project/images'
const outputJsonPath = '<workTmpDir/result.json 절대 경로>';  // 예: '/Users/edy/project/tmp/result.json'

// 내보내기 스크립트 실행
const exportScript = require('@scripts/export-text-split-assets.js');
const result = exportScript.runExportTextSplitAssets({
  layerId: layerId,
  outputDir: outputDir,
  outputJsonPath: outputJsonPath
});

// 디버깅을 위해 결과 출력
console.log(JSON.stringify(result, null, 2));

반환 결과:

  • 성공: 내보내기 통계 정보 반환
  • 실패: 오류 메시지 반환, layerId가 유효한지, 경로에 쓰기 권한이 있는지 확인

참고:

  • 스크립트는 일반 Node.js가 아닌 Sketch JavaScriptCore 환경에서 실행됨
  • 경로는 절대 경로여야 함
  • 출력 디렉토리가 존재해야 하며, 스크립트가 자동으로 생성하지 않음

4. 레이아웃 추론 및 result.json 덮어쓰기

Shell에서 실행:

npx tsx @scripts/sketch_layout_ir_inference.ts \
  <workTmpDir>/result.json \
  <workTmpDir>/result.json

이 단계는 내보낸 원시 구조를 직접 구현 가능한 통합 레이아웃 JSON으로 변환하고 원래 result.json을 덮어씁니다.

통합 result.json 구조 출력:

  • kind: flex | grid | absolute | leaf
  • direction: row | column (flex만 해당)
  • gap: 자식 요소 간격
  • padding: 안쪽 여백 { top, right, bottom, left }
  • justifyContent: flex 정렬 방식
  • alignItems: 교차축 정렬 방식
  • hasAbsoluteChildren: flex/grid 컨테이너에 직계 absolute 자식 노드가 있으면 true
  • css.position: "relative": flex/grid 컨테이너에 직계 absolute 자식 노드가 있으면 명시적으로 출력
  • columns / rows: 그리드 행/열 수 (grid만 해당)
  • source: 현재 레이아웃 노드에 해당하는 구현 보충 데이터, sourceClass / asset / background / style / decision / backgroundLayers / derivedFrom 등 레이아웃이 아닌 필드만 유지

5. 레이아웃 탐지 후 반드시 분기

레이아웃 추론이 완료된 후에는 직관에 따라 구현 방식을 결정할 수 없습니다. 통합된 result.json의 실제 줄 수에 따라 분기해야 합니다.

  • result.json이 3000줄 이하: 전체 result.json을 직접 읽어 구현하고 더 이상 분할하지 않음
  • result.json이 3000줄 초과: 반드시 "큰 파일 분할 프로세스"에 들어가야 하며, 전체 JSON을 후속 구현 단계에 직접 전달하는 것을 금지

줄 수 확인 예시:

wc -l <workTmpDir>/result.json

6. 작은 파일 메인 프로세스: 직접 구현

적용 조건: result.json 줄 수 <= 3000

핵심 규칙 (MUST FOLLOW):

  1. 일반 레이아웃에 absolute 사용 금지: kind: "absolute" 노드만 절대 위치 지정 허용
  2. 직계 absolute 자식 노드가 있는 경우, result.json의 위치 신호를 반드시 신뢰: 노드가 hasAbsoluteChildren: true 또는 css.position: "relative"를 출력하면, 구현 시 해당 부모 컨테이너에 위치 상태를 설정해야 하며 무시할 수 없음

생성 프로세스:

  1. 전체 result.json 읽기
  2. 레이아웃 트리 재귀적 순회
  3. kind에 따라 해당 CSS 생성:
    • flex: display: flex; flex-direction: {direction}; gap: {gap}px; ...
    • grid: display: grid; grid-template-columns: repeat({columns}, 1fr); ...
    • absolute: position: relative; 자식 요소 position: absolute;
    • leaf: 레이아웃 없음, 콘텐츠만 렌더링
  4. 현재 노드의 source를 직접 사용하여 텍스트, 이미지, 배경, 스타일, 결정을 구현하고 더 이상 이전 구조 JSON을 참조하지 않음

7. 큰 파일 메인 프로세스: 분할 → 단일 섹션 구현 → 역채우기 및 집계

적용 조건: result.json 줄 수 > 3000

7.1 JSON 분할

Shell에서 실행:

node @scripts/split-result-json.js \
  --inputJsonPath=<workTmpDir>/result.json \
  --outputDir=<workTmpDir> \
  --assetBasePath=images/ \
  --splitStrategy=auto

출력:

  • <workTmpDir>/manifest.json
  • 여러 섹션 JSON
  • 약속된 implementationPath, htmlMarker, cssMarker
  • manifest.json.root.layoutIR: 페이지 메인 레이아웃 의미 요약
  • manifest.json.sections[].layoutIR: 섹션 노드 자체의 레이아웃 의미 요약

7.2 단일 섹션 구현

각 섹션은 자신의 jsonPath만 읽고 manifest.json에 따라 자신의 implementationPath에 써야 합니다.

강제 규칙:

  • 단일 섹션 구현 프로세스는 @references/single-section-workflow.md 참조
  • 섹션 파일은 조각이어야 함: <section> 하나 + <style> 하나
  • 섹션 내부 구조와 내부 스타일만 작성하고, 메인 레이아웃 컨테이너의 외부 여백을 정의하지 않음
  • 루트가 아닌 선택자는 className으로 범위 격리해야 함
  • 심층 검사가 필요할 때 @scripts/inspect-single-section.js 사용

7.3 역채우기 및 집계

모든 섹션 구현이 완료된 후, 각 섹션 조각을 전체 레이아웃 파일에 역채워야 하며, 마커 내용을 수동으로 복사하여 붙여넣을 수 없습니다.

메인 레이아웃 파일은 미리 다음을 충족해야 함:

  • htmlMarker는 페이지 구조에서 섹션을 삽입해야 하는 위치에 배치
  • cssMarker는 메인 레이아웃 파일의 <style> 블록 내부에 배치해야 하며, 다른 태그, 주석 블록 외부 또는 본문 구조에 배치할 수 없음
  • HTML과 CSS가 별도 파일인 경우, cssMarker는 cssLayoutPath가 가리키는 CSS 파일에 배치해야 함

Shell에서 실행:

node @scripts/replace-section-placeholder.js \
  --layoutPath=/path/layout.html \
  --sectionPath=/path/01-section.html \
  --htmlMarker="<!-- 01-section HTML -->" \
  --cssMarker="/* 01-section CSS */"

HTML과 CSS가 다른 파일에 있는 경우, 추가로 --cssLayoutPath를 전달합니다.

8. 구현 체크리스트

구현 전 확인:

  • 전체 result.json 읽기
  • 각 노드의 kind 필드 확인
  • meta.background 배경 레이어 정보 확인
  • 텍스트, 이미지, 레이어 관계 확인 완료
  • 브랜드 에셋 및 복잡한 시각적 그룹 식별 완료

9. 전달

객관적인 산출물 보고:

  • 레이아웃 윤곽 및 대상 영역 ID
  • result.json 경로 및 실제 줄 수
  • 사용한 방식 ("작은 파일 직접 구현" 또는 "큰 파일 분할 프로세스")
  • 분할 프로세스 사용 시: manifest.json 경로, 섹션 수, 역채우기 대상 파일 경로
  • 레이아웃 유형 통계 (flex/grid/absolute/leaf 개수)
  • 내보낸 리소스 목록
  • 생성된 HTML/CSS 파일 경로

"시각적으로 검증됨" 등 머신이 판단할 수 없는 결론은 출력하지 마십시오.

고정 스크립트

스크립트 매개변수 및 반환 구조는 @references/script-api.md를 참조하십시오.

  • @scripts/export-text-split-assets.js: 이미지 및 JSON 내보내기. 필수 layerId, outputDir
  • @scripts/sketch_layout_ir_inference.ts: 레이아웃 추론 및 통합된 result.json 출력
  • @scripts/split-result-json.js: 큰 파일 메인 프로세스 스크립트, manifest.json 및 여러 섹션 JSON 생성
  • @scripts/replace-section-placeholder.js: 큰 파일 메인 프로세스 스크립트, 섹션 구현을 전체 레이아웃 파일에 역채우기
  • @scripts/inspect-single-section.js: 섹션 정보가 부족할 때 로컬 심층 검사 수행

금지: 내보내기 스크립트를 직접 생성하거나, 스크립트 소스를 복사하거나, 순회 로직을 다시 구현하지 마십시오.

LayoutIR 유형 설명

type LayoutKind = 'leaf' | 'flex' | 'grid' | 'absolute'

interface FlexIR {
  kind: 'flex'
  direction: 'row' | 'column'
  gap: number
  padding: { top, right, bottom, left }
  justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-between'
  alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch'
  children: LayoutIR[]
}

interface GridIR {
  kind: 'grid'
  columns: number
  rows: number
  columnGap: number
  rowGap: number
  padding: { top, right, bottom, left }
  children: LayoutIR[]
}

interface AbsoluteIR {
  kind: 'absolute'
  children: LayoutIR[]  // 자식 요소는 절대 위치 지정 필요
}

interface LeafIR {
  kind: 'leaf'
  text?: string
  css: { width?, height? }
}

리소스 내보내기 규칙

  • 이미지는 imageOutputDir로 출력하고, 임시 JSON은 workTmpDir에 저장
  • 이미지 파일 이름은 MD5의 처음 8자리를 사용하며, 동일 이미지는 재사용
  • asset/exports는 path, src, x, y, width, height만 유지. 코드 생성 시 src 참조, path 사용 안 함
  • JSON에서 빈 값과 값이 0인 스타일 필드 삭제
  • 기본적으로 숨겨진 레이어 필터링
  • 실제 텍스트가 포함된 노드는 분할되어야 하며, 전체를 이미지로 내보낼 수 없음
  • 일반 배경 Rectangle은 코드로 재구성하고, 브랜드 에셋, 복잡한 시각적 그룹은 충실도 높게 내보내기 우선

참조 색인

  • @references/export-assets.md: 리소스 내보내기 규칙
  • @references/script-api.md: 스크립트 매개변수 및 반환 구조
  • @references/single-section-workflow.md: 단일 섹션 구현 프로세스

관련 스킬