pubuilder 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/api.d.ts +1 -1
- package/dist/cli.js +657 -584
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/server/design-ir.d.ts +46 -0
- package/dist/server/http.d.ts +2 -0
- package/dist/server/skills.d.ts +5 -2
- package/package.json +2 -1
- package/skills/publish/SKILL.md +63 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma REST /nodes document 트리 → 컴팩트 Design IR.
|
|
3
|
+
*
|
|
4
|
+
* 규칙 기반 순수 변환(LLM 토큰 0). raw Figma 노드는 노드마다 수십 개 필드
|
|
5
|
+
* (blendMode/constraints/absoluteRenderBounds/exportSettings 등)를 담아 프롬프트에
|
|
6
|
+
* 그대로 실으면 토큰을 크게 낭비한다. 퍼블리싱에 실제로 필요한 스타일 필드만 뽑고
|
|
7
|
+
* 숨김 노드를 제거해 60~80% 축소한다. LLM은 이 IR로 판단(토큰 매핑·코드 작성)만 한다.
|
|
8
|
+
*/
|
|
9
|
+
export interface DesignIRNode {
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
size?: {
|
|
13
|
+
w: number;
|
|
14
|
+
h: number;
|
|
15
|
+
};
|
|
16
|
+
layout?: {
|
|
17
|
+
mode: 'row' | 'col';
|
|
18
|
+
gap?: number;
|
|
19
|
+
padding?: [number, number, number, number];
|
|
20
|
+
align?: string;
|
|
21
|
+
justify?: string;
|
|
22
|
+
};
|
|
23
|
+
radius?: number | number[];
|
|
24
|
+
fills?: string[];
|
|
25
|
+
strokes?: string[];
|
|
26
|
+
effects?: string[];
|
|
27
|
+
text?: {
|
|
28
|
+
chars: string;
|
|
29
|
+
font?: string;
|
|
30
|
+
size?: number;
|
|
31
|
+
weight?: number;
|
|
32
|
+
lineHeight?: number;
|
|
33
|
+
letterSpacing?: number;
|
|
34
|
+
};
|
|
35
|
+
component?: Record<string, string>;
|
|
36
|
+
children?: DesignIRNode[];
|
|
37
|
+
}
|
|
38
|
+
export interface DesignIR {
|
|
39
|
+
root: DesignIRNode;
|
|
40
|
+
/** 색상 사용 빈도 (hex→token 매핑 결정용, 빈도 내림차순) */
|
|
41
|
+
colors: Array<{
|
|
42
|
+
rgba: string;
|
|
43
|
+
count: number;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
export declare function extractDesignIR(document: unknown): DesignIR;
|
package/dist/server/http.d.ts
CHANGED
package/dist/server/skills.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SkillSource = 'project' | 'global' | 'uploaded';
|
|
1
|
+
export type SkillSource = 'builtin' | 'project' | 'global' | 'uploaded';
|
|
2
2
|
export interface SkillInfo {
|
|
3
3
|
id: string;
|
|
4
4
|
name: string;
|
|
@@ -9,16 +9,19 @@ export interface SkillInfo {
|
|
|
9
9
|
export declare class SkillRegistry {
|
|
10
10
|
private readonly projectRoot;
|
|
11
11
|
private readonly homeDir;
|
|
12
|
+
/** 패키지에 번들되어 배포되는 기본 스킬 디렉토리 (없으면 스캔 안 함) */
|
|
13
|
+
private readonly builtinDir?;
|
|
12
14
|
constructor(opts: {
|
|
13
15
|
projectRoot: string;
|
|
14
16
|
homeDir: string;
|
|
17
|
+
builtinDir?: string;
|
|
15
18
|
});
|
|
16
19
|
private settingsPath;
|
|
17
20
|
private loadSettings;
|
|
18
21
|
private saveSettings;
|
|
19
22
|
private scanDir;
|
|
20
23
|
private scanAll;
|
|
21
|
-
/** 기본값: project·uploaded on, global off (스펙 결정) */
|
|
24
|
+
/** 기본값: builtin·project·uploaded on, global off (스펙 결정) */
|
|
22
25
|
list(): SkillInfo[];
|
|
23
26
|
setEnabled(id: string, enabled: boolean): void;
|
|
24
27
|
upload(filename: string, content: string): SkillInfo;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pubuilder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "In-app IA minimap & block inspector for React — live iframe thumbnails of every page, plus a Next.js route scanner that drafts your ia.config (dev-only)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "taehoon",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"dist",
|
|
42
|
+
"skills",
|
|
42
43
|
"CHANGELOG.md"
|
|
43
44
|
],
|
|
44
45
|
"sideEffects": false,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish
|
|
3
|
+
description: Use when implementing a UI block from a Figma node — turning a Figma design into code inside an existing project, using that project's own style tokens and components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Figma 퍼블리싱 방법
|
|
7
|
+
|
|
8
|
+
Figma 노드를 이 프로젝트의 코드로 구현할 때 따르는 방법이다. **프레임워크 무관** — 프로젝트가 이미 쓰는 스타일 시스템(Chakra / Tailwind / MUI / styled-components / CSS Modules 등)과 기존 컴포넌트를 그대로 활용한다.
|
|
9
|
+
|
|
10
|
+
pubuilder가 이미 Figma를 **컴팩트 Design IR**(규칙 기반으로 스타일 필드만 추출, 숨김 노드 제외)과 렌더 이미지로 프롬프트에 전달한다. 이 스킬은 그것을 **어떤 태도와 순서로 코드에 옮길지**를 정의한다.
|
|
11
|
+
|
|
12
|
+
## 핵심 원칙 (모든 단계에 우선)
|
|
13
|
+
|
|
14
|
+
- **애매하거나 모르면 추측하지 말고 사용자에게 질문한다.** 추측으로 진행 금지.
|
|
15
|
+
- **문제가 생기면 우회하지 말고 멈추고 보고한다.** 노드 누락 / 스펙 불일치 / 토큰 매칭 실패 / 컴포넌트 매핑 부재 — "비슷해 보이는 값"으로 대체하거나 "아마 이 뜻일 것"으로 넘어가지 않는다.
|
|
16
|
+
- **기존 코드에서 UI 요소(컴포넌트·필드·컬럼 등)를 제거하기 전 반드시 확인한다.** 전달된 노드 JSON은 일부 노드만 담을 수 있으므로, 시안에 안 보인다고 없는 것으로 판단하지 않는다. 제거가 필요해 보이면 → 멈추고 이유와 함께 보고 → 확인 후 진행.
|
|
17
|
+
- **letter를 어기는 것은 spirit을 어기는 것이다.** 위 규칙은 다른 어떤 편의보다 우선한다.
|
|
18
|
+
|
|
19
|
+
## 1. 시안을 눈으로 먼저 본다
|
|
20
|
+
|
|
21
|
+
- 전달된 Figma 렌더 이미지를 **Read 도구로 직접 연다.**
|
|
22
|
+
- 노드 JSON의 수치를 1차 근거로 쓰되, **JSON에만 있고 이미지엔 안 보이는 요소**(hidden / opacity 0 / placeholder)는 구현하지 않는다.
|
|
23
|
+
|
|
24
|
+
## 2. 스펙을 raw 값으로 읽는다 (토큰명 추론 금지)
|
|
25
|
+
|
|
26
|
+
Design IR에서 아래를 **raw 값 그대로** 파악한다:
|
|
27
|
+
|
|
28
|
+
- size / layout(mode·align·sizing·gap·padding) / cornerRadius
|
|
29
|
+
- fills·strokes (rgba) / effects(shadow)
|
|
30
|
+
- text: 내용 + typography 5필드(font family / size / weight / lineHeight / letterSpacing)
|
|
31
|
+
- 컴포넌트 variant / INSTANCE_SWAP / BOOLEAN / TEXT 값
|
|
32
|
+
- 아이콘 내부 vector·알림 dot 같은 **decorative 요소도 누락 금지**
|
|
33
|
+
|
|
34
|
+
반복 요소(칩·카드·행)는 공통 스펙 + 인스턴스별 차이(width/text)를 **한 개도 빠짐없이** 확인한다.
|
|
35
|
+
|
|
36
|
+
## 3. 프로젝트 규약으로 변환한다
|
|
37
|
+
|
|
38
|
+
- raw 값을 **프로젝트가 이미 쓰는 토큰/유틸**로 매핑한다. 하드코딩보다 기존 토큰 우선.
|
|
39
|
+
- 토큰이 불확실하면 **토큰 정의 파일을 열어 대조**한다 — 이름을 추측하지 않는다.
|
|
40
|
+
- fill opacity < 1이면 시맨틱 토큰 대신 `rgba()`를 직접 쓴다.
|
|
41
|
+
- 컴포넌트는 **기존 컴포넌트를 재사용**한다. 같은 패턴이 이미 있으면 새로 만들지 않는다.
|
|
42
|
+
- 대상 소스 파일은 전달된 outerHTML 스냅샷과 라우트를 단서로 찾는다.
|
|
43
|
+
|
|
44
|
+
## 4. 구현
|
|
45
|
+
|
|
46
|
+
- 스타일·마크업만 시안에 맞추고, **기존 동작·이벤트 핸들러·데이터 로직은 유지**한다.
|
|
47
|
+
|
|
48
|
+
## 5. 완료 게이트 (선언 전 필수)
|
|
49
|
+
|
|
50
|
+
아래를 모두 확인한 뒤에만 "완료"라 한다. 한 칸이라도 미충족이면 완료 대신 사용자에게 보고한다:
|
|
51
|
+
|
|
52
|
+
- [ ] hidden/placeholder 노드를 잘못 구현하지 않았는가
|
|
53
|
+
- [ ] variant / INSTANCE_SWAP / 텍스트 값이 시안과 일치하는가
|
|
54
|
+
- [ ] 반복 요소의 개수·내용이 맞는가
|
|
55
|
+
- [ ] **색상·간격·타이포를 시안 이미지와 나란히 비교했는가** (코드만 보고 "맞다" 가정 금지)
|
|
56
|
+
- [ ] 프로젝트의 타입체크가 통과하는가
|
|
57
|
+
|
|
58
|
+
## 하지 않는 것
|
|
59
|
+
|
|
60
|
+
- Figma 스펙 추측 코딩 / sublayer 건너뛰기
|
|
61
|
+
- 시안 이미지에 없는 요소 추가 (비활성·숨김·placeholder 포함)
|
|
62
|
+
- 확인 없이 기존 UI 제거
|
|
63
|
+
- 이름을 추측한 토큰 사용
|