jkraccoon39 downloadsRender mid-fi web UI wireframes in notes from YAML (44 components, inline errors, typo hints) for ai co work(like claude code, codex ).
Language: English · 한국어 · 📖 Full docs · 한국어 문서
Sketch web UI wireframes from human-readable YAML — rendered inline in your Obsidian notes. 44 components. AI-friendly structure. Theme-adaptive.
사람이 읽기 쉽고 AI가 다루기 좋은 YAML로 웹 UI 와이어프레임을 그려서 Obsidian 노트 안에 바로 렌더링합니다. 컴포넌트 44개. AI 친화 구조. 테마 자동 적응.
Product specs, design briefs, RFCs, kickoff docs — when planners and UI/UX designers describe a screen in markdown, they reach for ASCII boxes:
+---------+------------------+
| Header | Actions |
+---------+------------------+
| Sidebar | Body |
| | |
+---------+------------------+
Slow to draw. Painful to edit. Easy to misalign. And worst of all, the structure is gone the moment you type it out. To your eyes it's a header with a sidebar; to anything trying to read it — a teammate skimming, a script parsing, an LLM rewriting — it's just String.split('|').
That last reader matters more than ever. A growing share of product writing now happens with an AI in the loop: co-drafting the spec, asking the model to revise a layout, generating screen variants from a brief. AI is excellent at reasoning over structured data and miserable at decoding ASCII rectangles. Your spec ends up being two things at once — a picture humans can almost read, and a string the model can't understand. Neither audience is well served.
UI Sketch is one simple trade. Stop drawing the UI in text. Describe it in YAML instead:
screen:
- navbar: { brand: "DocHub" }
- row:
items:
- col: { flex: 1, items: [ { sidebar: { items: ["Home", "Docs"] } } ] }
- col: { flex: 3, items: [ { card: { title: "Welcome" } } ] }
One source. Three audiences:
That's the whole pitch. Anywhere you'd otherwise reach for an ASCII sketch — spec docs, design briefs, RFCs, AI-assisted product threads — you get a single artifact that you, your reviewers, and your tools can all edit.

Drop this in a ```ui-sketch fenced block, switch to Reading view, and the wireframe appears inline.
viewport: desktop
screen:
- navbar: { brand: "DocHub", items: ["Home", "Docs", "Pricing"] }
- row:
gap: 16
items:
- col:
flex: 1
items:
- sidebar: { items: ["Getting Started", "API", "FAQ"] }
- col:
flex: 3
items:
- heading: { level: 1, text: "Welcome back" }
- row:
gap: 12
items:
- card: { title: "Tasks", body: "12 open" }
- card: { title: "Docs", body: "3 drafts" }
- button:
label: "New document"
variant: primary
note: "Navigates to /documents/new"
A single viewport: key flips between desktop, tablet, and mobile:
|
|
|
| Pain | Before (ASCII) | After (UI Sketch) |
|---|---|---|
| Aligning columns | │ Header │ Actions │ gymnastics |
- row: { items: [...] } |
| Tweaking layout | Retype the entire diagram | Edit one line of YAML |
| Reading someone else's sketch | Decode what the boxes meant | Render it and see |
| Keeping vault consistent with theme | Manual color adjustments | Uses Obsidian CSS variables automatically |
| Asking an LLM to revise the layout | Paste an ambiguous picture | Paste structured YAML |
var(--interactive-accent) and friends.raw: escape hatch runs through sanitize-html — no XSS surface.One-click from Obsidian Community (recommended):
From inside Obsidian — Settings → Community plugins → Browse → search UI Sketch → Install → enable.
Pre-release / dev build (BRAT):
jkRaccoon/obsidian-ui-sketch.Manual install:
main.js, manifest.json, and styles.css from the latest release. Release assets are signed with GitHub artifact attestations; verify with gh attestation verify main.js --repo jkRaccoon/obsidian-ui-sketch.<your-vault>/.obsidian/plugins/ui-sketch/.In any note, add a fenced code block tagged ui-sketch:
```ui-sketch
screen:
- navbar: { brand: "MyApp" }
- button: { label: "Sign in", variant: primary }
```
Switch to Reading view (Ctrl/Cmd+E). You'll see a rendered wireframe.
Full documentation lives in docs/:
44 components in 8 categories, plus one escape hatch. Every component accepts the base props (id, w, h, align, pad, note, muted) on top of its type-specific props. Detailed prop tables live in the Component Reference.
| Category | Components |
|---|---|
| Layout structure | container · card · panel · divider · spacer |
| Navigation | navbar · sidebar · tabs · breadcrumb · pagination · stepper |
| Basic input | button · input · textarea · select · checkbox · radio |
| Advanced input | toggle · slider · date-picker · file-upload · search |
| Display | heading · text · image · icon · avatar · badge · tag · kbd |
| Feedback | alert · progress · toast · modal · skeleton |
| Data | table · list · tree · kv-list |
| Placeholder | chart · map · video · placeholder |
| Escape hatch | raw (sanitized HTML) |
A few examples:
alert:
severity: warn
title: "Heads up"
message: "Review before committing."
table:
columns: ["Name", "Role", "Status"]
rows:
- ["Ada", "PM", "✓"]
- ["Ben", "ENG", "…"]
tree:
items:
- label: "src"
children:
- { label: "main.ts" }
- { label: "types.ts" }
- { label: "docs" }
kbd:
keys: ["Ctrl", "K"]
See the YAML Reference for complete syntax. Quick overview:
viewport: desktop | tablet | mobile | custom # default: desktop (1200px)
width: 375 # custom only
height: 640 # custom only
theme: adaptive # v0.2 only supports "adaptive"
background: default | muted | transparent
screen: # required: array OR grid
- ...
Two layout models, mutually exclusive at the root:
Flex (row/col nesting) — primary model, fits 99% of web UIs:
screen:
- row:
gap: 12
items:
- col: { flex: 1, items: [ { sidebar: {...} } ] }
- col: { flex: 3, items: [ ... ] }
Named-area grid — for dashboard layouts:
screen:
grid:
areas:
- "nav nav nav"
- "side main main"
- "side foot foot"
cols: "180px 1fr 1fr"
rows: "56px 1fr 48px"
map:
nav: { navbar: { brand: "MyApp" } }
side: { sidebar: { items: ["Home", "Docs"] } }
main: { card: { title: "Welcome" } }
foot: { text: { value: "© 2026" } }
UI Sketch never fails silently. Every problem gets surfaced with something actionable.
| Level | When | Result |
|---|---|---|
| L1 YAML parse error | Malformed YAML | Full-block error box with line/col |
| L2 Structure error | Missing screen, unknown viewport, etc. |
Full-block error box with path |
| L3 Component error | Unknown component type or invalid props | Inline error box at that component's position — rest of the wireframe still renders |
| L4 Empty block | No content | Friendly placeholder with a starter example |
Typo suggestions (Levenshtein distance ≤ 2):
⚠
butn: unknown component type · Did you mean "button"?
Safety caps:
raw: HTML always runs through sanitize-html — no <script>, no inline event handlers.Common causes and fixes are in Troubleshooting.
Open Settings → Community plugins → UI Sketch:
| Setting | Default | Notes |
|---|---|---|
| Default viewport | desktop |
Applied to any block that omits viewport: |
| Default theme | adaptive |
Locked in v0.2 |
| Compact mode | Off | Scales spacing and fonts by ×0.875 — useful when stacking several blocks in one note |
# Requires Node 18+
npm install
npm run dev # esbuild watch mode
npm test # vitest (happy-dom)
npm run lint # eslint with obsidianmd/recommended ruleset
npm run typecheck # tsc --noEmit
npm run build # production bundle → main.js
Plugin files at repo root:
main.js — bundled pluginmanifest.json — plugin metadata for Obsidianstyles.css — theme-adaptive stylingSource organized by responsibility:
src/
├── main.ts Plugin lifecycle, code-block processor
├── settings.ts Settings tab + data model
├── types.ts Shared AST types
├── parser/ YAML → document (+ location info)
├── schema/ Structural validation + per-component zod
├── components/ 44 builtin components, each a single file
├── renderer/ Dispatches layout tree → DOM
├── styler/ Viewport frame, theme hooks
└── errors/ L1/L2/L3 error rendering
raw: + sanitize-html, zod schemas per component, auto-generated component docs, recipe screenshots, signed release workflow (GitHub artifact attestation), Obsidian Community directory submission.eslint-plugin-obsidianmd ruleset (createDiv/createSpan helpers, activeDocument for popout windows, stricter style/DOM hygiene).Design specs in docs/superpowers/specs/; implementation plans in docs/superpowers/plans/.
If UI Sketch saves you time on your wireframes, consider sponsoring on GitHub. Sponsorships fund time spent on this plugin and future Obsidian tools.
Issues and PRs welcome. For a bigger change, please open an issue first so we can talk through the design. Small fixes can go straight to a PR.
기획서, 디자인 브리프, RFC, 킥오프 문서 — 기획자나 UI/UX 디자이너가 마크다운으로 화면을 설명할 때, 결국 ASCII 박스를 찾게 됩니다:
+---------+------------------+
| 헤더 | 액션 |
+---------+------------------+
| 사이드바 | 본문 |
| | |
+---------+------------------+
그리기 느립니다. 수정 고통스럽습니다. 정렬 어긋나기 일쑤입니다. 그리고 무엇보다도 타이핑하는 순간 구조가 사라집니다. 당신 눈에는 헤더와 사이드바지만, 그걸 읽는 무엇이든 — 훑어보는 동료, 파싱하는 스크립트, 다시 쓰는 LLM — 보기에는 그냥 String.split('|')일 뿐이죠.
이 마지막 독자가 요즘 점점 더 중요해지고 있습니다. 기획 글쓰기의 상당 부분이 이제 AI와 함께 이뤄집니다 — 모델과 스펙을 함께 다듬고, 레이아웃을 수정해달라고 하고, 브리프로부터 새 화면 안을 만들어내죠. AI는 구조화된 데이터를 다루는 데 뛰어나지만 ASCII 사각형을 해독하는 건 못합니다. 결과적으로 스펙은 두 가지가 동시에 됩니다 — 사람이 거의 읽을 수 있는 그림이자, 모델이 이해 못 하는 문자열. 두 독자 모두 제대로 대접받지 못하는 거죠.
UI Sketch는 한 가지 단순한 거래입니다. UI를 텍스트로 그리지 마세요. 대신 YAML로 설명하세요:
screen:
- navbar: { brand: "DocHub" }
- row:
items:
- col: { flex: 1, items: [ { sidebar: { items: ["Home", "Docs"] } } ] }
- col: { flex: 3, items: [ { card: { title: "Welcome" } } ] }
하나의 소스, 세 명의 독자:
이게 전부입니다. ASCII 스케치가 등장할 자리라면 어디든 — 기획서, 디자인 브리프, RFC, AI 협업 제품 스레드 — 당신과 리뷰어와 도구가 모두 함께 편집할 수 있는 단일 산출물이 됩니다.
아래 YAML을 ```ui-sketch 코드 블록 안에 넣고 읽기 뷰로 전환하면, 노트 안에서 와이어프레임이 바로 렌더링됩니다.
viewport: desktop
screen:
- navbar: { brand: "DocHub", items: ["Home", "Docs", "Pricing"] }
- row:
gap: 16
items:
- col:
flex: 1
items:
- sidebar: { items: ["Getting Started", "API", "FAQ"] }
- col:
flex: 3
items:
- heading: { level: 1, text: "Welcome back" }
- row:
gap: 12
items:
- card: { title: "Tasks", body: "12 open" }
- card: { title: "Docs", body: "3 drafts" }
- button:
label: "New document"
variant: primary
note: "Navigates to /documents/new"
viewport: 한 줄로 데스크톱부터 모바일까지 전환됩니다:
|
|
|
| 고통 | 이전 (ASCII) | 이후 (UI Sketch) |
|---|---|---|
| 열 맞추기 | │ Header │ Actions │ 체조 |
- row: { items: [...] } |
| 레이아웃 조정 | 다이어그램 전체 재작성 | YAML 한 줄 수정 |
| 다른 사람 스케치 읽기 | 박스가 뭘 의미하는지 해독 | 렌더링해서 그대로 봄 |
| 테마 일관성 유지 | 수동 색상 조정 | Obsidian CSS 변수로 자동 |
| AI에게 레이아웃 수정 요청 | 모호한 그림 붙여넣기 | 구조화된 YAML 붙여넣기 |
var(--interactive-accent) 같은 변수로 자동 상속합니다.raw: 탈출구는 sanitize-html을 거치므로 XSS 우려 없음.Obsidian Community 페이지에서 한 번에 설치 (권장):
Obsidian 안에서 직접 — 설정 → 커뮤니티 플러그인 → 둘러보기 → UI Sketch 검색 → 설치 → 활성화.
프리릴리스 / 개발 빌드 (BRAT):
jkRaccoon/obsidian-ui-sketch.수동 설치:
main.js, manifest.json, styles.css 다운로드. 릴리스 자산은 GitHub artifact attestation으로 서명되어 있어, gh attestation verify main.js --repo jkRaccoon/obsidian-ui-sketch 명령으로 출처 검증이 가능합니다.<your-vault>/.obsidian/plugins/ui-sketch/에 복사.아무 노트에 ui-sketch 태그 코드 블록을 추가:
```ui-sketch
screen:
- navbar: { brand: "MyApp" }
- button: { label: "Sign in", variant: primary }
```
읽기 뷰로 전환 (Ctrl/Cmd+E). 와이어프레임이 보입니다.
전체 한국어 문서는 docs/ko/에 있습니다:
8개 카테고리 44개 컴포넌트 + 탈출구 하나. 모든 컴포넌트는 타입별 프롭 위에 공통 프롭(id, w, h, align, pad, note, muted)을 받습니다. 상세 프롭 표는 컴포넌트 레퍼런스 참고.
| 카테고리 | 컴포넌트 |
|---|---|
| 레이아웃 | container · card · panel · divider · spacer |
| 내비게이션 | navbar · sidebar · tabs · breadcrumb · pagination · stepper |
| 기본 입력 | button · input · textarea · select · checkbox · radio |
| 고급 입력 | toggle · slider · date-picker · file-upload · search |
| 표시 | heading · text · image · icon · avatar · badge · tag · kbd |
| 피드백 | alert · progress · toast · modal · skeleton |
| 데이터 | table · list · tree · kv-list |
| 플레이스홀더 | chart · map · video · placeholder |
| 탈출구 | raw (sanitize된 HTML) |
예시 몇 가지:
alert:
severity: warn
title: "Heads up"
message: "Review before committing."
table:
columns: ["Name", "Role", "Status"]
rows:
- ["Ada", "PM", "✓"]
- ["Ben", "ENG", "…"]
tree:
items:
- label: "src"
children:
- { label: "main.ts" }
- { label: "types.ts" }
- { label: "docs" }
kbd:
keys: ["Ctrl", "K"]
전체 문법은 YAML 레퍼런스 참고. 간단 개요:
viewport: desktop | tablet | mobile | custom # 기본값: desktop (1200px)
width: 375 # custom일 때만
height: 640 # custom일 때만
theme: adaptive # v0.2는 "adaptive"만 지원
background: default | muted | transparent
screen: # 필수: 배열 OR grid
- ...
두 가지 레이아웃 모델 (최상위에서 상호 배타):
Flex (row/col 중첩) — 기본 모델, 웹 UI 99% 커버:
screen:
- row:
gap: 12
items:
- col: { flex: 1, items: [ { sidebar: {...} } ] }
- col: { flex: 3, items: [ ... ] }
Named-area grid — 대시보드 레이아웃용:
screen:
grid:
areas:
- "nav nav nav"
- "side main main"
- "side foot foot"
cols: "180px 1fr 1fr"
rows: "56px 1fr 48px"
map:
nav: { navbar: { brand: "MyApp" } }
side: { sidebar: { items: ["Home", "Docs"] } }
main: { card: { title: "Welcome" } }
foot: { text: { value: "© 2026" } }
UI Sketch는 조용히 실패하지 않습니다. 항상 대응 가능한 메시지를 보여줍니다.
| 레벨 | 상황 | 결과 |
|---|---|---|
| L1 YAML 파싱 에러 | 문법 오류 | 블록 전체 에러 박스 + 줄/열 |
| L2 구조 에러 | screen 누락, 알 수 없는 viewport 등 |
블록 전체 에러 박스 + 경로 |
| L3 컴포넌트 에러 | 알 수 없는 컴포넌트 타입 또는 잘못된 프롭 | 해당 위치에 인라인 에러 박스 — 나머지는 정상 렌더링 |
| L4 빈 블록 | 내용 없음 | 친절한 플레이스홀더 + 예시 코드 |
오타 제안 (Levenshtein 거리 ≤ 2):
⚠
butn: unknown component type · Did you mean "button"?
안전 제한:
raw: HTML은 항상 sanitize-html을 통과 — <script> 불가, 인라인 이벤트 핸들러 불가.자주 마주치는 문제와 해결법은 문제 해결 참고.
설정 → 커뮤니티 플러그인 → UI Sketch:
| 항목 | 기본값 | 비고 |
|---|---|---|
| 기본 viewport | desktop |
viewport: 생략한 블록에 적용 |
| 기본 theme | adaptive |
v0.2에서는 고정 |
| Compact 모드 | 꺼짐 | 간격과 폰트를 ×0.875로 축소 — 한 노트에 블록 여러 개 쌓을 때 유용 |
# Node 18+ 필요
npm install
npm run dev # esbuild watch 모드
npm test # vitest (happy-dom)
npm run lint # obsidianmd/recommended 룰셋으로 eslint
npm run typecheck # tsc --noEmit
npm run build # 프로덕션 번들 → main.js
저장소 루트 플러그인 파일:
main.js — 번들된 플러그인manifest.json — Obsidian 플러그인 메타데이터styles.css — 테마 적응형 스타일책임별로 구성된 소스:
src/
├── main.ts 플러그인 생명주기, 코드 블록 프로세서
├── settings.ts 설정 탭 + 데이터 모델
├── types.ts 공용 AST 타입
├── parser/ YAML → document (+ 위치 정보)
├── schema/ 구조 검증 + 컴포넌트별 zod
├── components/ 내장 컴포넌트 44개, 각각 파일 하나
├── renderer/ 레이아웃 트리 → DOM 디스패치
├── styler/ viewport 프레임, 테마 훅
└── errors/ L1/L2/L3 에러 렌더링
raw: + sanitize-html, 컴포넌트별 zod 스키마, 자동 생성 컴포넌트 문서, 레시피 스크린샷, 서명된 릴리스 워크플로우(GitHub artifact attestation), Obsidian Community 디렉토리 등록.eslint-plugin-obsidianmd 룰셋 적용 (createDiv/createSpan 헬퍼, 팝아웃 창 호환을 위한 activeDocument, 더 엄격한 스타일/DOM 규칙).설계 스펙은 docs/superpowers/specs/, 구현 플랜은 docs/superpowers/plans/ 참고.
UI Sketch가 와이어프레임 시간을 아껴준다면 **GitHub 후원**을 고려해주세요. 후원은 이 플러그인과 향후 Obsidian 도구 개발 시간으로 쓰입니다.
이슈와 PR 환영합니다. 큰 변경은 디자인을 논의할 수 있도록 먼저 이슈를 열어주세요. 작은 수정은 바로 PR 주셔도 됩니다.
MIT © 2026 jikwangkim
Built with TypeScript, esbuild, zod, js-yaml, sanitize-html, and Vitest · happy-dom. Linted with eslint-plugin-obsidianmd.