diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4109164 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,266 @@ +# Contributing to Open Design + +Thanks for thinking about contributing. OD is small on purpose — most of the value lives in **files** (skills, design systems, prompt fragments) rather than framework code. That means the highest-leverage contributions are usually one folder, one Markdown file, or one PR-sized adapter. + +This guide tells you exactly where to look for each type of contribution and what bar a PR has to clear before we merge it. + +

English · 简体中文

+ +--- + +## Three things you can ship in one afternoon + +| If you want to… | You're really adding | Where it lives | Ship size | +|---|---|---|---| +| Make OD render a new kind of artifact (an invoice, an iOS Settings screen, a one-pager…) | a **Skill** | [`skills//`](skills/) | one folder, ~2 files | +| Make OD speak a new brand's visual language | a **Design System** | [`design-systems//DESIGN.md`](design-systems/) | one Markdown file | +| Hook up a new coding-agent CLI | an **Agent adapter** | [`daemon/agents.js`](daemon/agents.js) | ~10 lines in one array | +| Add a feature, fix a bug, lift a UX pattern from [`open-codesign`][ocod] | code | `src/`, `daemon/` | normal PR | +| Improve docs, port a section to 中文, fix typos | docs | `README.md`, `README.zh-CN.md`, `docs/`, `QUICKSTART.md` | one PR | + +If you're not sure which bucket your idea is in, [open a discussion / issue first](https://github.com/nexu-io/open-design/issues/new) and we'll point you at the right surface. + +--- + +## Local setup + +The full one-page setup lives in [`QUICKSTART.md`](QUICKSTART.md). The TL;DR for contributors: + +```bash +git clone https://github.com/nexu-io/open-design.git +cd open-design +pnpm install # or npm install +pnpm dev:all # daemon (:7456) + Vite (:5173) +pnpm typecheck # tsc -b --noEmit +pnpm build # production build +``` + +Node 18+ is required. macOS, Linux, and WSL2 are tested daily. Windows native should work but isn't a primary target — file an issue if it doesn't. + +You don't need any agent CLI on your `PATH` to develop OD itself — the daemon will tell you "no agents found" and fall back to the **Anthropic API · BYOK** path, which is the fastest dev loop anyway. + +--- + +## Adding a new Skill + +A skill is a folder under [`skills/`](skills/) with a `SKILL.md` at the root, following Claude Code's [`SKILL.md` convention][skill] plus our optional `od:` extension. **No registration step.** Drop the folder in, restart the daemon, the picker shows it. + +### Skill folder layout + +```text +skills/your-skill/ +├── SKILL.md # required +├── assets/template.html # optional but recommended — the seed file +├── references/ # optional — knowledge files the agent reads +│ ├── layouts.md +│ ├── components.md +│ └── checklist.md +└── example.html # strongly recommended — a real, hand-built sample +``` + +### `SKILL.md` frontmatter + +The first three keys are the Claude Code base spec — `name`, `description`, `triggers`. Everything under `od:` is OD-specific and optional, but **`od.mode`** decides which group the skill shows up in (Prototype / Deck / Template / Design system). + +```yaml +--- +name: your-skill +description: | + One-paragraph elevator pitch. The agent reads this verbatim to decide + if the user's brief matches. Be concrete: surface, audience, what's in + the artifact, what's not. +triggers: + - "your trigger phrase" + - "another phrase" + - "中文触发词" +od: + mode: prototype # prototype | deck | template | design-system + platform: desktop # desktop | mobile + scenario: marketing # free-form tag for grouping + featured: 1 # any positive integer surfaces it under "Showcase examples" + preview: + type: html # html | jsx | pptx | markdown + entry: index.html + design_system: + requires: true # does the skill read the active DESIGN.md? + sections: [color, typography, layout, components] + example_prompt: "A copy-pastable prompt that nicely shows what this skill does." +--- + +# Your Skill + +Body is free-form Markdown describing the workflow the agent should follow… +``` + +The full grammar — typed inputs, slider parameters, capability gating — lives in [`docs/skills-protocol.md`](docs/skills-protocol.md). + +### Bar for merging a new skill + +We're picky about skills because they're the user-facing surface. A new skill must: + +1. **Ship a real `example.html`.** Hand-built, opens straight from disk, looks like something a designer would actually deliver. No lorem ipsum, no `` placeholder hero. If you can't build the example yourself, the skill probably isn't ready. +2. **Pass the anti-AI-slop checklist** in the body. No purple gradients, no generic emoji icons, no rounded card with a left-border accent, no Inter as a *display* face, no invented stats. Read the **Anti-AI-slop machinery** section of the README for the full list. +3. **Honest placeholders.** When the agent doesn't have a real number, write `—` or a labelled grey block, not "10× faster". +4. **Have a `references/checklist.md`** with at least P0 gates (the stuff the agent has to pass before emitting ``). Lift the format from [`skills/guizang-ppt/references/checklist.md`](skills/guizang-ppt/) or [`skills/dating-web/references/checklist.md`](skills/dating-web/). +5. **Add a screenshot** at `docs/screenshots/skills/.png` if the skill is featured. PNG, ~1024×640 retina, captured from the real `example.html` at zoomed-out browser scale. +6. **Be a single self-contained folder.** No CDN imports beyond what other skills already use; no fonts you didn't license; no images larger than ~250 KB. + +If you fork an existing skill (e.g. start from `dating-web` and remix into a `recruiting-web`), keep the original LICENSE and authorship in `references/` and call it out in your PR description. + +### Skills that already ship — pick one to imitate + +- Visual showcase, single-screen prototype: [`skills/dating-web/`](skills/dating-web/), [`skills/digital-eguide/`](skills/digital-eguide/) +- Multi-frame mobile flow: [`skills/mobile-onboarding/`](skills/mobile-onboarding/), [`skills/gamified-app/`](skills/gamified-app/) +- Document / template (no design system required): [`skills/pm-spec/`](skills/pm-spec/), [`skills/weekly-update/`](skills/weekly-update/) +- Deck mode: [`skills/guizang-ppt/`](skills/guizang-ppt/) (bundled verbatim from [op7418/guizang-ppt-skill][guizang]) and [`skills/simple-deck/`](skills/simple-deck/) + +--- + +## Adding a new Design System + +A design system is a single [`DESIGN.md`](design-systems/README.md) file under `design-systems//`. **One file, no code.** Drop it in, restart the daemon, the picker shows it grouped by category. + +### Design system folder layout + +```text +design-systems/your-brand/ +└── DESIGN.md +``` + +### `DESIGN.md` shape + +```markdown +# Design System Inspired by YourBrand + +> Category: Developer Tools +> One-line summary that shows in the picker preview. + +## 1. Visual Theme & Atmosphere +… + +## 2. Color +- Primary: `#hex` / `oklch(...)` +- … + +## 3. Typography +… + +## 4. Spacing & Grid +## 5. Layout & Composition +## 6. Components +## 7. Motion & Interaction +## 8. Voice & Brand +## 9. Anti-patterns +``` + +The 9-section schema is fixed — that's what skill bodies grep for. The first H1 becomes the picker label (the `Design System Inspired by` prefix is stripped automatically), and the `> Category: …` line decides which group it lands in. Existing categories are listed in [`design-systems/README.md`](design-systems/README.md); if your brand truly doesn't fit, you can introduce a new one, but **try existing categories first**. + +### Bar for merging a new design system + +1. **All 9 sections present.** Empty section bodies are fine for hard-to-find data (e.g. motion tokens), but the headings have to be there or the prompt grep breaks. +2. **Hex codes are real.** Sample directly from the brand's site or product, not from memory or AI guesses. The README's "brand-spec extraction" 5-step protocol applies to maintainers too. +3. **OKLch values for accent colors** are nice-to-have. They make palettes lerp predictably across light/dark. +4. **No marketing fluff.** The brand's tagline is not a design token. Cut it. +5. **Slug uses ASCII** — `linear.app` becomes `linear-app`, `x.ai` becomes `x-ai`. The 69 imported systems already follow this convention; mirror it. + +The 69 product systems we ship are imported from [`VoltAgent/awesome-design-md`][acd2] via [`scripts/sync-design-systems.mjs`](scripts/sync-design-systems.mjs). If your brand belongs upstream, **send the PR there first** — we'll pick it up automatically on the next sync. The `design-systems/` folder is for systems that don't fit upstream, plus our two hand-authored starters. + +--- + +## Adding a new coding-agent CLI + +Hooking up a new agent (e.g. some new shop's `foo-coder` CLI) is one entry in [`daemon/agents.js`](daemon/agents.js): + +```javascript +{ + id: 'foo', + name: 'Foo Coder', + bin: 'foo', + versionArgs: ['--version'], + buildArgs: (prompt) => ['exec', '-p', prompt], + streamFormat: 'plain', // or 'claude-stream-json' if it speaks that +} +``` + +That's it — daemon will detect it on `PATH`, the picker shows it, the chat path works. If the CLI emits **typed events** (like Claude Code's `--output-format stream-json`), wire a parser in [`daemon/claude-stream.js`](daemon/claude-stream.js) and set `streamFormat: 'claude-stream-json'`. + +Bar for merging: + +1. **A real session works end-to-end** with the new agent — paste the daemon log into the PR description showing it streamed an artifact through. +2. **`docs/agent-adapters.md`** is updated with the CLI's quirks (does it require a key file? does it support image input? what's its non-interactive flag?). +3. **The README's "Supported coding agents" table** gets one row. + +--- + +## Code style + +We're not pedantic about formatting (Prettier on save is fine), but two rules are non-negotiable because they show up in the prompt stack and the user-facing API: + +1. **Single quotes in JS/TS.** Strings are single-quoted unless escaping makes them ugly. The codebase is already consistent — please match. +2. **Comments in English.** Even if the PR is translating something into 中文, code comments stay in English so we can keep one set of greppable references. + +Beyond that: + +- **Don't narrate.** No `// import the module`, no `// loop through items`. If the code reads obviously, the comment is noise. Save comments for non-obvious intent or constraints the code can't express. +- **TypeScript** for `src/`. The daemon (`daemon/`) is plain ESM JavaScript with JSDoc when types matter — keep it that way. +- **No new top-level dependencies** without a paragraph in the PR description on what we get vs. what bytes we ship. The dep list in [`package.json`](package.json) is small on purpose. +- **Run `pnpm typecheck`** before pushing. CI runs it; failing it earns a "please fix" comment. + +--- + +## Commits & pull requests + +- **One concern per PR.** Adding a skill + refactoring the parser + bumping a dep is three PRs. +- **Title is imperative + scope.** `add dating-web skill`, `fix daemon SSE backpressure when CLI hangs`, `docs: clarify .od layout`. +- **Body explains the why.** "What does this do" is usually obvious from the diff; "why does this need to exist" rarely is. +- **Reference an issue** if there is one. If there isn't and the PR is non-trivial, open one first so we can agree the change is wanted before you spend the time. +- **No squash-during-review.** Push fixups; we'll squash on merge. +- **No force-push to a shared branch** unless the reviewer asked. + +We don't enforce a CLA. Apache-2.0 covers us; your contribution is licensed under the same. + +--- + +## Reporting bugs + +Open an issue with: + +- What you ran (the exact `pnpm dev:all` / `npm start` invocation). +- Which agent CLI was selected (or whether you were on the BYOK path). +- The skill + design system pair that triggered it. +- The relevant **daemon stderr tail** — most "the artifact never rendered" reports get diagnosed in 30 seconds when we can see `spawn ENOENT` or the CLI's actual error. +- A screenshot if it's UI. + +For prompt-stack bugs ("the agent emitted a purple gradient hero, the slop blacklist was supposed to forbid that"), include the **full assistant message** so we can see whether the violation was the model or the prompt. + +--- + +## Asking questions + +- Architecture question, design question, "is this a bug or a misuse" → [GitHub Discussions](https://github.com/nexu-io/open-design/discussions) (preferred — searchable for the next person). +- "How do I write a skill that does X" → Open a discussion. We'll answer it and turn the answer into [`docs/skills-protocol.md`](docs/skills-protocol.md) if it's a missing pattern. + +--- + +## What we don't accept + +To keep the project focused, please don't open PRs that: + +- **Vendor a model runtime.** OD's whole bet is "your existing CLI is enough". We don't ship `pi-ai`, OpenAI keys, or model loaders. +- **Add a new framework to the frontend.** Vite + React 18 + TS is the line. No Next.js, Astro, Solid, Svelte rewrites. +- **Replace the daemon with a serverless function.** The daemon's whole point is owning a real `cwd` and spawning a real CLI. Vercel deployment of the SPA is fine; the daemon stays a daemon. +- **Add telemetry / analytics / phone-home.** OD is local-first. The only outbound calls are to providers the user explicitly configured. +- **Bundle a binary** without a license file and authorship attribution next to it. + +If you're not sure whether your idea fits, open a discussion before writing the code. + +--- + +## License + +By contributing, you agree your contribution is licensed under the [Apache-2.0 License](LICENSE) of this repository, with the exception of files inside [`skills/guizang-ppt/`](skills/guizang-ppt/), which retain their original MIT license and authorship attribution to [op7418](https://github.com/op7418). + +[skill]: https://docs.anthropic.com/en/docs/claude-code/skills +[guizang]: https://github.com/op7418/guizang-ppt-skill +[acd2]: https://github.com/VoltAgent/awesome-design-md +[ocod]: https://github.com/OpenCoworkAI/open-codesign diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md new file mode 100644 index 0000000..5e44c39 --- /dev/null +++ b/CONTRIBUTING.zh-CN.md @@ -0,0 +1,265 @@ +# 贡献指南 · Contributing to Open Design + +谢谢你愿意参与。OD 是有意做小的 —— 大部分价值在 **文件** 里(skill、design system、提示词片段),而不是框架代码。这意味着收益最高的贡献往往就是一个文件夹、一份 Markdown,或者一个 PR 大小的 adapter。 + +这份指南会告诉你:每种贡献该往哪里看、合并之前 PR 需要过哪些线。 + +

English · 简体中文

+ +--- + +## 一个下午就能交付的三件事 + +| 你想要…… | 你其实在加的是 | 它住在哪 | 体量 | +|---|---|---|---| +| 让 OD 渲染一种新的 artifact(一份发票、一个 iOS 设置页、一张 one-pager……) | 一个 **Skill** | [`skills//`](skills/) | 一个文件夹,约 2 个文件 | +| 让 OD 说一种新品牌的视觉语言 | 一套 **Design System** | [`design-systems//DESIGN.md`](design-systems/) | 一个 Markdown 文件 | +| 接入一个新的 coding-agent CLI | 一个 **Agent adapter** | [`daemon/agents.js`](daemon/agents.js) | 一个数组里 ~10 行 | +| 加功能、修 bug、从 [`open-codesign`][ocod] 移植一个 UX 模式 | 代码 | `src/`、`daemon/` | 普通 PR | +| 改文档、补中文翻译、修错别字 | 文档 | `README.md`、`README.zh-CN.md`、`docs/`、`QUICKSTART.md` | 一个 PR | + +不确定自己想做的属于哪一桶?[先开 issue / discussion](https://github.com/nexu-io/open-design/issues/new),我们告诉你该改哪个面。 + +--- + +## 本地起跑 + +完整的一页式 setup 在 [`QUICKSTART.md`](QUICKSTART.md)。给贡献者的 TL;DR: + +```bash +git clone https://github.com/nexu-io/open-design.git +cd open-design +pnpm install # 或 npm install +pnpm dev:all # daemon (:7456) + Vite (:5173) +pnpm typecheck # tsc -b --noEmit +pnpm build # 生产构建 +``` + +要求 Node 18+。macOS、Linux、WSL2 每天都在跑。Windows 原生应该能跑但不是主要目标 —— 跑不起来请开 issue。 + +**开发 OD 本身不需要在 `PATH` 上装任何 agent CLI** —— daemon 会告诉你「找不到 agent」并落到 **Anthropic API · BYOK** 路径,反而是最快的开发循环。 + +--- + +## 加一个 Skill + +一个 skill 就是 [`skills/`](skills/) 下的一个文件夹,根目录放一个 `SKILL.md`,遵循 Claude Code 的 [`SKILL.md` 规范][skill],再加上我们可选的 `od:` 扩展。**没有注册步骤。** 文件夹丢进来、重启 daemon、picker 里就出现了。 + +### Skill 文件夹结构 + +```text +skills/your-skill/ +├── SKILL.md # 必须 +├── assets/template.html # 可选但强烈推荐 —— seed 模板 +├── references/ # 可选 —— agent 在规划阶段会读的知识文件 +│ ├── layouts.md +│ ├── components.md +│ └── checklist.md +└── example.html # 强烈推荐 —— 一份手搓的真实样例 +``` + +### `SKILL.md` 的 frontmatter + +前三个字段是 Claude Code 的基础规范 —— `name`、`description`、`triggers`。`od:` 下面所有字段都是 OD 特有的、可选的,但 **`od.mode`** 决定 skill 出现在哪一组(Prototype / Deck / Template / Design system)。 + +```yaml +--- +name: your-skill +description: | + 一段电梯演讲。Agent 会原样读这段来判断用户的需求是否匹配。 + 写具体一点:surface、受众、artifact 里有什么、没有什么。 +triggers: + - "your trigger phrase" + - "another phrase" + - "中文触发词" +od: + mode: prototype # prototype | deck | template | design-system + platform: desktop # desktop | mobile + scenario: marketing # 自由 tag,用来分组 + featured: 1 # 任何正整数都会让它出现在「Showcase examples」 + preview: + type: html # html | jsx | pptx | markdown + entry: index.html + design_system: + requires: true # 这个 skill 是否会读激活的 DESIGN.md + sections: [color, typography, layout, components] + example_prompt: "一段可复制粘贴的提示词,最能体现这个 skill 的能力。" +--- + +# Your Skill + +正文是自由 Markdown,描述 agent 应该走的工作流…… +``` + +完整 grammar —— 类型化输入、滑块参数、能力 gating —— 在 [`docs/skills-protocol.md`](docs/skills-protocol.md)。 + +### 合并新 skill 的硬线 + +Skill 是用户直接看到的面,所以我们对它挑剔。一个新 skill 必须: + +1. **附一份真实的 `example.html`。** 手搓的、本地直接打开就能看、像设计师真的会交付的东西。不要 lorem ipsum,不要 `` 占位 hero。如果你自己都不能搓出 example,这个 skill 大概率还没准备好。 +2. **过 anti-AI-slop checklist**(写在 body 里)。不准紫色渐变、不准通用 emoji 图标、不准左 border 圆角卡片、不准把 Inter 当 *display* 字体、不准自编数据。完整黑名单看 README 的「Anti-AI-slop machinery」一节。 +3. **诚实占位。** Agent 没真数字时写 `—` 或一个标注的灰块,绝不写「快 10 倍」。 +4. **附 `references/checklist.md`**,至少要有 P0 关卡(agent emit `` 之前必须过的硬线)。格式照搬 [`skills/guizang-ppt/references/checklist.md`](skills/guizang-ppt/) 或 [`skills/dating-web/references/checklist.md`](skills/dating-web/)。 +5. **如果是 featured skill,加一张截图** 到 `docs/screenshots/skills/.png`。PNG 格式,约 1024×640 retina,从真实 `example.html` 上以缩小后的浏览器倍率截。 +6. **是一个自包含文件夹。** CDN 引入不能超过其他 skill 已经引入的;不准用没授权的字体;图片不要超过约 250 KB。 + +如果你 fork 了一个现有 skill(比如从 `dating-web` 改成 `recruiting-web`),保留原 LICENSE 和原作者归属在 `references/` 里,并在 PR 描述里点出来。 + +### 已有的 skill —— 挑一个像的来抄 + +- 视觉 showcase、单屏原型:[`skills/dating-web/`](skills/dating-web/)、[`skills/digital-eguide/`](skills/digital-eguide/) +- 多屏移动流程:[`skills/mobile-onboarding/`](skills/mobile-onboarding/)、[`skills/gamified-app/`](skills/gamified-app/) +- 文档 / 模板(不需要 design system):[`skills/pm-spec/`](skills/pm-spec/)、[`skills/weekly-update/`](skills/weekly-update/) +- Deck 模式:[`skills/guizang-ppt/`](skills/guizang-ppt/)(来自 [op7418/guizang-ppt-skill][guizang],原样捆绑)和 [`skills/simple-deck/`](skills/simple-deck/) + +--- + +## 加一套 Design System + +一套 design system 就是 `design-systems//` 下的一个 [`DESIGN.md`](design-systems/README.md) 文件。**一个文件,零代码。** 丢进来、重启 daemon、picker 按 category 分组显示出来。 + +### Design system 文件夹结构 + +```text +design-systems/your-brand/ +└── DESIGN.md +``` + +### `DESIGN.md` 形态 + +```markdown +# Design System Inspired by YourBrand + +> Category: Developer Tools +> 一行总结,会显示在 picker 的预览里。 + +## 1. Visual Theme & Atmosphere +… + +## 2. Color +- Primary: `#hex` / `oklch(...)` +- … + +## 3. Typography +… + +## 4. Spacing & Grid +## 5. Layout & Composition +## 6. Components +## 7. Motion & Interaction +## 8. Voice & Brand +## 9. Anti-patterns +``` + +9 段式 schema 是固定的 —— skill body 会按这个结构 grep 内容。第一行 H1 会成为 picker 的标签(`Design System Inspired by` 前缀会被自动剥掉),`> Category: …` 那一行决定它落到哪个组。已有的 category 列表在 [`design-systems/README.md`](design-systems/README.md);如果你的品牌真的塞不进任何一个,可以新增 category,但**优先尝试现有 category**。 + +### 合并新 design system 的硬线 + +1. **9 个 section 都要在。** Section 内容空着可以(比如真的找不到 motion token),但标题必须保留,否则提示词的 grep 会断。 +2. **Hex 是真的。** 直接从品牌官网或产品里取色,不准从记忆里掏,不准让 AI 猜。README 里那套 5 步「品牌资产协议」对维护者一样适用。 +3. **强调色给 OKLch 是加分项。** 让色板在亮 / 暗模式之间能可预测地 lerp。 +4. **不要营销废话。** 品牌的 tagline 不是设计 token。删掉。 +5. **slug 用 ASCII** —— `linear.app` 写成 `linear-app`,`x.ai` 写成 `x-ai`。已经导入的 69 套都遵循这个约定,跟着写。 + +我们内置的 69 套产品系统是通过 [`scripts/sync-design-systems.mjs`](scripts/sync-design-systems.mjs) 从 [`VoltAgent/awesome-design-md`][acd2] 导入的。如果你的品牌应该归属在上游,**请先把 PR 发到那里** —— 我们下一次同步会自动收上来。`design-systems/` 文件夹用来放那些**不适合归到上游**的系统、加上我们手写的两套 starter。 + +--- + +## 接入一个新的 coding-agent CLI + +接入一个新 agent(比如某个新 shop 的 `foo-coder` CLI)就是在 [`daemon/agents.js`](daemon/agents.js) 里加一项: + +```javascript +{ + id: 'foo', + name: 'Foo Coder', + bin: 'foo', + versionArgs: ['--version'], + buildArgs: (prompt) => ['exec', '-p', prompt], + streamFormat: 'plain', // 如果它说 claude-stream-json 就写那个 +} +``` + +完事 —— daemon 会在 `PATH` 上检测到它、picker 显示出来、对话路径就通了。如果这个 CLI 吐 **类型化事件**(像 Claude Code 的 `--output-format stream-json`),在 [`daemon/claude-stream.js`](daemon/claude-stream.js) 里写一个 parser,并把 `streamFormat` 设成 `'claude-stream-json'`。 + +合并硬线: + +1. **真的跑通一次端到端会话** —— 把 daemon 日志贴在 PR 描述里,证明它流出了一个 artifact。 +2. **更新 [`docs/agent-adapters.md`](docs/agent-adapters.md)**,写清楚这个 CLI 的怪癖(要不要 key 文件?支不支持图片输入?非交互模式的 flag 是什么?)。 +3. **README 的「Supported coding agents」表里加一行**。 + +--- + +## 代码风格 + +格式我们不抠(保存时跑 Prettier 就行),但有两条不能让 —— 因为它们出现在提示词栈和用户可见的 API 里: + +1. **JS/TS 用单引号。** 字符串一律单引号,除非转义太丑。代码库已经是一致的,请保持一致。 +2. **代码注释用英文。** 即使 PR 是把某段翻译成中文,代码注释也保留英文,这样我们能维护一份可 grep 的引用集。 + +除此之外: + +- **不要写废话注释。** 不要 `// 引入这个模块`、不要 `// 遍历元素`。如果代码本身一眼能读,注释就是噪音。注释只用来说明非显而易见的意图、或者代码本身表达不出来的约束。 +- **`src/` 用 TypeScript。** Daemon (`daemon/`) 是纯 ESM JavaScript,类型重要的地方用 JSDoc —— 保持这样。 +- **不要随便加顶层依赖。** PR 描述里至少要有一段,说明引入它能换到什么、又新增了多少 bundle 字节。[`package.json`](package.json) 的依赖少是有意为之。 +- **推之前跑 `pnpm typecheck`。** CI 会跑;挂了会换来一句「请修一下」。 + +--- + +## Commit 与 PR + +- **一个 PR 只做一件事。** 加 skill + 重构 parser + 升依赖,是三个 PR。 +- **标题用动词起头 + 范围。** `add dating-web skill`、`fix daemon SSE backpressure when CLI hangs`、`docs: clarify .od layout`。 +- **正文解释 why。** 「这个 PR 改了什么」从 diff 一般能看出来;「为什么要改」很少能。 +- **如果有 issue,引用它。** 没有、且改动非平凡,请先开 issue 让我们先就「值不值得做」达成一致,再投入时间。 +- **Review 期间不要 squash。** 推 fixup commit;merge 时我们会 squash。 +- **不要 force-push 共享分支**,除非 reviewer 主动让你这么做。 + +我们不强制 CLA。Apache-2.0 已经覆盖;你的贡献按同样的 license 授权。 + +--- + +## 报 bug + +开 issue 时请带上: + +- 你跑的命令(精确到 `pnpm dev:all` / `npm start`)。 +- 选中的 agent CLI 是哪个(或者你走的是 BYOK 路径)。 +- 触发问题时的 skill + design system 组合。 +- 相关的 **daemon stderr 末尾几行** —— 大多数「artifact 没渲染出来」的报告,看到 `spawn ENOENT` 或 CLI 实际报错后 30 秒就能定位。 +- UI 问题贴一张截图。 + +提示词栈相关的 bug(「agent 吐了一个紫色渐变 hero,slop 黑名单不是禁了吗」),请贴 **完整的助手消息**,方便我们判断违规来自模型还是提示词。 + +--- + +## 提问 + +- 架构问题、设计问题、「这是 bug 还是误用」 → 请用 [GitHub Discussions](https://github.com/nexu-io/open-design/discussions)(首选 —— 下一个人能搜到)。 +- 「我想写一个干 X 的 skill 怎么写」 → 开一个 discussion。我们会回答,且如果是缺失的模式,答案会被收进 [`docs/skills-protocol.md`](docs/skills-protocol.md)。 + +--- + +## 我们不接收的 PR + +为了保持项目聚焦,请不要发以下类型的 PR: + +- **Vendor 一个模型运行时。** OD 整个赌注就是「你已有的 CLI 就够了」。我们不带 `pi-ai`、不带 OpenAI key、不带模型加载器。 +- **给前端加一个新框架。** Vite + React 18 + TS 是底线。不要 Next.js / Astro / Solid / Svelte 改写。 +- **把 daemon 换成 serverless function。** Daemon 的存在意义就是拥有真实的 `cwd` 和 spawn 真实的 CLI。SPA 部署 Vercel 没问题,daemon 仍然是 daemon。 +- **加 telemetry / 分析 / phone-home。** OD 是 local-first。唯一的对外请求是用户明确配置的 provider。 +- **打包二进制** 而没有附 license 文件和原作者归属。 + +不确定自己的想法合不合适?开个 discussion 再写代码。 + +--- + +## License + +提交贡献即代表你同意你的贡献按本仓库的 [Apache-2.0 License](LICENSE) 授权。例外是 [`skills/guizang-ppt/`](skills/guizang-ppt/) 下的所有文件,保留它们原始的 MIT license 和原作者 [op7418](https://github.com/op7418) 的归属。 + +[skill]: https://docs.anthropic.com/en/docs/claude-code/skills +[guizang]: https://github.com/op7418/guizang-ppt-skill +[acd2]: https://github.com/VoltAgent/awesome-design-md +[ocod]: https://github.com/OpenCoworkAI/open-codesign diff --git a/README.md b/README.md index 3b746bc..eb21073 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Open Design -> **Claude Code, but for design.** A local-first, web-deployable open replica of Anthropic's [Claude Design][cd] — your existing coding agent (Claude Code, Codex, Cursor Agent, Gemini CLI, OpenCode, Qwen) becomes the design engine, driven by composable **Skills** and **71 brand-grade Design Systems**. +> **The open-source alternative to [Claude Design][cd].** Local-first, web-deployable, BYOK at every layer — your existing coding agent (Claude Code, Codex, Cursor Agent, Gemini CLI, OpenCode, Qwen) becomes the design engine, driven by **19 composable Skills** and **71 brand-grade Design Systems**.

- Open Design banner — placeholder, replace with the live UI hero shot + Open Design — editorial cover: design with the agent on your laptop

@@ -20,13 +20,13 @@ ## Why this exists -Anthropic's [Claude Design][cd] (released 2026-04-17, Opus 4.7) showed what happens when an LLM stops writing prose and starts shipping design artifacts. It went viral — and stayed closed, paid-only, cloud-only, locked to Anthropic's model and Anthropic's skills. +Anthropic's [Claude Design][cd] (released 2026-04-17, Opus 4.7) showed what happens when an LLM stops writing prose and starts shipping design artifacts. It went viral — and stayed closed-source, paid-only, cloud-only, locked to Anthropic's model and Anthropic's skills. There is no checkout, no self-host, no Vercel deploy, no swap-in-your-own-agent. -**Open Design (OD) is the open substrate.** We don't build an agent — the strongest coding agents already live on your laptop. We wire them into a skill-driven design workflow that runs on `pnpm dev`, deploys to Vercel, and stays BYOK at every layer. +**Open Design (OD) is the open-source alternative.** Same loop, same artifact-first mental model, none of the lock-in. We don't ship an agent — the strongest coding agents already live on your laptop. We wire them into a skill-driven design workflow that runs on `pnpm dev`, deploys to Vercel, and stays BYOK at every layer. Type `make me a magazine-style pitch deck for our seed round`. The interactive question form pops up before the model improvises a single pixel. The agent picks one of five curated visual directions. A live `TodoWrite` plan streams into the UI. The daemon builds a real on-disk project folder with a seed template, layout library, and self-check checklist. The agent reads them — pre-flight enforced — runs a five-dimensional critique against its own output, and emits a single `` that renders in a sandboxed iframe seconds later. -That's not "AI tries to design something". That's an AI that has been trained, by the prompt stack, to behave like a senior designer with a working filesystem, a deterministic palette library, and a checklist culture. +That's not "AI tries to design something". That's an AI that has been trained, by the prompt stack, to behave like a senior designer with a working filesystem, a deterministic palette library, and a checklist culture — exactly the bar Claude Design set, but open and yours. OD stands on four open-source shoulders: @@ -52,51 +52,130 @@ OD stands on four open-source shoulders: ## Demo -> **Screenshots pending.** Every card below is a placeholder SVG — replace `docs/screenshots/*.svg` with real `.png`/`.jpg` captures and bump the `` extension when you do. -
-01 · Entry view — placeholder, replace with the real screenshot
+01 · Entry view
Entry view — pick a skill, pick a design system, type the brief. The same surface for prototypes, decks, mobile apps, dashboards, and editorial pages.
-02 · Discovery form — placeholder, replace with the real screenshot
+02 · Turn-1 discovery form
Turn-1 discovery form — before the model writes a pixel, OD locks the brief: surface, audience, tone, brand context, scale. 30 seconds of radios beats 30 minutes of redirects.
-03 · Direction picker — placeholder, replace with the real screenshot
+03 · Direction picker
Direction picker — when the user has no brand, the agent emits a second form with 5 curated directions (Monocle / Modern Minimal / Tech Utility / Brutalist / Soft Warm). One radio click → a deterministic palette + font stack, no model freestyle.
-04 · Live todo progress — placeholder, replace with the real screenshot
+04 · Live todo progress
Live todo progress — the agent's plan streams as a live card. in_progresscompleted updates land in real time. The user can redirect cheaply, mid-flight.
-05 · Sandboxed preview — placeholder, replace with the real screenshot
+05 · Sandboxed preview
Sandboxed preview — every <artifact> renders in a clean srcdoc iframe. Editable in place via the file workspace; downloadable as HTML, PDF, ZIP.
-06 · 71-system library — placeholder, replace with the real screenshot
+06 · 71-system library
71-system library — every product system shows its 4-color signature. Click for the full DESIGN.md, swatch grid, and live showcase.
-07 · Magazine deck — placeholder, replace with the real screenshot
+07 · Magazine deck
Deck mode (guizang-ppt) — the bundled guizang-ppt-skill drops in unchanged. Magazine layouts, WebGL hero backgrounds, single-file HTML output, PDF export.
-08 · Mobile prototype — placeholder, replace with the real screenshot
+08 · Mobile prototype
Mobile prototype — pixel-accurate iPhone 15 Pro chrome (Dynamic Island, status bar SVGs, home indicator). Multi-screen prototypes use the shared /frames/ assets so the agent never re-draws a phone.
+## Skills + +19 skills ship in the box. Each is a folder under [`skills/`](skills/) following the Claude Code [`SKILL.md`][skill] convention with an extended `od:` frontmatter (`mode`, `platform`, `scenario`, `preview`, `design_system`). + +### Showcase examples + +The visually distinctive skills you'll most likely run first. Each ships a real `example.html` you can open straight from the repo to see exactly what the agent will produce — no auth, no setup. + + + + + + + + + + + + + + + + + + +
+dating-web
+dating-web · prototype
Consumer dating / matchmaking dashboard — left rail nav, ticker bar, KPIs, 30-day mutual-matches chart, editorial typography.
+
+digital-eguide
+digital-eguide · template
Two-spread digital e-guide — cover (title, author, TOC teaser) + lesson spread with pull-quote and step list. Creator / lifestyle tone.
+
+email-marketing
+email-marketing · prototype
Brand product-launch HTML email — masthead, hero image, headline lockup, CTA, specs grid. Centered single-column, table-fallback safe.
+
+gamified-app
+gamified-app · prototype
Three-frame gamified mobile-app prototype on a dark showcase stage — cover, today's quests with XP ribbons + level bar, quest detail.
+
+mobile-onboarding
+mobile-onboarding · prototype
Three-frame mobile onboarding flow — splash, value-prop, sign-in. Status bar, swipe dots, primary CTA.
+
+motion-frames
+motion-frames · prototype
Single-frame motion-design hero with looping CSS animations — rotating type ring, animated globe, ticking timer. Hand-off ready for HyperFrames.
+
+social-carousel
+social-carousel · prototype
Three-card 1080×1080 social-media carousel — cinematic panels with display headlines that connect across the series, brand mark, loop affordance.
+
+sprite-animation
+sprite-animation · prototype
Pixel / 8-bit animated explainer slide — full-bleed cream stage, animated pixel mascot, kinetic Japanese display type, looping CSS keyframes.
+
+ +### Design surfaces + +| Skill | Mode | Default for | What it produces | +|---|---|---|---| +| [`web-prototype`](skills/web-prototype/) | prototype | desktop | Single-page HTML — landings, marketing, hero pages | +| [`saas-landing`](skills/saas-landing/) | prototype | desktop | Hero / features / pricing / CTA marketing layout | +| [`dashboard`](skills/dashboard/) | prototype | desktop | Admin / analytics with sidebar + data dense layout | +| [`pricing-page`](skills/pricing-page/) | prototype | desktop | Standalone pricing + comparison tables | +| [`docs-page`](skills/docs-page/) | prototype | desktop | 3-column documentation layout | +| [`blog-post`](skills/blog-post/) | prototype | desktop | Editorial long-form | +| [`mobile-app`](skills/mobile-app/) | prototype | mobile | iPhone 15 Pro / Pixel framed app screen(s) | +| [`simple-deck`](skills/simple-deck/) | deck | desktop | Minimal horizontal-swipe deck | +| [`guizang-ppt`](skills/guizang-ppt/) | deck | **default** for deck | Magazine-style web PPT — bundled from [op7418/guizang-ppt-skill][guizang] | + +### Document / work-product surfaces + +| Skill | Mode | What it produces | +|---|---|---| +| [`pm-spec`](skills/pm-spec/) | template | PM specification doc with TOC + decision log | +| [`weekly-update`](skills/weekly-update/) | template | Team weekly with progress / blockers / next | +| [`meeting-notes`](skills/meeting-notes/) | template | Meeting decision log | +| [`eng-runbook`](skills/eng-runbook/) | template | Incident runbook | +| [`finance-report`](skills/finance-report/) | template | Exec finance summary | +| [`hr-onboarding`](skills/hr-onboarding/) | template | Role onboarding plan | +| [`invoice`](skills/invoice/) | template | Single-page invoice | +| [`kanban-board`](skills/kanban-board/) | template | Board snapshot | +| [`team-okrs`](skills/team-okrs/) | template | OKR scoresheet | + +Adding a skill takes one folder. Read [`docs/skills-protocol.md`](docs/skills-protocol.md) for the extended frontmatter, fork an existing skill, restart the daemon, it appears in the picker. + ## Six load-bearing ideas ### 1 · We don't ship an agent. Yours is good enough. @@ -320,59 +399,10 @@ open-design/ └── artifacts/ ← saved one-off renders ``` -## Skills - -19 skills ship in the box. Each is a folder under [`skills/`](skills/) following the Claude Code [`SKILL.md`][skill] convention with an extended `od:` frontmatter (`mode`, `platform`, `scenario`, `preview`, `design_system`). - -### Showcase examples - -The visually distinctive skills you'll most likely run first. Each ships a real `example.html` you can open straight from the repo to see what the agent will produce. - -| Skill | Mode | What it produces | -|---|---|---| -| [`dating-web`](skills/dating-web/) | prototype | Consumer dating / matchmaking dashboard — left rail nav, ticker bar, KPIs, 30-day mutual-matches chart, editorial typography | -| [`digital-eguide`](skills/digital-eguide/) | template | Two-spread digital e-guide — cover (title, author, TOC teaser) + lesson spread with pull-quote and step list. Creator / lifestyle tone | -| [`email-marketing`](skills/email-marketing/) | prototype | Brand product-launch HTML email — masthead, hero image, headline lockup, CTA, specs grid. Centered single-column, table-fallback safe | -| [`gamified-app`](skills/gamified-app/) | prototype | Three-frame gamified mobile-app prototype on a dark showcase stage — cover, today's quests with XP ribbons + level bar, quest detail | -| [`mobile-onboarding`](skills/mobile-onboarding/) | prototype | Three-frame mobile onboarding flow — splash, value-prop, sign-in. Status bar, swipe dots, primary CTA | -| [`motion-frames`](skills/motion-frames/) | prototype | Single-frame motion-design hero with looping CSS animations — rotating type ring, animated globe, ticking timer. Hand-off ready for HyperFrames | -| [`social-carousel`](skills/social-carousel/) | prototype | Three-card 1080×1080 social-media carousel — cinematic panels with display headlines that connect across the series, brand mark, loop affordance | -| [`sprite-animation`](skills/sprite-animation/) | prototype | Pixel / 8-bit animated explainer slide — full-bleed cream stage, animated pixel mascot, kinetic Japanese display type, looping CSS keyframes | - -### Design surfaces - -| Skill | Mode | Default for | What it produces | -|---|---|---|---| -| [`web-prototype`](skills/web-prototype/) | prototype | desktop | Single-page HTML — landings, marketing, hero pages | -| [`saas-landing`](skills/saas-landing/) | prototype | desktop | Hero / features / pricing / CTA marketing layout | -| [`dashboard`](skills/dashboard/) | prototype | desktop | Admin / analytics with sidebar + data dense layout | -| [`pricing-page`](skills/pricing-page/) | prototype | desktop | Standalone pricing + comparison tables | -| [`docs-page`](skills/docs-page/) | prototype | desktop | 3-column documentation layout | -| [`blog-post`](skills/blog-post/) | prototype | desktop | Editorial long-form | -| [`mobile-app`](skills/mobile-app/) | prototype | mobile | iPhone 15 Pro / Pixel framed app screen(s) | -| [`simple-deck`](skills/simple-deck/) | deck | desktop | Minimal horizontal-swipe deck | -| [`guizang-ppt`](skills/guizang-ppt/) | deck | **default** for deck | Magazine-style web PPT — bundled from [op7418/guizang-ppt-skill][guizang] | - -### Document / work-product surfaces - -| Skill | Mode | What it produces | -|---|---|---| -| [`pm-spec`](skills/pm-spec/) | template | PM specification doc with TOC + decision log | -| [`weekly-update`](skills/weekly-update/) | template | Team weekly with progress / blockers / next | -| [`meeting-notes`](skills/meeting-notes/) | template | Meeting decision log | -| [`eng-runbook`](skills/eng-runbook/) | template | Incident runbook | -| [`finance-report`](skills/finance-report/) | template | Exec finance summary | -| [`hr-onboarding`](skills/hr-onboarding/) | template | Role onboarding plan | -| [`invoice`](skills/invoice/) | template | Single-page invoice | -| [`kanban-board`](skills/kanban-board/) | template | Board snapshot | -| [`team-okrs`](skills/team-okrs/) | template | OKR scoresheet | - -Adding a skill takes one folder. Read [`docs/skills-protocol.md`](docs/skills-protocol.md) for the extended frontmatter, fork an existing skill, restart the daemon, it appears in the picker. - ## Design Systems

- 71 design systems library — placeholder, replace with the real screenshot + The 71 design systems library — style guide spread

71 systems out of the box, each as a single [`DESIGN.md`](design-systems/README.md): @@ -450,7 +480,7 @@ The whole machinery below is the [`huashu-design`](https://github.com/alchaincyf | PPT skill reuse | N/A | Built-in | **[`guizang-ppt-skill`][guizang] drops in** | | Minimum billing | Pro / Max / Team | BYOK | **BYOK** | -[cd]: https://www.anthropic.com/news/claude-design +[cd]: https://x.com/claudeai/status/2045156267690213649 [ocod]: https://github.com/OpenCoworkAI/open-codesign [piai]: https://github.com/mariozechner/pi-ai [acd]: https://github.com/VoltAgent/awesome-claude-design @@ -479,7 +509,7 @@ Every external project this repo borrows from. Each link goes to the source so y | Project | Role here | |---|---| -| [`Claude Design`][cd] | The closed product this repo provides an open substrate for. | +| [`Claude Design`][cd] | The closed-source product this repo is the open-source alternative to. | | [**`alchaincyf/huashu-design`**](https://github.com/alchaincyf/huashu-design) | The design-philosophy core. Junior-Designer workflow, the 5-step brand-asset protocol, anti-AI-slop checklist, 5-dimensional self-critique, and the "5 schools × 20 design philosophies" library behind our direction picker — all distilled into [`src/prompts/discovery.ts`](src/prompts/discovery.ts) and [`src/prompts/directions.ts`](src/prompts/directions.ts). | | [**`op7418/guizang-ppt-skill`**][guizang] | Magazine-web-PPT skill bundled verbatim under [`skills/guizang-ppt/`](skills/guizang-ppt/) with original LICENSE preserved. Default for deck mode. P0/P1/P2 checklist culture borrowed for every other skill. | | [**`multica-ai/multica`**](https://github.com/multica-ai/multica) | The daemon + adapter architecture. PATH-scan agent detection, local daemon as the only privileged process, agent-as-teammate worldview. We adopt the model; we do not vendor the code. | @@ -508,7 +538,15 @@ Phased delivery → [`docs/roadmap.md`](docs/roadmap.md). This is an early implementation — the closed loop (detect → pick skill + design system → chat → parse `` → preview → save) runs end-to-end. The prompt stack and skill library are where most of the value lives, and they're stable. The component-level UI is shipping daily. -Issues, PRs, new skills, and new design systems are all welcome. +## Contributing + +Issues, PRs, new skills, and new design systems are all welcome. The highest-leverage contributions are usually one folder, one Markdown file, or one PR-sized adapter: + +- **Add a skill** — drop a folder into [`skills/`](skills/) following the [`SKILL.md`][skill] convention. +- **Add a design system** — drop a `DESIGN.md` into [`design-systems//`](design-systems/) using the 9-section schema. +- **Wire up a new coding-agent CLI** — one entry in [`daemon/agents.js`](daemon/agents.js). + +Full walkthrough, bar-for-merging, code style, and what we don't accept → [`CONTRIBUTING.md`](CONTRIBUTING.md) ([简体中文](CONTRIBUTING.zh-CN.md)). ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index ecfebb9..763c2ca 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,9 +1,9 @@ # Open Design -> **给设计的 Claude Code。** 一个本地优先、可部署到 Vercel 的开源 [Claude Design][cd] 复刻 —— 你机器上已经装好的 coding agent(Claude Code、Codex、Cursor Agent、Gemini CLI、OpenCode、Qwen)就是设计引擎,由可组合的 **Skills** 和 **71 套品牌级 Design System** 驱动。 +> **[Claude Design][cd] 的开源替代品。** 本地优先、可部署到 Vercel、每一层都 BYOK —— 你机器上已经装好的 coding agent(Claude Code、Codex、Cursor Agent、Gemini CLI、OpenCode、Qwen)就是设计引擎,由 **19 个可组合 Skills** 和 **71 套品牌级 Design System** 驱动。

- Open Design banner —— 占位图,等待替换为真实产品截图 + Open Design 封面:与本地 AI 智能体共同设计

@@ -20,13 +20,13 @@ ## 为什么要做这个 -Anthropic 的 [Claude Design][cd](2026-04-17 发布,基于 Opus 4.7)让大家第一次看到:当一个 LLM 不再写废话、开始直接交付设计成品,会是什么样子。它瞬间出圈 —— 然后保持闭源、付费、只跑在云上、绑定 Anthropic 的模型和 Anthropic 的内部 skill。 +Anthropic 的 [Claude Design][cd](2026-04-17 发布,基于 Opus 4.7)让大家第一次看到:当一个 LLM 不再写废话、开始直接交付设计成品,会是什么样子。它瞬间出圈 —— 然后保持**闭源**、付费、只跑在云上、绑定 Anthropic 的模型和 Anthropic 的内部 skill。没有 checkout,没有自托管,没有 Vercel 部署,也换不了自己的 agent。 -**Open Design(OD)是它的开源底座。** 我们不做 agent —— 你笔记本上最强的 coding agent 已经装好了。我们要做的,是把它接进一个 skill 驱动的设计工作流,跑在一个普通的 Web 应用里:本地 `pnpm dev`,云端 `vercel deploy`,每一层都 BYOK(自带 Key)。 +**Open Design(OD)就是它的开源替代品。** 同一套 loop、同一种「artifact-first」心智模型,但没有锁定。我们不做 agent —— 你笔记本上最强的 coding agent 已经装好了。我们要做的,是把它接进一个 skill 驱动的设计工作流,跑在一个普通的 Web 应用里:本地 `pnpm dev`,云端 `vercel deploy`,每一层都 BYOK(自带 Key)。 输入「帮我做一份杂志风的种子轮 pitch deck」。在模型挥洒第一个像素之前,**初始化问题表单**已经先跳出来。Agent 从 5 套精挑的视觉方向里选一个。一张活的 `TodoWrite` 计划卡片实时流入 UI。Daemon 在磁盘上构建出一个真实的项目目录,里面有 seed 模板、布局库、自检 checklist。Agent **强制 pre-flight** 读取它们,对自己的输出跑一轮**五维评审**,几秒后吐出一个 ``,渲染在沙盒 iframe 里。 -这不是「AI 试图做点设计」。这是一个被提示词栈训练得像高级设计师一样工作的 AI —— 有可用的文件系统、有确定性的色板库、有 checklist 文化。 +这不是「AI 试图做点设计」。这是一个被提示词栈训练得像高级设计师一样工作的 AI —— 有可用的文件系统、有确定性的色板库、有 checklist 文化 —— 也就是 Claude Design 立下的那条线,只是这次它开源、归你。 OD 站在四个开源项目的肩膀上: @@ -52,51 +52,130 @@ OD 站在四个开源项目的肩膀上: ## 效果展示 -> **截图位待补。** 下方每张卡片都是占位 SVG —— 截好真实图后把 `docs/screenshots/*.svg` 替换为 `.png` / `.jpg`,并把对应 `` 的扩展名同步改掉即可。 -
-01 · 入口页 —— 占位图,等待替换为真实截图
+01 · 入口页
入口页 —— 选 skill、选 design system、写一行需求。同一个表面服务原型、deck、移动端、dashboard、editorial 页面所有 mode。
-02 · 初始化问题表单 —— 占位图,等待替换为真实截图
+02 · 初始化问题表单
初始化问题表单 —— 模型动笔之前,OD 先把需求锁住:surface、受众、调性、品牌上下文、规模。30 秒勾选项秒杀 30 分钟来回返工。
-03 · 方向选择器 —— 占位图,等待替换为真实截图
+03 · 方向选择器
方向选择器 —— 用户没有品牌上下文时,agent 自动跳第二个表单,5 套精选方向(Monocle / Modern Minimal / Tech Utility / Brutalist / Soft Warm)一个 radio 选完,色板 + 字体栈直接锁定,没有 freestyle 空间。
-04 · 实时 todo 进度 —— 占位图,等待替换为真实截图
+04 · 实时 todo 进度
实时 todo 进度 —— Agent 的计划以活卡片形式流入 UI。in_progresscompleted 实时切换。用户能在中途以极低成本介入纠偏。
-05 · 沙盒预览 —— 占位图,等待替换为真实截图
+05 · 沙盒预览
沙盒预览 —— 每个 <artifact> 都在干净的 srcdoc iframe 里渲染。可在文件工作区里就地编辑;可下载为 HTML / PDF / ZIP。
-06 · 71 套 design system 库 —— 占位图,等待替换为真实截图
+06 · 71 套 design system 库
71 套 design system 库 —— 每套产品系统都展示 4 色色卡。点进去看完整的 DESIGN.md、色板网格、live showcase。
-07 · 杂志风 deck —— 占位图,等待替换为真实截图
+07 · 杂志风 deck
Deck 模式(guizang-ppt) —— 内置的 guizang-ppt-skill 原样接入。杂志版式、WebGL hero 背景、单文件 HTML 输出、可导 PDF。
-08 · 移动端原型 —— 占位图,等待替换为真实截图
+08 · 移动端原型
移动端原型 —— 像素级精确的 iPhone 15 Pro chrome(灵动岛、状态栏 SVG、Home Indicator)。多屏原型直接复用 /frames/ 共享资源,agent 永远不需要重新画一遍手机。
+## 内置 Skills + +19 个 skill,每个一个文件夹,都遵循 Claude Code 的 [`SKILL.md`][skill] 规范,并叠加 OD 的 `od:` frontmatter(`mode`、`platform`、`scenario`、`preview`、`design_system`)。 + +### 示例展示(Showcase examples) + +视觉表现最强、最适合上手第一跑的几条 skill。每条都附带可直接打开的 `example.html` —— 不用登录、不用配置,先看产出再下单。 + + + + + + + + + + + + + + + + + + +
+dating-web
+dating-web · prototype
消费级约会 / 婚恋仪表盘 —— 左侧栏、社区动态 ticker、头部 KPI、30 天双向匹配柱状图,editorial 字体,克制点缀色。
+
+digital-eguide
+digital-eguide · template
两页数字 e-guide —— 封面(标题、作者、TOC 预告)+ 内文跨页(pull-quote + 步骤列表),创作者 / 生活方式风。
+
+email-marketing
+email-marketing · prototype
品牌新品发布邮件 —— 顶部 wordmark、hero 图、标题锁排、主 CTA、规格网格。居中单列 + 表格降级,邮件客户端安全。
+
+gamified-app
+gamified-app · prototype
三屏游戏化移动 app 原型,黑色舞台 —— 封面 / 今日任务(XP 缎带 + 等级条)/ 任务详情。
+
+mobile-onboarding
+mobile-onboarding · prototype
三屏移动端引导流 —— splash、价值主张、登录。状态栏、滑动点、主 CTA。
+
+motion-frames
+motion-frames · prototype
单帧 motion 设计 hero,CSS 循环动画 —— 旋转字环、地球、计时器。可直接交给 HyperFrames 等关键帧导出。
+
+social-carousel
+social-carousel · prototype
1080×1080 三连社媒轮播图 —— 三张电影感面板,标题前后呼应,品牌标识、loop 标记。
+
+sprite-animation
+sprite-animation · prototype
像素 / 8-bit 动画解释器单帧 —— 米白通屏、像素吉祥物、动感日文标题、循环 CSS keyframes,可直接录屏成竖版视频。
+
+ +### 设计交付类 + +| Skill | Mode | 默认场景 | 产出 | +|---|---|---|---| +| [`web-prototype`](skills/web-prototype/) | prototype | 桌面 | 单页 HTML —— landing、营销、hero | +| [`saas-landing`](skills/saas-landing/) | prototype | 桌面 | hero / features / pricing / CTA 营销版式 | +| [`dashboard`](skills/dashboard/) | prototype | 桌面 | 带侧栏 + 数据密集型的后台 | +| [`pricing-page`](skills/pricing-page/) | prototype | 桌面 | 独立定价页 + 对比表 | +| [`docs-page`](skills/docs-page/) | prototype | 桌面 | 三栏文档版式 | +| [`blog-post`](skills/blog-post/) | prototype | 桌面 | 长文 editorial | +| [`mobile-app`](skills/mobile-app/) | prototype | 移动 | 带 iPhone 15 Pro / Pixel 外壳的 app 屏 | +| [`simple-deck`](skills/simple-deck/) | deck | 桌面 | 极简横滑 deck | +| [`guizang-ppt`](skills/guizang-ppt/) | deck | **deck 默认** | 杂志风网页 PPT —— 来自 [op7418/guizang-ppt-skill][guizang] | + +### 文档与办公产物类 + +| Skill | Mode | 产出 | +|---|---|---| +| [`pm-spec`](skills/pm-spec/) | template | PM 规范文档 + 目录 + 决策日志 | +| [`weekly-update`](skills/weekly-update/) | template | 团队周报:进度 / 阻塞 / 下一步 | +| [`meeting-notes`](skills/meeting-notes/) | template | 会议决策纪要 | +| [`eng-runbook`](skills/eng-runbook/) | template | 故障 runbook | +| [`finance-report`](skills/finance-report/) | template | 高管财务摘要 | +| [`hr-onboarding`](skills/hr-onboarding/) | template | 岗位入职计划 | +| [`invoice`](skills/invoice/) | template | 单页发票 | +| [`kanban-board`](skills/kanban-board/) | template | 看板快照 | +| [`team-okrs`](skills/team-okrs/) | template | OKR 计分表 | + +新增一个 skill 就是新增一个文件夹。读 [`docs/skills-protocol.md`](docs/skills-protocol.md) 了解扩展 frontmatter,fork 一个现有 skill,重启 daemon 即生效。 + ## 六个底层设计 ### 1 · 我们不带 agent,你的就够好 @@ -320,59 +399,10 @@ open-design/ └── artifacts/ ← 单次保存的 artifact ``` -## 内置 Skills - -19 个 skill,每个一个文件夹,都遵循 Claude Code 的 [`SKILL.md`][skill] 规范,并叠加 OD 的 `od:` frontmatter(`mode`、`platform`、`scenario`、`preview`、`design_system`)。 - -### 示例展示(Showcase examples) - -视觉表现最强、最适合上手第一跑的几条 skill。每条都附带可直接打开的 `example.html`,先看产出再下单。 - -| Skill | Mode | 产出 | -|---|---|---| -| [`dating-web`](skills/dating-web/) | prototype | 消费级约会 / 婚恋仪表盘 —— 左侧栏、社区动态 ticker、头部 KPI、30 天双向匹配柱状图,editorial 字体,克制点缀色 | -| [`digital-eguide`](skills/digital-eguide/) | template | 两页数字 e-guide —— 封面(标题、作者、TOC 预告)+ 内文跨页(pull-quote + 步骤列表),创作者 / 生活方式风 | -| [`email-marketing`](skills/email-marketing/) | prototype | 品牌新品发布邮件 —— 顶部 wordmark、hero 图、标题锁排、主 CTA、规格网格。居中单列 + 表格降级,邮件客户端安全 | -| [`gamified-app`](skills/gamified-app/) | prototype | 三屏游戏化移动 app 原型,黑色舞台 —— 封面 / 今日任务(XP 缎带 + 等级条)/ 任务详情 | -| [`mobile-onboarding`](skills/mobile-onboarding/) | prototype | 三屏移动端引导流 —— splash、价值主张、登录。状态栏、滑动点、主 CTA | -| [`motion-frames`](skills/motion-frames/) | prototype | 单帧 motion 设计 hero,CSS 循环动画 —— 旋转字环、地球、计时器。可直接交给 HyperFrames 等关键帧导出 | -| [`social-carousel`](skills/social-carousel/) | prototype | 1080×1080 三连社媒轮播图 —— 三张电影感面板,标题前后呼应,品牌标识、loop 标记 | -| [`sprite-animation`](skills/sprite-animation/) | prototype | 像素 / 8-bit 动画解释器单帧 —— 米白通屏、像素吉祥物、动感日文标题、循环 CSS keyframes,可直接录屏成竖版视频 | - -### 设计交付类 - -| Skill | Mode | 默认场景 | 产出 | -|---|---|---|---| -| [`web-prototype`](skills/web-prototype/) | prototype | 桌面 | 单页 HTML —— landing、营销、hero | -| [`saas-landing`](skills/saas-landing/) | prototype | 桌面 | hero / features / pricing / CTA 营销版式 | -| [`dashboard`](skills/dashboard/) | prototype | 桌面 | 带侧栏 + 数据密集型的后台 | -| [`pricing-page`](skills/pricing-page/) | prototype | 桌面 | 独立定价页 + 对比表 | -| [`docs-page`](skills/docs-page/) | prototype | 桌面 | 三栏文档版式 | -| [`blog-post`](skills/blog-post/) | prototype | 桌面 | 长文 editorial | -| [`mobile-app`](skills/mobile-app/) | prototype | 移动 | 带 iPhone 15 Pro / Pixel 外壳的 app 屏 | -| [`simple-deck`](skills/simple-deck/) | deck | 桌面 | 极简横滑 deck | -| [`guizang-ppt`](skills/guizang-ppt/) | deck | **deck 默认** | 杂志风网页 PPT —— 来自 [op7418/guizang-ppt-skill][guizang] | - -### 文档与办公产物类 - -| Skill | Mode | 产出 | -|---|---|---| -| [`pm-spec`](skills/pm-spec/) | template | PM 规范文档 + 目录 + 决策日志 | -| [`weekly-update`](skills/weekly-update/) | template | 团队周报:进度 / 阻塞 / 下一步 | -| [`meeting-notes`](skills/meeting-notes/) | template | 会议决策纪要 | -| [`eng-runbook`](skills/eng-runbook/) | template | 故障 runbook | -| [`finance-report`](skills/finance-report/) | template | 高管财务摘要 | -| [`hr-onboarding`](skills/hr-onboarding/) | template | 岗位入职计划 | -| [`invoice`](skills/invoice/) | template | 单页发票 | -| [`kanban-board`](skills/kanban-board/) | template | 看板快照 | -| [`team-okrs`](skills/team-okrs/) | template | OKR 计分表 | - -新增一个 skill 就是新增一个文件夹。读 [`docs/skills-protocol.md`](docs/skills-protocol.md) 了解扩展 frontmatter,fork 一个现有 skill,重启 daemon 即生效。 - ## Design System

- 71 套 design system 库 —— 占位图,等待替换为真实截图 + 71 套 Design Systems 库 — 编辑版式双页

71 套开箱即用,每套一个 [`DESIGN.md`](design-systems/README.md): @@ -450,7 +480,7 @@ open-design/ | PPT skill 复用 | N/A | 内置 | **[`guizang-ppt-skill`][guizang] 直接接入** | | 计费门槛 | Pro / Max / Team | BYOK | **BYOK** | -[cd]: https://www.anthropic.com/news/claude-design +[cd]: https://x.com/claudeai/status/2045156267690213649 [ocod]: https://github.com/OpenCoworkAI/open-codesign [piai]: https://github.com/mariozechner/pi-ai [acd]: https://github.com/VoltAgent/awesome-claude-design @@ -479,7 +509,7 @@ Daemon 启动时从 `PATH` 自动检测,无需配置。 | 项目 | 在这里的角色 | |---|---| -| [`Claude Design`][cd] | 本仓库为它提供开源底座的闭源产品。 | +| [`Claude Design`][cd] | 本仓库为之提供开源替代的闭源产品。 | | [**`alchaincyf/huashu-design`**(花叔的画术)](https://github.com/alchaincyf/huashu-design) | 设计哲学的核心。Junior-Designer 工作流、5 步品牌资产协议、anti-AI-slop checklist、五维自评审、以及方向选择器背后的「5 流派 × 20 种设计哲学」库 —— 全部蒸馏进 [`src/prompts/discovery.ts`](src/prompts/discovery.ts) 与 [`src/prompts/directions.ts`](src/prompts/directions.ts)。 | | [**`op7418/guizang-ppt-skill`**(歸藏)][guizang] | Magazine-web-PPT skill 原样捆绑在 [`skills/guizang-ppt/`](skills/guizang-ppt/) 下,原 LICENSE 保留。Deck 模式默认。P0/P1/P2 checklist 文化也被借给了所有其他 skill。 | | [**`multica-ai/multica`**](https://github.com/multica-ai/multica) | Daemon + adapter 架构。PATH 扫描式 agent 检测、本地 daemon 作为唯一特权进程、agent-as-teammate 世界观。我们采纳模型,不 vendor 代码。 | @@ -508,7 +538,15 @@ Daemon 启动时从 `PATH` 自动检测,无需配置。 这是一个早期实现 —— 闭环(检测 → 选 skill + design system → 对话 → 解析 `` → 预览 → 保存)已经端到端跑通。提示词栈和 skill 库是价值最重的部分,目前已稳定。组件级 UI 仍在每天迭代。 -欢迎 issue、PR、新 skill、新 design system。 +## 贡献 + +欢迎 issue、PR、新 skill、新 design system。收益最高的贡献往往就是一个文件夹、一份 Markdown,或者一个 PR 大小的 adapter: + +- **加一个 skill** —— 往 [`skills/`](skills/) 丢一个文件夹,遵循 [`SKILL.md`][skill] 规范。 +- **加一套 design system** —— 往 [`design-systems//`](design-systems/) 丢一份 `DESIGN.md`,用 9 段式 schema。 +- **接入一个新的 coding-agent CLI** —— 在 [`daemon/agents.js`](daemon/agents.js) 里加一项。 + +完整流程、合并硬线、代码风格、我们不接收的 PR 类型 → [`CONTRIBUTING.zh-CN.md`](CONTRIBUTING.zh-CN.md)([English](CONTRIBUTING.md))。 ## License diff --git a/daemon/skills.js b/daemon/skills.js index c20c592..ff0fa85 100644 --- a/daemon/skills.js +++ b/daemon/skills.js @@ -2,9 +2,9 @@ // front-matter, returns listing. No watching in this MVP — re-scans on every // GET /api/skills, which is fine for dozens of skills. -import { readdir, readFile, stat } from 'node:fs/promises'; -import path from 'node:path'; -import { parseFrontmatter } from './frontmatter.js'; +import { readdir, readFile, stat } from "node:fs/promises"; +import path from "node:path"; +import { parseFrontmatter } from "./frontmatter.js"; export async function listSkills(skillsRoot) { const out = []; @@ -17,27 +17,40 @@ export async function listSkills(skillsRoot) { for (const entry of entries) { if (!entry.isDirectory()) continue; const dir = path.join(skillsRoot, entry.name); - const skillPath = path.join(dir, 'SKILL.md'); + const skillPath = path.join(dir, "SKILL.md"); try { const stats = await stat(skillPath); if (!stats.isFile()) continue; - const raw = await readFile(skillPath, 'utf8'); + const raw = await readFile(skillPath, "utf8"); const { data, body } = parseFrontmatter(raw); const hasAttachments = await dirHasAttachments(dir); const mode = data.od?.mode || inferMode(body, data.description); out.push({ id: data.name || entry.name, name: data.name || entry.name, - description: data.description || '', + description: data.description || "", triggers: Array.isArray(data.triggers) ? data.triggers : [], mode, - platform: normalizePlatform(data.od?.platform, mode, body, data.description), + platform: normalizePlatform( + data.od?.platform, + mode, + body, + data.description + ), scenario: normalizeScenario(data.od?.scenario, body, data.description), - previewType: data.od?.preview?.type || 'html', + previewType: data.od?.preview?.type || "html", designSystemRequired: data.od?.design_system?.requires ?? true, defaultFor: normalizeDefaultFor(data.od?.default_for), - upstream: typeof data.od?.upstream === 'string' ? data.od.upstream : null, + upstream: + typeof data.od?.upstream === "string" ? data.od.upstream : null, featured: normalizeFeatured(data.od?.featured), + // Optional metadata hints used by 'Use this prompt' fast-create so + // the resulting project mirrors the shipped example.html. Each hint + // is only consumed when its kind matches the skill mode; missing + // hints fall back to the same defaults the new-project form uses. + fidelity: normalizeFidelity(data.od?.fidelity), + speakerNotes: normalizeBoolHint(data.od?.speaker_notes), + animations: normalizeBoolHint(data.od?.animations), examplePrompt: derivePrompt(data), body: hasAttachments ? withSkillRootPreamble(body, dir) : body, dir, @@ -56,15 +69,15 @@ export async function listSkills(skillsRoot) { // open those files via absolute paths. function withSkillRootPreamble(body, dir) { const preamble = [ - '> **Skill root (absolute):** `' + dir + '`', - '>', - '> This skill ships side files alongside `SKILL.md`. When the workflow', - '> below references relative paths such as `assets/template.html` or', - '> `references/layouts.md`, resolve them against the skill root above and', - '> open them via their full absolute path.', - '', - '', - ].join('\n'); + "> **Skill root (absolute):** `" + dir + "`", + ">", + "> This skill ships side files alongside `SKILL.md`. When the workflow", + "> below references relative paths such as `assets/template.html` or", + "> `references/layouts.md`, resolve them against the skill root above and", + "> open them via their full absolute path.", + "", + "", + ].join("\n"); return preamble + body; } @@ -72,7 +85,9 @@ async function dirHasAttachments(dir) { try { const entries = await readdir(dir, { withFileTypes: true }); return entries.some( - (e) => e.name !== 'SKILL.md' && (e.isDirectory() || /\.(md|html|css|js|json|txt)$/i.test(e.name)), + (e) => + e.name !== "SKILL.md" && + (e.isDirectory() || /\.(md|html|css|js|json|txt)$/i.test(e.name)) ); } catch { return false; @@ -85,14 +100,35 @@ function normalizeDefaultFor(value) { return [String(value)]; } +// Optional `od.fidelity` hint for prototype skills. Only 'wireframe' and +// 'high-fidelity' are meaningful — anything else collapses to null so the +// caller falls back to the form default ('high-fidelity'). +function normalizeFidelity(value) { + if (value === "wireframe" || value === "high-fidelity") return value; + return null; +} + +// Coerce truthy / falsy strings ("true", "yes", "false", "no") and booleans +// to a real boolean. Returns null for anything we can't interpret so the +// caller knows to fall back to the form default. +function normalizeBoolHint(value) { + if (typeof value === "boolean") return value; + if (typeof value === "string") { + const v = value.trim().toLowerCase(); + if (v === "true" || v === "yes" || v === "1") return true; + if (v === "false" || v === "no" || v === "0") return false; + } + return null; +} + // Coerce `od.featured` into a numeric priority. Lower numbers float to the // top of the Examples gallery; `true` is treated as priority 1; anything // missing/unrecognised becomes null so non-featured skills keep their // natural alphabetical order. function normalizeFeatured(value) { if (value === true) return 1; - if (typeof value === 'number' && Number.isFinite(value)) return value; - if (typeof value === 'string' && value.trim()) { + if (typeof value === "number" && Number.isFinite(value)) return value; + if (typeof value === "string" && value.trim()) { const n = Number(value); if (Number.isFinite(n)) return n; } @@ -105,66 +141,70 @@ function normalizeFeatured(value) { // serves as a passable starter prompt. function derivePrompt(data) { const explicit = data.od?.example_prompt; - if (typeof explicit === 'string' && explicit.trim()) return explicit.trim(); - const desc = typeof data.description === 'string' ? data.description.trim() : ''; - if (!desc) return ''; - const collapsed = desc.replace(/\s+/g, ' ').trim(); + if (typeof explicit === "string" && explicit.trim()) return explicit.trim(); + const desc = + typeof data.description === "string" ? data.description.trim() : ""; + if (!desc) return ""; + const collapsed = desc.replace(/\s+/g, " ").trim(); const firstSentence = collapsed.match(/^.+?[.!?。!?](?:\s|$)/)?.[0]?.trim(); return (firstSentence || collapsed).slice(0, 320); } function inferMode(body, description) { - const hay = `${description ?? ''}\n${body ?? ''}`.toLowerCase(); - if (/\bppt|deck|slide|presentation|幻灯|投影/.test(hay)) return 'deck'; - if (/\bdesign[- ]system|\bdesign\.md|\bdesign tokens/.test(hay)) return 'design-system'; - if (/\btemplate\b/.test(hay)) return 'template'; - return 'prototype'; + const hay = `${description ?? ""}\n${body ?? ""}`.toLowerCase(); + if (/\bppt|deck|slide|presentation|幻灯|投影/.test(hay)) return "deck"; + if (/\bdesign[- ]system|\bdesign\.md|\bdesign tokens/.test(hay)) + return "design-system"; + if (/\btemplate\b/.test(hay)) return "template"; + return "prototype"; } // Validate platform tag — only desktop / mobile are meaningful for the // Examples gallery. Falls back to autodetecting "mobile" from descriptions // so legacy skills sort under the right pill without authoring changes. function normalizePlatform(value, mode, body, description) { - if (value === 'desktop' || value === 'mobile') return value; - if (mode !== 'prototype') return null; - const hay = `${description ?? ''}\n${body ?? ''}`.toLowerCase(); - if (/mobile|phone|ios|android|手机|移动端/.test(hay)) return 'mobile'; - return 'desktop'; + if (value === "desktop" || value === "mobile") return value; + if (mode !== "prototype") return null; + const hay = `${description ?? ""}\n${body ?? ""}`.toLowerCase(); + if (/mobile|phone|ios|android|手机|移动端/.test(hay)) return "mobile"; + return "desktop"; } // Normalise a scenario tag to a small fixed vocabulary so the filter pills // stay tidy. Unknown values pass through verbatim so authors can experiment; // missing values default to "general". const KNOWN_SCENARIOS = new Set([ - 'general', - 'engineering', - 'product', - 'design', - 'marketing', - 'sales', - 'finance', - 'hr', - 'operations', - 'support', - 'legal', - 'education', - 'personal', + "general", + "engineering", + "product", + "design", + "marketing", + "sales", + "finance", + "hr", + "operations", + "support", + "legal", + "education", + "personal", ]); function normalizeScenario(value, body, description) { - if (typeof value === 'string') { + if (typeof value === "string") { const v = value.trim().toLowerCase(); if (v) return v; } - const hay = `${description ?? ''}\n${body ?? ''}`.toLowerCase(); - if (/finance|invoice|expense|budget|p&l|revenue/.test(hay)) return 'finance'; - if (/\bhr\b|onboarding|payroll|employee|人事/.test(hay)) return 'hr'; - if (/marketing|campaign|brand|landing/.test(hay)) return 'marketing'; - if (/runbook|incident|deploy|engineering|sre|api/.test(hay)) return 'engineering'; - if (/spec|prd|roadmap|product manager|product team/.test(hay)) return 'product'; - if (/design system|moodboard|mockup|ui kit/.test(hay)) return 'design'; - if (/sales|quote|proposal|lead/.test(hay)) return 'sales'; - if (/operations|ops|logistics|inventory/.test(hay)) return 'operations'; - return 'general'; + const hay = `${description ?? ""}\n${body ?? ""}`.toLowerCase(); + if (/finance|invoice|expense|budget|p&l|revenue/.test(hay)) return "finance"; + if (/\bhr\b|onboarding|payroll|employee|人事/.test(hay)) return "hr"; + if (/marketing|campaign|brand|landing/.test(hay)) return "marketing"; + if (/runbook|incident|deploy|engineering|sre|api/.test(hay)) + return "engineering"; + if (/spec|prd|roadmap|product manager|product team/.test(hay)) + return "product"; + if (/design system|moodboard|mockup|ui kit/.test(hay)) return "design"; + if (/sales|quote|proposal|lead/.test(hay)) return "sales"; + if (/operations|ops|logistics|inventory/.test(hay)) return "operations"; + return "general"; } // Surface the vocabulary so callers (frontend filter UI) could mirror it // later if they want to. Not exported today, kept here for documentation. diff --git a/docs/assets/_cover/banner.html b/docs/assets/_cover/banner.html new file mode 100644 index 0000000..a3f57b0 --- /dev/null +++ b/docs/assets/_cover/banner.html @@ -0,0 +1,381 @@ + + + + +Open Design — cover + + + + + + +
+
Open Design · Manifesto · 2026 Edition
+
open.design
+
Cover · 01 / 08 · OSS Alternative
+
+ +
+
+
+
+ · APACHE 2.0 + Local-first · BYOK +
+

+ Design with the
+ agent already
+ on your laptop. +

+

+ Open Design is the open-source alternative to Claude Design. + Your existing coding agent — Claude Code · Codex · Cursor · Gemini · OpenCode · Qwen — + becomes the design engine, driven by 19 composable Skills and 71 brand-grade Design Systems. +

+
+ +
+
+
71
+
Design
Systems
+
+
+
19
+
Composable
Skills
+
+
+
06
+
Coding
Agents
+
+
+
0
+
Lock-in /
Vendor Cloud
+
+
+
+ +
+
+
+ · Hi-Fi Prototype · iPhone + +
+
+ · Digital E-guide · 64pp + +
+
+ · Dating App · Web + +
+
OPEN
SOURCE
+
+
+
+ +
+
BYOK at every layer · No cloud lock-in
+
· pnpm dev · vercel deploy · npm start ·
+
github.com/open-design
+
+ + diff --git a/docs/assets/_cover/library.html b/docs/assets/_cover/library.html new file mode 100644 index 0000000..5ed33ff --- /dev/null +++ b/docs/assets/_cover/library.html @@ -0,0 +1,520 @@ + + + + +71 Design Systems — cover + + + + + + + + +
+
+
Style & Format Guide for Designers
+
2026 Edition
+
+ +

The 71
Systems
Library.

+

+ Linear, Stripe, Vercel, Airbnb, Tesla, Notion, Anthropic, Apple, Cursor, Supabase, Figma — + seventy-one brand-grade systems, one open library, zero lock-in. +

+ + +
+
+
71
+
Design
Systems
+
+
+
19
+
Composable
Skills
+
+
+
1
+
Library, zero
vendor cloud
+
+
+ +

What's inside.

+
+
Tokens, palettes, motion04
+
Pick a direction12
+
Tone & typography18
+
71 systems index24
+
Bring-your-own-key40
+
The anti-AI-slop checklist52
+
+ + +
+ + +
+
+
Chapter 02 · Index
+
71 entries · A → Z
+
+ +

All systems —
one library.

+

+ Every system ships a deterministic OKLch palette, a font stack, and a tone profile. + Pick one tile and the agent inherits the whole brand. +

+ +

+ S + eventy-one product systems, two hand-authored starters, five visual directions. Imported and curated + from awesome-design-md, hand-tuned for Open Design's discovery loop. Drop one in, + every artifact downstream changes accordingly — no model freestyle. +

+ +
+ +
+ 07 + Stripe + · payments · indigo +
+
+ 09 + Vercel + · void · grayscale +
+
+ 14 + Airbnb + · rausch · rounded +
+
+ 18 + Tesla + · red · industrial +
+
+ 22 + Notion + · paper · serif +
+
+ 27 + Anthropic + · clay · serif +
+
+ 31 + Apple + · chrome · sf pro +
+
+ 34 + Cursor + · terminal · mono +
+
+ 41 + Supabase + · emerald · rounded +
+
+ 48 + Figma + · spectrum · canvas +
+
+ 57 + OpenAI + · void · sober +
+
+ +
+
+ + + + +
+
+
Spotlight · Linear · 03 / 71
+

Graphite + electric violet.

+

IBM Plex Sans · Inter Display · 4-step OKLch palette · 16/24 grid · square radius. The agent inherits the full token tree the moment you tap the tile.

+
+
+ + + +
71
SYSTEMS
+
+ + + diff --git a/docs/assets/banner.png b/docs/assets/banner.png new file mode 100644 index 0000000..5218331 Binary files /dev/null and b/docs/assets/banner.png differ diff --git a/docs/assets/design-systems-library.png b/docs/assets/design-systems-library.png new file mode 100644 index 0000000..01fb739 Binary files /dev/null and b/docs/assets/design-systems-library.png differ diff --git a/docs/references.md b/docs/references.md index 9daddc4..b2c544f 100644 --- a/docs/references.md +++ b/docs/references.md @@ -11,7 +11,7 @@ Every external project this spec leans on. Three questions per entry: what is it ### [Anthropic Claude Design][cd] - **URL:** [claude.ai/design][cd] · [release announcement](https://www.infoq.cn/article/TH0QVHpvVGZ7VP3hAEmm) · [ifanr review](https://www.ifanr.com/1662860) -[cd]: https://www.anthropic.com/news/claude-design +[cd]: https://x.com/claudeai/status/2045156267690213649 - **What it is:** Anthropic's closed-source AI design product. Released 2026-04-17. Powered by Opus 4.7. Web-only (claude.ai). Generates prototypes, wireframes, decks, marketing pages, complex prototypes with voice/video/3D/shaders. - **Why it matters to us:** Defines the category. Its viral moment (~60M X impressions week 1) proves the market. - **What we borrow:** The high-level value prop — "natural language → editable visual design." Feature inspiration for modes (prototype, deck, marketing). UI ideas around inline editing and custom sliders. diff --git a/docs/screenshots/01-entry-view.png b/docs/screenshots/01-entry-view.png new file mode 100644 index 0000000..60b5f90 Binary files /dev/null and b/docs/screenshots/01-entry-view.png differ diff --git a/docs/screenshots/02-question-form.png b/docs/screenshots/02-question-form.png new file mode 100644 index 0000000..6f73342 Binary files /dev/null and b/docs/screenshots/02-question-form.png differ diff --git a/docs/screenshots/03-direction-picker.png b/docs/screenshots/03-direction-picker.png new file mode 100644 index 0000000..b014041 Binary files /dev/null and b/docs/screenshots/03-direction-picker.png differ diff --git a/docs/screenshots/04-todo-progress.png b/docs/screenshots/04-todo-progress.png new file mode 100644 index 0000000..9e98a67 Binary files /dev/null and b/docs/screenshots/04-todo-progress.png differ diff --git a/docs/screenshots/05-preview-iframe.png b/docs/screenshots/05-preview-iframe.png new file mode 100644 index 0000000..0d509c6 Binary files /dev/null and b/docs/screenshots/05-preview-iframe.png differ diff --git a/docs/screenshots/06-design-systems-library.png b/docs/screenshots/06-design-systems-library.png new file mode 100644 index 0000000..e4de137 Binary files /dev/null and b/docs/screenshots/06-design-systems-library.png differ diff --git a/docs/screenshots/07-magazine-deck.png b/docs/screenshots/07-magazine-deck.png new file mode 100644 index 0000000..2bfcbc4 Binary files /dev/null and b/docs/screenshots/07-magazine-deck.png differ diff --git a/docs/screenshots/08-mobile-app.png b/docs/screenshots/08-mobile-app.png new file mode 100644 index 0000000..48f8c9d Binary files /dev/null and b/docs/screenshots/08-mobile-app.png differ diff --git a/docs/screenshots/skills/dating-web.png b/docs/screenshots/skills/dating-web.png new file mode 100644 index 0000000..87bbcf6 Binary files /dev/null and b/docs/screenshots/skills/dating-web.png differ diff --git a/docs/screenshots/skills/digital-eguide.png b/docs/screenshots/skills/digital-eguide.png new file mode 100644 index 0000000..c5efe2b Binary files /dev/null and b/docs/screenshots/skills/digital-eguide.png differ diff --git a/docs/screenshots/skills/email-marketing.png b/docs/screenshots/skills/email-marketing.png new file mode 100644 index 0000000..8f435b2 Binary files /dev/null and b/docs/screenshots/skills/email-marketing.png differ diff --git a/docs/screenshots/skills/gamified-app.png b/docs/screenshots/skills/gamified-app.png new file mode 100644 index 0000000..dddf081 Binary files /dev/null and b/docs/screenshots/skills/gamified-app.png differ diff --git a/docs/screenshots/skills/mobile-onboarding.png b/docs/screenshots/skills/mobile-onboarding.png new file mode 100644 index 0000000..0d49e9f Binary files /dev/null and b/docs/screenshots/skills/mobile-onboarding.png differ diff --git a/docs/screenshots/skills/motion-frames.png b/docs/screenshots/skills/motion-frames.png new file mode 100644 index 0000000..e83de16 Binary files /dev/null and b/docs/screenshots/skills/motion-frames.png differ diff --git a/docs/screenshots/skills/social-carousel.png b/docs/screenshots/skills/social-carousel.png new file mode 100644 index 0000000..219c4dd Binary files /dev/null and b/docs/screenshots/skills/social-carousel.png differ diff --git a/docs/screenshots/skills/sprite-animation.png b/docs/screenshots/skills/sprite-animation.png new file mode 100644 index 0000000..1c158d2 Binary files /dev/null and b/docs/screenshots/skills/sprite-animation.png differ diff --git a/docs/spec.md b/docs/spec.md index 06b354a..806a0ef 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -3,7 +3,7 @@ **Status:** Draft v0.1 · 2026-04-24 **Scope:** Product definition, scenarios, non-goals, high-level modules, and positioning against both [Anthropic's Claude Design][cd] and the existing open-source alternative ([Open CoDesign][ocod]). -[cd]: https://www.anthropic.com/news/claude-design +[cd]: https://x.com/claudeai/status/2045156267690213649 [ocod]: https://github.com/OpenCoworkAI/open-codesign [guizang]: https://github.com/op7418/guizang-ppt-skill [multica]: https://github.com/multica-ai/multica diff --git a/skills/wireframe-sketch/SKILL.md b/skills/wireframe-sketch/SKILL.md index 3512542..decb05e 100644 --- a/skills/wireframe-sketch/SKILL.md +++ b/skills/wireframe-sketch/SKILL.md @@ -21,6 +21,7 @@ od: mode: prototype platform: desktop scenario: design + fidelity: wireframe preview: type: html entry: index.html diff --git a/src/components/ChatComposer.tsx b/src/components/ChatComposer.tsx index bb6bd2d..d199ab9 100644 --- a/src/components/ChatComposer.tsx +++ b/src/components/ChatComposer.tsx @@ -76,8 +76,12 @@ export const ChatComposer = forwardRef( const importTriggerRef = useRef(null); // initialDraft is only honored on the first non-empty value the parent // hands us. After we seed once, the composer is fully under user control - // — re-renders that pass the same prompt back must not reseed. - const seededRef = useRef(false); + // — re-renders that pass the same prompt back must not reseed. If the + // initial useState above already consumed a non-empty initialDraft we + // mark it seeded immediately, so an early clear by the user (typing or + // backspace before the parent stops passing initialDraft) does not get + // overwritten by the effect. + const seededRef = useRef(Boolean(initialDraft)); useEffect(() => { if (seededRef.current) return; diff --git a/src/components/EntryView.tsx b/src/components/EntryView.tsx index c5d6c49..29dd1a8 100644 --- a/src/components/EntryView.tsx +++ b/src/components/EntryView.tsx @@ -5,6 +5,8 @@ import type { AppConfig, DesignSystemSummary, Project, + ProjectKind, + ProjectMetadata, ProjectTemplate, SkillSummary, } from '../types'; @@ -15,7 +17,7 @@ import { ExamplesTab } from './ExamplesTab'; import { Icon } from './Icon'; import { LanguageMenu } from './LanguageMenu'; import { CenteredLoader } from './Loading'; -import { NewProjectPanel, type CreateInput, type CreateTab } from './NewProjectPanel'; +import { NewProjectPanel, type CreateInput } from './NewProjectPanel'; type TopTab = 'designs' | 'examples' | 'design-systems'; @@ -70,13 +72,6 @@ export function EntryView({ const t = useT(); const [topTab, setTopTab] = useState('designs'); const [previewSystemId, setPreviewSystemId] = useState(null); - const [panelPreset, setPanelPreset] = useState<{ - tab: CreateTab; - skillId: string | null; - name: string; - pendingPrompt?: string; - nonce: number; - } | null>(null); const [sidebarWidth, setSidebarWidth] = useState(() => loadSidebarWidth()); const [resizing, setResizing] = useState(false); @@ -98,13 +93,16 @@ export function EntryView({ : t('settings.noAgentSelected'); }, [config.mode, config.model, config.baseUrl, currentAgent, t]); + // 'Use this prompt' on an example card is a fast path — skip the form and + // create the project immediately with sane defaults derived from the skill, + // seeding the chat composer with the example prompt via pendingPrompt. function usePromptFromSkill(skill: SkillSummary) { - setPanelPreset({ - tab: tabForSkill(skill), - skillId: skill.id, + onCreateProject({ name: skill.name, + skillId: skill.id, + designSystemId: null, + metadata: metadataForSkill(skill), pendingPrompt: skill.examplePrompt || skill.description, - nonce: Date.now(), }); } @@ -118,10 +116,7 @@ export function EntryView({ ); function handleCreate(input: CreateInput) { - onCreateProject({ - ...input, - pendingPrompt: panelPreset?.pendingPrompt, - }); + onCreateProject(input); } const startWidthRef = useRef(0); @@ -177,15 +172,11 @@ export function EntryView({
@@ -313,8 +304,38 @@ function TopTabButton({ ); } -function tabForSkill(skill: SkillSummary): CreateTab { +// Map a skill's declared mode to project metadata. Falls back to the same +// defaults the new-project form would apply (high-fidelity prototype, no +// speaker notes on decks, no template animations) so 'Use this prompt' +// produces a project indistinguishable from one created via the form. Per- +// skill hints in SKILL.md frontmatter (od.fidelity, od.speaker_notes, +// od.animations) override the defaults so each example reproduces the +// shipped example.html — e.g. wireframe-sketch declares fidelity:wireframe. +function metadataForSkill(skill: SkillSummary): ProjectMetadata { + const kind = kindForSkill(skill); + if (kind === 'prototype') { + return { kind, fidelity: skill.fidelity ?? 'high-fidelity' }; + } + if (kind === 'deck') { + return { + kind, + speakerNotes: + typeof skill.speakerNotes === 'boolean' ? skill.speakerNotes : false, + }; + } + if (kind === 'template') { + return { + kind, + animations: + typeof skill.animations === 'boolean' ? skill.animations : false, + }; + } + return { kind: 'other' }; +} + +function kindForSkill(skill: SkillSummary): ProjectKind { if (skill.mode === 'deck') return 'deck'; if (skill.mode === 'prototype') return 'prototype'; - return 'template'; + if (skill.mode === 'template') return 'template'; + return 'other'; } diff --git a/src/components/FileViewer.tsx b/src/components/FileViewer.tsx index c35a82c..d3b2aae 100644 --- a/src/components/FileViewer.tsx +++ b/src/components/FileViewer.tsx @@ -141,13 +141,23 @@ function HtmlViewer({ }; }, [projectId, file.name, file.mtime, liveHtml, reloadKey]); + // Detect deck-shaped HTML even when the project's skill didn't declare + // `mode: deck`. Freeform projects often produce a deck because the user + // asked for one in plain prose; without this, prev/next and Present + // never surface and the deck becomes a static, unnavigable preview. + const looksLikeDeck = useMemo(() => { + if (!source) return false; + return /class\s*=\s*['"][^'"]*\bslide\b/i.test(source); + }, [source]); + const effectiveDeck = isDeck || looksLikeDeck; + const srcDoc = useMemo( - () => (source ? buildSrcdoc(source, { deck: isDeck }) : ''), - [source, isDeck], + () => (source ? buildSrcdoc(source, { deck: effectiveDeck }) : ''), + [source, effectiveDeck], ); useEffect(() => { - if (!isDeck) { + if (!effectiveDeck) { setSlideState(null); return; } @@ -161,7 +171,7 @@ function HtmlViewer({ } window.addEventListener('message', onMessage); return () => window.removeEventListener('message', onMessage); - }, [isDeck]); + }, [effectiveDeck]); function postSlide(action: 'next' | 'prev' | 'first' | 'last') { const win = iframeRef.current?.contentWindow; @@ -172,7 +182,7 @@ function HtmlViewer({ // Keyboard nav on the host, so the user can press ←/→ even when focus // is on the chat composer or any other host control. useEffect(() => { - if (!isDeck || mode !== 'preview') return; + if (!effectiveDeck || mode !== 'preview') return; function onKey(e: KeyboardEvent) { const target = e.target as HTMLElement | null; if (target) { @@ -195,7 +205,7 @@ function HtmlViewer({ } window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); - }, [isDeck, mode]); + }, [effectiveDeck, mode]); useEffect(() => { if (!presentMenuOpen) return; @@ -309,7 +319,7 @@ function HtmlViewer({ setZoom((z) => Math.max(25, Math.min(200, z + delta))); } - const showPresent = isDeck && source !== null; + const showPresent = effectiveDeck && source !== null; const canShare = source !== null; const exportTitle = file.name.replace(/\.html?$/i, '') || file.name; const canPptx = canShare && Boolean(onExportAsPptx) && !streaming; @@ -328,7 +338,7 @@ function HtmlViewer({ > - {isDeck ? ( + {effectiveDeck ? ( { setShareMenuOpen(false); - exportAsPdf(source ?? '', exportTitle, { deck: isDeck }); + exportAsPdf(source ?? '', exportTitle, { deck: effectiveDeck }); }} > - {isDeck + {effectiveDeck ? t('fileViewer.exportPdfAllSlides') : t('fileViewer.exportPdf')} diff --git a/src/components/NewProjectPanel.tsx b/src/components/NewProjectPanel.tsx index d0283f0..cde451a 100644 --- a/src/components/NewProjectPanel.tsx +++ b/src/components/NewProjectPanel.tsx @@ -28,9 +28,6 @@ interface Props { defaultDesignSystemId: string | null; templates: ProjectTemplate[]; onCreate: (input: CreateInput) => void; - presetTab?: CreateTab; - presetSkillId?: string | null; - presetName?: string; loading?: boolean; } @@ -47,14 +44,11 @@ export function NewProjectPanel({ defaultDesignSystemId, templates, onCreate, - presetTab, - presetSkillId, - presetName, loading = false, }: Props) { const t = useT(); - const [tab, setTab] = useState(presetTab ?? 'prototype'); - const [name, setName] = useState(presetName ?? ''); + const [tab, setTab] = useState('prototype'); + const [name, setName] = useState(''); // Design-system selection is now an *array* internally so the same // component can drive both single-select and multi-select modes without // duplicating state. Single-select coerces to length 0/1. @@ -89,7 +83,6 @@ export function NewProjectPanel({ // pick a default-rendered skill (so the agent gets the right SKILL.md // body) without requiring the user to choose one explicitly. const skillIdForTab = useMemo(() => { - if (presetSkillId !== undefined) return presetSkillId; if (tab === 'other') return null; if (tab === 'prototype') { const list = skills.filter((s) => s.mode === 'prototype'); @@ -104,7 +97,7 @@ export function NewProjectPanel({ ?? null; } return null; - }, [tab, skills, presetSkillId]); + }, [tab, skills]); const canCreate = !loading && (tab !== 'template' || templateId != null); diff --git a/src/components/ProjectView.tsx b/src/components/ProjectView.tsx index a31c29b..634869a 100644 --- a/src/components/ProjectView.tsx +++ b/src/components/ProjectView.tsx @@ -666,9 +666,22 @@ export function ProjectView({ [skills, project.skillId], ); - // Hand the pending prompt to ChatPane exactly once. After the first render - // we tell App to clear it so re-entering the project later doesn't reseed. - const initialDraft = project.pendingPrompt; + // Hand the pending prompt to ChatPane exactly once. We snapshot the value + // into local state on mount so it survives the ChatPane remount triggered + // when `activeConversationId` resolves from `null` to a real id (the + // `key={activeConversationId}` on ChatPane otherwise wipes the freshly + // seeded composer draft). Once the conversation id is in place — meaning + // ChatPane has remounted with the seed still available — we clear both + // the local snapshot and the persisted pendingPrompt so future + // conversation switches don't keep re-seeding the composer. + const [initialDraft, setInitialDraft] = useState( + project.pendingPrompt, + ); + useEffect(() => { + if (initialDraft && activeConversationId) { + setInitialDraft(undefined); + } + }, [initialDraft, activeConversationId]); useEffect(() => { if (project.pendingPrompt) onClearPendingPrompt(); }, [project.pendingPrompt, onClearPendingPrompt]); diff --git a/src/runtime/srcdoc.ts b/src/runtime/srcdoc.ts index c6ab634..80414dc 100644 --- a/src/runtime/srcdoc.ts +++ b/src/runtime/srcdoc.ts @@ -16,10 +16,10 @@ */ export function buildSrcdoc( html: string, - options: { deck?: boolean } = {}, + options: { deck?: boolean } = {} ): string { const head = html.trimStart().slice(0, 64).toLowerCase(); - const isFullDoc = head.startsWith(' @@ -30,33 +30,174 @@ export function buildSrcdoc( ${html} `; - if (!options.deck) return wrapped; - return injectDeckBridge(wrapped); + const withShim = injectSandboxShim(wrapped); + if (!options.deck) return withShim; + return injectDeckBridge(withShim); } +// Sandboxed iframes (we use `sandbox="allow-scripts"`) without +// `allow-same-origin` raise a SecurityError on first `localStorage` / +// `sessionStorage` access. Many freeform-generated decks call +// `localStorage.getItem(...)` at the top of their IIFE without a +// try/catch — when it throws, the whole script aborts and the deck +// becomes a static, unnavigable preview. We install a same-origin +// in-memory shim BEFORE any user script runs so those decks degrade +// gracefully (position just doesn't persist across reloads). +function injectSandboxShim(doc: string): string { + const shim = ``; + if (/]*>/i.test(doc)) + return doc.replace(/]*>/i, (m) => `${m}${shim}`); + if (/]*>/i.test(doc)) + return doc.replace(/]*>/i, (m) => `${m}${shim}`); + return shim + doc; +} + +// The deck bridge supports three deck conventions found across our skills +// and freeform-generated artifacts: +// 1. Horizontal scroll decks (simple-deck, guizang-ppt) — slides laid out +// side-by-side, navigation = scrollTo({ left }). +// 2. Class-toggle decks (deck-framework, freeform pitches) — one slide +// carries `.active` or `.is-active`; siblings are display:none. Their +// own JS listens for ArrowRight/Left, so we drive them by dispatching +// synthetic KeyboardEvents. +// 3. Visibility-only decks — no class toggle, slides hidden via inline +// style. We fall back to keyboard dispatch + visibility detection. +// +// All three report `{ active, count }` back to the host so the toolbar can +// render a unified counter. A MutationObserver on each `.slide` lets us +// catch class changes from the deck's own keyboard handler. +// +// We also inject a small CSS override that fixes a common authoring +// mistake in fixed-canvas decks: a `.stage { display: grid; place-items: +// center }` only centers items within their grid cells, but the track +// itself stays `start`-aligned, so the 1920x1080 canvas top-lefts at +// (0,0) of the stage. Combined with `transform-origin: center center`, +// the scaled canvas ends up offset toward the bottom-right of any +// preview that's smaller than 1920x1080 — exactly what users see in the +// sandbox iframe. `place-content: center` centers the track itself. function injectDeckBridge(doc: string): string { + const styleFix = ``; + const docWithStyle = /<\/head>/i.test(doc) + ? doc.replace(/<\/head>/i, styleFix + "") + : /]*>/i.test(doc) + ? doc.replace(/]*>/i, (m) => m + styleFix) + : styleFix + doc; + doc = docWithStyle; const script = ``; - if (/<\/body>/i.test(doc)) return doc.replace(/<\/body>/i, `${script}`); + if (/<\/body>/i.test(doc)) + return doc.replace(/<\/body>/i, `${script}`); return doc + script; } diff --git a/src/types.ts b/src/types.ts index 448555b..0f8aa92 100644 --- a/src/types.ts +++ b/src/types.ts @@ -88,6 +88,15 @@ export interface SkillSummary { * the skill in its natural alphabetical position below all featured * entries. Set via `od.featured` in the SKILL.md frontmatter. */ featured?: number | null; + /** Optional metadata hints, parsed from `od.fidelity`, + * `od.speaker_notes`, and `od.animations` in SKILL.md. Used by the + * Examples gallery's "Use this prompt" fast-create path to mirror the + * shipped `example.html` (e.g. wireframe-sketch declares + * `fidelity: wireframe`). Missing hints fall back to the same defaults + * the new-project form would apply. */ + fidelity?: 'wireframe' | 'high-fidelity' | null; + speakerNotes?: boolean | null; + animations?: boolean | null; hasBody: boolean; examplePrompt: string; } diff --git a/story/STORY.md b/story/STORY.md new file mode 100644 index 0000000..e69de29 diff --git a/story/STORY.zh-CN.md b/story/STORY.zh-CN.md new file mode 100644 index 0000000..e69de29