Upload folder using huggingface_hub
Browse files- .claude-plugin/marketplace.json +20 -0
- .claude-plugin/plugin.json +25 -0
- .codex-plugin/plugin.json +42 -0
- .cursor-plugin/plugin.json +24 -0
- .gitattributes +5 -0
- .github/ISSUE_TEMPLATE/bug-report.yml +30 -0
- .github/ISSUE_TEMPLATE/config.yml +5 -0
- .github/ISSUE_TEMPLATE/skill-request.yml +34 -0
- .github/PULL_REQUEST_TEMPLATE.md +32 -0
- .github/workflows/validate.yml +14 -0
- .gitignore +10 -0
- .opencode/INSTALL.md +130 -0
- .opencode/plugins/opendesign.js +100 -0
- AGENTS.md +37 -0
- CLAUDE.md +37 -0
- CONTRIBUTING.md +53 -0
- GEMINI.md +1 -0
- LICENSE +21 -0
- README.md +157 -3
- VERSIONS.md +37 -0
- gemini-extension.json +6 -0
- opendesign-example.png +3 -0
- package.json +6 -0
- screenshot.png +3 -0
- showcase1.gif +3 -0
- showcase2.gif +3 -0
- showcase3.gif +3 -0
- skills/create-design-system/SKILL.md +68 -0
- skills/frontend-design/SKILL.md +49 -0
- skills/handoff-to-claude-code/SKILL.md +43 -0
- skills/interactive-prototype/SKILL.md +44 -0
- skills/make-a-deck/SKILL.md +101 -0
- skills/make-tweakable/SKILL.md +41 -0
- skills/opendesign/SKILL.md +132 -0
- skills/opendesign/viewer.html +325 -0
- skills/run-opendesign/SKILL.md +87 -0
- skills/setup-opendesign/SKILL.md +44 -0
- skills/wireframe/SKILL.md +43 -0
- validate-skills.sh +77 -0
.claude-plugin/marketplace.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design) for Claude Code. HTML pages, slide decks, interactive prototypes, UI kits, and brand systems.",
|
| 4 |
+
"owner": {
|
| 5 |
+
"name": "manalkaff",
|
| 6 |
+
"email": "manalkaff@gmail.com"
|
| 7 |
+
},
|
| 8 |
+
"plugins": [
|
| 9 |
+
{
|
| 10 |
+
"name": "opendesign",
|
| 11 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design) for Claude Code. HTML pages, slide decks, interactive prototypes, UI kits, and brand systems — with taste, context-matching, and anti-slop discipline.",
|
| 12 |
+
"version": "0.3.1",
|
| 13 |
+
"source": "./",
|
| 14 |
+
"author": {
|
| 15 |
+
"name": "manalkaff",
|
| 16 |
+
"email": "manalkaff@gmail.com"
|
| 17 |
+
}
|
| 18 |
+
}
|
| 19 |
+
]
|
| 20 |
+
}
|
.claude-plugin/plugin.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design) for Claude Code. HTML pages, slide decks, interactive prototypes, UI kits, and brand systems — with taste, context-matching, and anti-slop discipline.",
|
| 4 |
+
"version": "0.3.1",
|
| 5 |
+
"author": {
|
| 6 |
+
"name": "manalkaff",
|
| 7 |
+
"email": "manalkaff@gmail.com"
|
| 8 |
+
},
|
| 9 |
+
"homepage": "https://github.com/manalkaff/opendesign",
|
| 10 |
+
"repository": "https://github.com/manalkaff/opendesign",
|
| 11 |
+
"license": "MIT",
|
| 12 |
+
"keywords": [
|
| 13 |
+
"claude-code",
|
| 14 |
+
"claude-design",
|
| 15 |
+
"skills",
|
| 16 |
+
"design",
|
| 17 |
+
"ui",
|
| 18 |
+
"ux",
|
| 19 |
+
"prototyping",
|
| 20 |
+
"design-system",
|
| 21 |
+
"slides",
|
| 22 |
+
"wireframes",
|
| 23 |
+
"open-source"
|
| 24 |
+
]
|
| 25 |
+
}
|
.codex-plugin/plugin.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"version": "0.3.1",
|
| 4 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design). HTML pages, slide decks, interactive prototypes, UI kits, and brand systems.",
|
| 5 |
+
"author": {
|
| 6 |
+
"name": "manalkaff",
|
| 7 |
+
"email": "manalkaff@gmail.com",
|
| 8 |
+
"url": "https://github.com/manalkaff"
|
| 9 |
+
},
|
| 10 |
+
"homepage": "https://github.com/manalkaff/opendesign",
|
| 11 |
+
"repository": "https://github.com/manalkaff/opendesign",
|
| 12 |
+
"license": "MIT",
|
| 13 |
+
"keywords": [
|
| 14 |
+
"claude-design",
|
| 15 |
+
"design",
|
| 16 |
+
"ui",
|
| 17 |
+
"ux",
|
| 18 |
+
"prototyping",
|
| 19 |
+
"design-system",
|
| 20 |
+
"slides",
|
| 21 |
+
"wireframes"
|
| 22 |
+
],
|
| 23 |
+
"skills": "./skills/",
|
| 24 |
+
"interface": {
|
| 25 |
+
"displayName": "OpenDesign",
|
| 26 |
+
"shortDescription": "A senior designer for your coding agent — decks, prototypes, UI kits, brand systems.",
|
| 27 |
+
"longDescription": "OpenDesign is an open-source, skills-based version of Claude Design (claude.ai/design). It turns your coding agent into a senior designer: intake questions, context-matching, taste discipline, and a verifier pass on the output. Ships eight skills covering wireframes, interactive prototypes, slide decks, design systems, and developer handoff.",
|
| 28 |
+
"developerName": "manalkaff",
|
| 29 |
+
"category": "Design",
|
| 30 |
+
"capabilities": [
|
| 31 |
+
"Interactive",
|
| 32 |
+
"Read",
|
| 33 |
+
"Write"
|
| 34 |
+
],
|
| 35 |
+
"defaultPrompt": [
|
| 36 |
+
"Make a pitch deck for a seed-stage company, 10 slides.",
|
| 37 |
+
"Design a settings page for this app using our existing design system.",
|
| 38 |
+
"I want to explore a few options for the onboarding flow. Rough sketches, nothing polished yet."
|
| 39 |
+
],
|
| 40 |
+
"screenshots": []
|
| 41 |
+
}
|
| 42 |
+
}
|
.cursor-plugin/plugin.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"displayName": "OpenDesign",
|
| 4 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design). HTML pages, slide decks, interactive prototypes, UI kits, and brand systems.",
|
| 5 |
+
"version": "0.3.1",
|
| 6 |
+
"author": {
|
| 7 |
+
"name": "manalkaff",
|
| 8 |
+
"email": "manalkaff@gmail.com"
|
| 9 |
+
},
|
| 10 |
+
"homepage": "https://github.com/manalkaff/opendesign",
|
| 11 |
+
"repository": "https://github.com/manalkaff/opendesign",
|
| 12 |
+
"license": "MIT",
|
| 13 |
+
"keywords": [
|
| 14 |
+
"claude-design",
|
| 15 |
+
"design",
|
| 16 |
+
"ui",
|
| 17 |
+
"ux",
|
| 18 |
+
"prototyping",
|
| 19 |
+
"design-system",
|
| 20 |
+
"slides",
|
| 21 |
+
"wireframes"
|
| 22 |
+
],
|
| 23 |
+
"skills": "./skills/"
|
| 24 |
+
}
|
.gitattributes
CHANGED
|
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
opendesign-example.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
screenshot.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
showcase1.gif filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
showcase2.gif filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
showcase3.gif filter=lfs diff=lfs merge=lfs -text
|
.github/ISSUE_TEMPLATE/bug-report.yml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Bug report
|
| 2 |
+
description: Report a skill behaving incorrectly.
|
| 3 |
+
labels: ["bug"]
|
| 4 |
+
body:
|
| 5 |
+
- type: input
|
| 6 |
+
id: skill
|
| 7 |
+
attributes:
|
| 8 |
+
label: Which skill?
|
| 9 |
+
placeholder: opendesign / wireframe / make-a-deck / ...
|
| 10 |
+
validations:
|
| 11 |
+
required: true
|
| 12 |
+
- type: textarea
|
| 13 |
+
id: expected
|
| 14 |
+
attributes:
|
| 15 |
+
label: Expected behavior
|
| 16 |
+
validations:
|
| 17 |
+
required: true
|
| 18 |
+
- type: textarea
|
| 19 |
+
id: actual
|
| 20 |
+
attributes:
|
| 21 |
+
label: Actual behavior
|
| 22 |
+
validations:
|
| 23 |
+
required: true
|
| 24 |
+
- type: textarea
|
| 25 |
+
id: repro
|
| 26 |
+
attributes:
|
| 27 |
+
label: How to reproduce
|
| 28 |
+
description: Include the prompt you gave and the artifact the agent produced.
|
| 29 |
+
validations:
|
| 30 |
+
required: true
|
.github/ISSUE_TEMPLATE/config.yml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
blank_issues_enabled: false
|
| 2 |
+
contact_links:
|
| 3 |
+
- name: Question or discussion
|
| 4 |
+
url: https://github.com/manalkaff/opendesign/discussions
|
| 5 |
+
about: For general questions and discussion, use Discussions instead of filing an issue.
|
.github/ISSUE_TEMPLATE/skill-request.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Skill request
|
| 2 |
+
description: Propose a new skill or a change to an existing one.
|
| 3 |
+
labels: ["skill-request"]
|
| 4 |
+
body:
|
| 5 |
+
- type: input
|
| 6 |
+
id: skill-name
|
| 7 |
+
attributes:
|
| 8 |
+
label: Skill name
|
| 9 |
+
description: Lowercase, hyphenated (e.g. animate-transitions).
|
| 10 |
+
placeholder: your-skill-name
|
| 11 |
+
validations:
|
| 12 |
+
required: true
|
| 13 |
+
- type: textarea
|
| 14 |
+
id: trigger
|
| 15 |
+
attributes:
|
| 16 |
+
label: When should the agent load this skill?
|
| 17 |
+
description: Write a "Use when..." sentence describing the triggering conditions. Not a summary of what the skill does.
|
| 18 |
+
placeholder: Use when the user asks for ...
|
| 19 |
+
validations:
|
| 20 |
+
required: true
|
| 21 |
+
- type: textarea
|
| 22 |
+
id: why-not-existing
|
| 23 |
+
attributes:
|
| 24 |
+
label: Why doesn't an existing skill cover this?
|
| 25 |
+
description: Check the existing skills in the README. Explain why none of them fit.
|
| 26 |
+
validations:
|
| 27 |
+
required: true
|
| 28 |
+
- type: textarea
|
| 29 |
+
id: rules
|
| 30 |
+
attributes:
|
| 31 |
+
label: Concrete rules the skill would enforce
|
| 32 |
+
description: What forbidden patterns, required constants, or specific behaviors would the body contain?
|
| 33 |
+
validations:
|
| 34 |
+
required: true
|
.github/PULL_REQUEST_TEMPLATE.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!--
|
| 2 |
+
Thanks for the PR. Please fill in the relevant sections and delete the rest.
|
| 3 |
+
-->
|
| 4 |
+
|
| 5 |
+
## What this changes
|
| 6 |
+
|
| 7 |
+
Briefly describe the change.
|
| 8 |
+
|
| 9 |
+
## Type
|
| 10 |
+
|
| 11 |
+
- [ ] New skill
|
| 12 |
+
- [ ] Edit to an existing skill
|
| 13 |
+
- [ ] Documentation
|
| 14 |
+
- [ ] Tooling / infrastructure
|
| 15 |
+
|
| 16 |
+
## If adding a new skill
|
| 17 |
+
|
| 18 |
+
- [ ] `skills/<name>/SKILL.md` created with `name` + `description` frontmatter
|
| 19 |
+
- [ ] Row added to the "Available skills" table in `README.md`
|
| 20 |
+
- [ ] Versions bumped across all host configs (`plugin.json`, `marketplace.json`, `.cursor-plugin/`, `.codex-plugin/`, `gemini-extension.json`, `package.json`)
|
| 21 |
+
|
| 22 |
+
Why can't an existing skill cover this case?
|
| 23 |
+
|
| 24 |
+
## If editing an existing skill
|
| 25 |
+
|
| 26 |
+
- [ ] `name` in frontmatter unchanged (or the change is called out as breaking)
|
| 27 |
+
- [ ] `description` updated if the trigger shifted
|
| 28 |
+
- [ ] Versions bumped if behavior changed
|
| 29 |
+
|
| 30 |
+
## Notes
|
| 31 |
+
|
| 32 |
+
Anything else a reviewer should know.
|
.github/workflows/validate.yml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Validate skills
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
push:
|
| 6 |
+
branches: [main]
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
validate:
|
| 10 |
+
runs-on: ubuntu-latest
|
| 11 |
+
steps:
|
| 12 |
+
- uses: actions/checkout@v4
|
| 13 |
+
- name: Run validator
|
| 14 |
+
run: ./validate-skills.sh
|
.gitignore
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
node_modules/
|
| 2 |
+
.DS_Store
|
| 3 |
+
.env
|
| 4 |
+
.env.*
|
| 5 |
+
.claude/
|
| 6 |
+
.worktrees/
|
| 7 |
+
*.log
|
| 8 |
+
.idea/
|
| 9 |
+
.vscode/
|
| 10 |
+
docs/superpowers
|
.opencode/INSTALL.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Installing OpenDesign for OpenCode
|
| 2 |
+
|
| 3 |
+
## Prerequisites
|
| 4 |
+
|
| 5 |
+
- [OpenCode.ai](https://opencode.ai) installed
|
| 6 |
+
|
| 7 |
+
## Installation
|
| 8 |
+
|
| 9 |
+
### Project-level (recommended)
|
| 10 |
+
|
| 11 |
+
Add opendesign to `.opencode/opencode.json` in your project root (create the file if it does not exist):
|
| 12 |
+
|
| 13 |
+
```json
|
| 14 |
+
{
|
| 15 |
+
"$schema": "../opencode-schema.json",
|
| 16 |
+
"plugin": [
|
| 17 |
+
"opendesign@git+https://github.com/manalkaff/opendesign.git"
|
| 18 |
+
]
|
| 19 |
+
}
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
> **Note:** Current OpenCode reads project-level config from `.opencode/opencode.json`, not from `opencode.json` or `.opencode.json` at the repo root. If you added the plugin to one of those locations and it is not loading, move it here.
|
| 23 |
+
|
| 24 |
+
Restart OpenCode. The first install fetches the package from GitHub and may take 10–30 seconds while dependencies are reified — wait for it before assuming something failed.
|
| 25 |
+
|
| 26 |
+
### Global (all projects)
|
| 27 |
+
|
| 28 |
+
Add opendesign to your global config at `~/.config/opencode/opencode.json` or `~/.opencode/opencode.json`:
|
| 29 |
+
|
| 30 |
+
```json
|
| 31 |
+
{
|
| 32 |
+
"plugin": [
|
| 33 |
+
"opendesign@git+https://github.com/manalkaff/opendesign.git"
|
| 34 |
+
]
|
| 35 |
+
}
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
Restart OpenCode.
|
| 39 |
+
|
| 40 |
+
## Verifying install
|
| 41 |
+
|
| 42 |
+
After restarting, verify by asking: "What design skills do you have?"
|
| 43 |
+
|
| 44 |
+
You should see opendesign skills listed. If skill count did not increase, check the logs (see Troubleshooting below).
|
| 45 |
+
|
| 46 |
+
## Usage
|
| 47 |
+
|
| 48 |
+
Use OpenCode's native `skill` tool:
|
| 49 |
+
|
| 50 |
+
```
|
| 51 |
+
use skill tool to list skills
|
| 52 |
+
use skill tool to load opendesign
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
## Updating
|
| 56 |
+
|
| 57 |
+
OpenDesign updates automatically when you restart OpenCode.
|
| 58 |
+
|
| 59 |
+
If OpenCode still shows older skill content after restart, see `Troubleshooting -> Stale cached plugin content` below. In some cases OpenCode continues using an older cached package until that cache entry is removed.
|
| 60 |
+
|
| 61 |
+
To pin a specific version:
|
| 62 |
+
|
| 63 |
+
```json
|
| 64 |
+
{
|
| 65 |
+
"plugin": ["opendesign@git+https://github.com/manalkaff/opendesign.git#v0.1.0"]
|
| 66 |
+
}
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
## Troubleshooting
|
| 70 |
+
|
| 71 |
+
### Plugin not loading
|
| 72 |
+
|
| 73 |
+
1. Check logs for these key lines:
|
| 74 |
+
|
| 75 |
+
```
|
| 76 |
+
project config loaded from .opencode/opencode.json ← confirms correct config path
|
| 77 |
+
project .opencode reify ← npm install in progress
|
| 78 |
+
loading plugin ← plugin being initialized
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
Run: `opencode run --print-logs "hello" 2>&1 | grep -iE "opendesign|reify|project config|plugin"`
|
| 82 |
+
|
| 83 |
+
2. Make sure the plugin entry is in `.opencode/opencode.json` (not `opencode.json` or `.opencode.json` at the repo root — those may be ignored by current OpenCode builds for project-level plugin loading).
|
| 84 |
+
|
| 85 |
+
3. Make sure you are running a recent version of OpenCode.
|
| 86 |
+
|
| 87 |
+
4. If you just added the plugin for the first time, wait 30 seconds on the next restart — the git package download and npm reify take time.
|
| 88 |
+
|
| 89 |
+
### Skills not found
|
| 90 |
+
|
| 91 |
+
1. Use `skill` tool to list what is discovered.
|
| 92 |
+
2. Confirm the plugin loaded (see log check above).
|
| 93 |
+
3. Confirm skill count increased after restart.
|
| 94 |
+
|
| 95 |
+
### Stale cached plugin content
|
| 96 |
+
|
| 97 |
+
If OpenCode loads the plugin but the skill text still looks outdated after you updated or reinstalled `opendesign`, OpenCode may be using a stale cached package copy under `~/.cache/opencode/packages/`.
|
| 98 |
+
|
| 99 |
+
Symptoms include:
|
| 100 |
+
|
| 101 |
+
- the plugin appears installed, but skill content still reflects an older revision
|
| 102 |
+
- reinstalling in `~/.config/opencode/` or `~/.opencode/` does not change the loaded skill text
|
| 103 |
+
- the cached package under `~/.cache/opencode/packages/` contains an older `opendesign` version than the one you expect
|
| 104 |
+
|
| 105 |
+
Check the cached copy directly:
|
| 106 |
+
|
| 107 |
+
```bash
|
| 108 |
+
grep -n "design-systems" ~/.cache/opencode/packages/opendesign@git+https:/github.com/manalkaff/opendesign.git/node_modules/opendesign/skills/opendesign/SKILL.md
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
If that cached package is stale, remove it and restart OpenCode so it can fetch the current plugin again:
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
rm -rf ~/.cache/opencode/packages/opendesign@git+https:/github.com/manalkaff/opendesign.git
|
| 115 |
+
```
|
| 116 |
+
|
| 117 |
+
Then fully restart OpenCode and start a fresh session.
|
| 118 |
+
|
| 119 |
+
### Tool mapping
|
| 120 |
+
|
| 121 |
+
When skills reference Claude Code tools:
|
| 122 |
+
- `TodoWrite` → `todowrite`
|
| 123 |
+
- `Task` with subagents → `@mention` syntax
|
| 124 |
+
- `Skill` tool → OpenCode's native `skill` tool
|
| 125 |
+
- File operations → your native tools
|
| 126 |
+
|
| 127 |
+
## Getting help
|
| 128 |
+
|
| 129 |
+
- Report issues: https://github.com/manalkaff/opendesign/issues
|
| 130 |
+
- Repo: https://github.com/manalkaff/opendesign
|
.opencode/plugins/opendesign.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* OpenDesign plugin for OpenCode.ai
|
| 3 |
+
*
|
| 4 |
+
* Injects the opendesign bootstrap skill via chat transform,
|
| 5 |
+
* and registers the skills directory via config hook (no symlinks needed).
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
import path from 'path';
|
| 9 |
+
import fs from 'fs';
|
| 10 |
+
import os from 'os';
|
| 11 |
+
import { fileURLToPath } from 'url';
|
| 12 |
+
|
| 13 |
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
| 14 |
+
|
| 15 |
+
// Minimal frontmatter extractor (avoids external deps).
|
| 16 |
+
const extractAndStripFrontmatter = (content) => {
|
| 17 |
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
| 18 |
+
if (!match) return { frontmatter: {}, content };
|
| 19 |
+
|
| 20 |
+
const frontmatterStr = match[1];
|
| 21 |
+
const body = match[2];
|
| 22 |
+
const frontmatter = {};
|
| 23 |
+
|
| 24 |
+
for (const line of frontmatterStr.split('\n')) {
|
| 25 |
+
const colonIdx = line.indexOf(':');
|
| 26 |
+
if (colonIdx > 0) {
|
| 27 |
+
const key = line.slice(0, colonIdx).trim();
|
| 28 |
+
const value = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, '');
|
| 29 |
+
frontmatter[key] = value;
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
return { frontmatter, content: body };
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
const normalizePath = (p, homeDir) => {
|
| 37 |
+
if (!p || typeof p !== 'string') return null;
|
| 38 |
+
let normalized = p.trim();
|
| 39 |
+
if (!normalized) return null;
|
| 40 |
+
if (normalized.startsWith('~/')) {
|
| 41 |
+
normalized = path.join(homeDir, normalized.slice(2));
|
| 42 |
+
} else if (normalized === '~') {
|
| 43 |
+
normalized = homeDir;
|
| 44 |
+
}
|
| 45 |
+
return path.resolve(normalized);
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
export const OpenDesignPlugin = async ({ client, directory }) => {
|
| 49 |
+
const homeDir = os.homedir();
|
| 50 |
+
const opendesignSkillsDir = path.resolve(__dirname, '../../skills');
|
| 51 |
+
const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
|
| 52 |
+
const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
|
| 53 |
+
|
| 54 |
+
const getBootstrapContent = () => {
|
| 55 |
+
const skillPath = path.join(opendesignSkillsDir, 'opendesign', 'SKILL.md');
|
| 56 |
+
if (!fs.existsSync(skillPath)) return null;
|
| 57 |
+
|
| 58 |
+
const fullContent = fs.readFileSync(skillPath, 'utf8');
|
| 59 |
+
const { content } = extractAndStripFrontmatter(fullContent);
|
| 60 |
+
|
| 61 |
+
const toolMapping = `**Tool Mapping for OpenCode:**
|
| 62 |
+
When OpenDesign skills reference tools you don't have, substitute OpenCode equivalents:
|
| 63 |
+
- \`TodoWrite\` → \`todowrite\`
|
| 64 |
+
- \`Task\` tool with subagents → OpenCode's subagent system (@mention)
|
| 65 |
+
- \`Skill\` tool → OpenCode's native \`skill\` tool
|
| 66 |
+
- \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → your native tools
|
| 67 |
+
|
| 68 |
+
Use OpenCode's native \`skill\` tool to list and load the other OpenDesign skills (wireframe, make-a-deck, interactive-prototype, etc.) on demand.`;
|
| 69 |
+
|
| 70 |
+
return `<EXTREMELY_IMPORTANT>
|
| 71 |
+
You have OpenDesign loaded.
|
| 72 |
+
|
| 73 |
+
**The opendesign entry-point skill is included below. It is ALREADY LOADED — you are currently following it. Do NOT use the skill tool to load "opendesign" again.**
|
| 74 |
+
|
| 75 |
+
${content}
|
| 76 |
+
|
| 77 |
+
${toolMapping}
|
| 78 |
+
</EXTREMELY_IMPORTANT>`;
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
return {
|
| 82 |
+
// Register the skills directory so OpenCode discovers every SKILL.md
|
| 83 |
+
// without the user editing opencode.json or symlinking.
|
| 84 |
+
config: async (config) => {
|
| 85 |
+
config.skills = config.skills || {};
|
| 86 |
+
config.skills.paths = config.skills.paths || [];
|
| 87 |
+
if (!config.skills.paths.includes(opendesignSkillsDir)) {
|
| 88 |
+
config.skills.paths.push(opendesignSkillsDir);
|
| 89 |
+
}
|
| 90 |
+
},
|
| 91 |
+
|
| 92 |
+
// Use system prompt transform for compatibility with current OpenCode builds.
|
| 93 |
+
'experimental.chat.system.transform': async (_input, output) => {
|
| 94 |
+
const bootstrap = getBootstrapContent();
|
| 95 |
+
if (bootstrap) {
|
| 96 |
+
(output.system ||= []).push(bootstrap);
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
};
|
| 100 |
+
};
|
AGENTS.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Agent instructions for this repository
|
| 2 |
+
|
| 3 |
+
This repo is **OpenDesign** — an open-source, skills-based version of [Claude Design](https://claude.ai/design) (the web design mode on claude.ai), packaged as a Claude Code plugin. When working inside this repository, your job is to maintain and extend those skills — not to run them.
|
| 4 |
+
|
| 5 |
+
## Repo layout
|
| 6 |
+
|
| 7 |
+
- `skills/<skill-name>/SKILL.md` — one folder per skill. Each `SKILL.md` has YAML frontmatter (`name`, `description`) followed by the skill body.
|
| 8 |
+
- `.claude-plugin/plugin.json` — Claude Code plugin metadata.
|
| 9 |
+
- `.claude-plugin/marketplace.json` — Claude Code marketplace entry. Skills are discovered by convention from `./skills/`; do not add a `skills[]` field (Claude Code's schema rejects it).
|
| 10 |
+
- `.cursor-plugin/plugin.json` — Cursor plugin metadata.
|
| 11 |
+
- `.codex-plugin/plugin.json` — Codex plugin metadata (richer `interface` block for app UI).
|
| 12 |
+
- `.opencode/plugins/opendesign.js` — OpenCode plugin (registers skills dir + injects `opendesign` bootstrap into the first user message).
|
| 13 |
+
- `.opencode/INSTALL.md` — user-facing install notes for OpenCode.
|
| 14 |
+
- `gemini-extension.json` + `GEMINI.md` — Gemini CLI extension. `GEMINI.md` `@-`imports the `opendesign` skill as context.
|
| 15 |
+
- `package.json` — required so OpenCode can install the repo via `git+https://...`. `main` points at the OpenCode plugin entry.
|
| 16 |
+
- `README.md` — user-facing. The "Available skills" table must match the actual skills shipped.
|
| 17 |
+
|
| 18 |
+
## Rules when editing skills
|
| 19 |
+
|
| 20 |
+
- Skills are written in direct imperative voice. No marketing language, no apologies, no emoji.
|
| 21 |
+
- Every `SKILL.md` must start with frontmatter containing `name` and `description`. `description` is a "Use when..." sentence that describes triggering conditions, not a summary of what the skill does.
|
| 22 |
+
- Keep `opendesign/SKILL.md` as the entry-point/base skill. Specialist skills (`wireframe`, `make-a-deck`, etc.) are loaded on demand by the workflow described there.
|
| 23 |
+
- If you add a new skill: create `skills/<name>/SKILL.md` with frontmatter and add a row to the README table. Do not add a per-skill list to `.claude-plugin/marketplace.json`; Claude Code discovers skills from `./skills/`.
|
| 24 |
+
- If you rename or remove a skill: update the README table and any direct references to that skill in the same change.
|
| 25 |
+
|
| 26 |
+
## Rules when editing the plugin config
|
| 27 |
+
|
| 28 |
+
- `name` must match across every host config: `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` (both top-level and `plugins[0].name`), `.cursor-plugin/plugin.json`, `.codex-plugin/plugin.json`, `gemini-extension.json`, and `package.json`.
|
| 29 |
+
- Bump `version` everywhere together: both `.claude-plugin/*.json` files, `.cursor-plugin/plugin.json`, `.codex-plugin/plugin.json`, `gemini-extension.json`, and `package.json`. Also add a new section to `VERSIONS.md`.
|
| 30 |
+
- `.opencode/plugins/opendesign.js` bootstraps from `skills/opendesign/SKILL.md`. If you rename or remove that skill, update the path in the JS.
|
| 31 |
+
- Do not add secrets or personal paths to any config file.
|
| 32 |
+
|
| 33 |
+
## Style
|
| 34 |
+
|
| 35 |
+
- Concrete beats vague ("Use `#246BFD` for primary buttons" beats "use a blue tone").
|
| 36 |
+
- Specific rules and forbidden patterns beat aspirational prose.
|
| 37 |
+
- Prefer editing existing skills over adding new ones.
|
CLAUDE.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Agent instructions for this repository
|
| 2 |
+
|
| 3 |
+
This repo is **OpenDesign** — an open-source, skills-based version of [Claude Design](https://claude.ai/design) (the web design mode on claude.ai), packaged as a Claude Code plugin. When working inside this repository, your job is to maintain and extend those skills — not to run them.
|
| 4 |
+
|
| 5 |
+
## Repo layout
|
| 6 |
+
|
| 7 |
+
- `skills/<skill-name>/SKILL.md` — one folder per skill. Each `SKILL.md` has YAML frontmatter (`name`, `description`) followed by the skill body.
|
| 8 |
+
- `.claude-plugin/plugin.json` — Claude Code plugin metadata.
|
| 9 |
+
- `.claude-plugin/marketplace.json` — Claude Code marketplace entry. Skills are discovered by convention from `./skills/`; do not add a `skills[]` field (Claude Code's schema rejects it).
|
| 10 |
+
- `.cursor-plugin/plugin.json` — Cursor plugin metadata.
|
| 11 |
+
- `.codex-plugin/plugin.json` — Codex plugin metadata (richer `interface` block for app UI).
|
| 12 |
+
- `.opencode/plugins/opendesign.js` — OpenCode plugin (registers skills dir + injects `opendesign` bootstrap into the first user message).
|
| 13 |
+
- `.opencode/INSTALL.md` — user-facing install notes for OpenCode.
|
| 14 |
+
- `gemini-extension.json` + `GEMINI.md` — Gemini CLI extension. `GEMINI.md` `@-`imports the `opendesign` skill as context.
|
| 15 |
+
- `package.json` — required so OpenCode can install the repo via `git+https://...`. `main` points at the OpenCode plugin entry.
|
| 16 |
+
- `README.md` — user-facing. The "Available skills" table must match the actual skills shipped.
|
| 17 |
+
|
| 18 |
+
## Rules when editing skills
|
| 19 |
+
|
| 20 |
+
- Skills are written in direct imperative voice. No marketing language, no apologies, no emoji.
|
| 21 |
+
- Every `SKILL.md` must start with frontmatter containing `name` and `description`. `description` is a "Use when..." sentence that describes triggering conditions, not a summary of what the skill does.
|
| 22 |
+
- Keep `opendesign/SKILL.md` as the entry-point/base skill. Specialist skills (`wireframe`, `make-a-deck`, etc.) are loaded on demand by the workflow described there.
|
| 23 |
+
- If you add a new skill: create `skills/<name>/SKILL.md` with frontmatter and add a row to the README table. Do not add a per-skill list to `.claude-plugin/marketplace.json`; Claude Code discovers skills from `./skills/`.
|
| 24 |
+
- If you rename or remove a skill: update the README table and any direct references to that skill in the same change.
|
| 25 |
+
|
| 26 |
+
## Rules when editing the plugin config
|
| 27 |
+
|
| 28 |
+
- `name` must match across every host config: `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` (both top-level and `plugins[0].name`), `.cursor-plugin/plugin.json`, `.codex-plugin/plugin.json`, `gemini-extension.json`, and `package.json`.
|
| 29 |
+
- Bump `version` everywhere together: both `.claude-plugin/*.json` files, `.cursor-plugin/plugin.json`, `.codex-plugin/plugin.json`, `gemini-extension.json`, and `package.json`. Also add a new section to `VERSIONS.md`.
|
| 30 |
+
- `.opencode/plugins/opendesign.js` bootstraps from `skills/opendesign/SKILL.md`. If you rename or remove that skill, update the path in the JS.
|
| 31 |
+
- Do not add secrets or personal paths to any config file.
|
| 32 |
+
|
| 33 |
+
## Style
|
| 34 |
+
|
| 35 |
+
- Concrete beats vague ("Use `#246BFD` for primary buttons" beats "use a blue tone").
|
| 36 |
+
- Specific rules and forbidden patterns beat aspirational prose.
|
| 37 |
+
- Prefer editing existing skills over adding new ones.
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to OpenDesign
|
| 2 |
+
|
| 3 |
+
Thanks for considering a contribution. OpenDesign is an open-source, skills-based version of [Claude Design](https://claude.ai/design) — the goal is parity with that experience, not feature creep. This repo ships a small, opinionated set of skills; quality bar is higher than coverage. Before adding a new skill, strongly consider whether an existing one can be extended instead.
|
| 4 |
+
|
| 5 |
+
## Ground rules
|
| 6 |
+
|
| 7 |
+
- Every `SKILL.md` is written in direct imperative voice. No marketing language, no apologies, no emoji, no "as we discussed".
|
| 8 |
+
- Concrete beats vague. Specific rules, forbidden patterns, and measured constants beat aspirational prose.
|
| 9 |
+
- Skills describe *behavior under specific conditions*, not philosophies. If your skill body is abstract, it's not ready.
|
| 10 |
+
|
| 11 |
+
## SKILL.md format
|
| 12 |
+
|
| 13 |
+
```markdown
|
| 14 |
+
---
|
| 15 |
+
name: your-skill-name
|
| 16 |
+
description: Use when [specific triggering conditions]. [One-line summary of what it produces.]
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
Loaded when [restate trigger].
|
| 20 |
+
|
| 21 |
+
## [Section]
|
| 22 |
+
|
| 23 |
+
[Rules, constants, forbidden patterns, required paths. Be concrete.]
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
Rules:
|
| 27 |
+
|
| 28 |
+
- `name` uses lowercase and hyphens. Must match the folder name.
|
| 29 |
+
- `description` starts with "Use when..." and describes *when the skill applies*, not what it does internally. The agent reads this to decide whether to load the skill.
|
| 30 |
+
- Do not summarize the skill's workflow in the description — the skill body is authoritative.
|
| 31 |
+
|
| 32 |
+
## Adding a new skill
|
| 33 |
+
|
| 34 |
+
1. Create `skills/<name>/SKILL.md` with frontmatter and body.
|
| 35 |
+
2. Add a row to the "Available skills" table in `README.md`.
|
| 36 |
+
3. Open a PR. In the description, state:
|
| 37 |
+
- What the skill does.
|
| 38 |
+
- Why existing skills can't cover this case.
|
| 39 |
+
- Any risk of overlap with `opendesign`, `frontend-design`, `create-design-system`, or `make-a-deck`.
|
| 40 |
+
|
| 41 |
+
## Editing an existing skill
|
| 42 |
+
|
| 43 |
+
- Keep the frontmatter `name` stable — changing it is a breaking change for users.
|
| 44 |
+
- If you're narrowing or widening the trigger, update the `description` in the same change.
|
| 45 |
+
- Bump the version in every host config for any user-visible change. Run `bash validate-skills.sh` to catch version drift.
|
| 46 |
+
|
| 47 |
+
## Things I'll reject
|
| 48 |
+
|
| 49 |
+
- Skills that replicate what an existing skill covers with minor variation.
|
| 50 |
+
- Skill bodies that read like a blog post or pitch.
|
| 51 |
+
- Emoji, marketing adjectives, or aspirational prose.
|
| 52 |
+
- Frontmatter that summarizes the skill's workflow instead of its trigger.
|
| 53 |
+
- PRs that add a skill file but forget the README update.
|
GEMINI.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
@./skills/opendesign/SKILL.md
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 manalkaff
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,11 +1,165 @@
|
|
| 1 |
---
|
| 2 |
license: mit
|
| 3 |
-
tags:
|
| 4 |
-
- opendesign
|
| 5 |
language:
|
| 6 |
- es
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
---
|
| 8 |
|
| 9 |
# OpenDesign
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
license: mit
|
|
|
|
|
|
|
| 3 |
language:
|
| 4 |
- es
|
| 5 |
+
tags:
|
| 6 |
+
- opendesign
|
| 7 |
+
- design
|
| 8 |
+
- skills
|
| 9 |
+
- agents
|
| 10 |
---
|
| 11 |
|
| 12 |
# OpenDesign
|
| 13 |
|
| 14 |
+
## Why this exists
|
| 15 |
+
|
| 16 |
+
Claude Design on claude.ai is excellent. But it's locked.
|
| 17 |
+
|
| 18 |
+
Locked to the browser. Locked to Anthropic models. Locked to the web app — which means no access to your local files, no integration with your existing design system, and no way to use it inside the editor where your actual work happens.
|
| 19 |
+
|
| 20 |
+
I built OpenDesign to fix that. Same philosophy as Claude Design — structured intake, context-matching, taste, a verifier that checks the output against the brief — but packaged as portable markdown skills you can install in Claude Code, Cursor, Codex, Gemini CLI, or OpenCode. It runs locally, reads your codebase, and works with whatever model you're on.
|
| 21 |
+
|
| 22 |
+
You own it. You can read every skill, fork it, and extend it.
|
| 23 |
+
|
| 24 |
+
## What it does
|
| 25 |
+
|
| 26 |
+
OpenDesign turns your AI coding agent into a designer with taste, opinions, and the discipline to restrain them. HTML is the output medium. Inside that medium it embodies whichever specialist the task calls for — deck designer, UX designer, prototyper, brand designer.
|
| 27 |
+
|
| 28 |
+
It doesn't generate generic AI output. It reads your actual codebase first.
|
| 29 |
+
|
| 30 |
+

|
| 31 |
+
*OpenDesign extracting a live design system from a real codebase — colors, typography, tokens, all sourced directly from `src/app.css`.*
|
| 32 |
+
|
| 33 |
+
## Showcase
|
| 34 |
+
|
| 35 |
+

|
| 36 |
+
|
| 37 |
+

|
| 38 |
+
|
| 39 |
+

|
| 40 |
+
|
| 41 |
+
Ten skills ship together. One is the entry point (`opendesign`); the others are loaded on demand by the workflow.
|
| 42 |
+
|
| 43 |
+
## Available skills
|
| 44 |
+
|
| 45 |
+
<!-- SKILLS:START -->
|
| 46 |
+
|
| 47 |
+
| Skill | Use when |
|
| 48 |
+
|---|---|
|
| 49 |
+
| `opendesign` | Starting any design task. Establishes the base role, workflow, and taste rules, and routes to specialist skills. |
|
| 50 |
+
| `setup-opendesign` | Initialising OpenDesign for the first time in a project. Creates output folders, copies the viewer, and writes an empty manifest. Called automatically by `opendesign` — rarely needed directly. |
|
| 51 |
+
| `run-opendesign` | Starting the preview server after a build. Serves `./opendesign/` on port 8289, handles duplicate prevention and python/node detection, and prints a clickable link. Called automatically by `opendesign` — rarely needed directly. |
|
| 52 |
+
| `create-design-system` | Producing a reusable design system or UI kit from an existing brand, codebase, or product. |
|
| 53 |
+
| `frontend-design` | Designing without an existing brand system. Pushes for a committed, distinctive aesthetic. |
|
| 54 |
+
| `wireframe` | Exploring the design space quickly — many rough ideas, not one polished direction. |
|
| 55 |
+
| `interactive-prototype` | Asking for a working, clickable prototype that behaves like a real app. |
|
| 56 |
+
| `make-a-deck` | Asking for a slide presentation. Fixed 1920×1080 canvas, chapter-driven titles. |
|
| 57 |
+
| `make-tweakable` | Wanting in-design controls for toggling variants, colors, copy, or feature flags. |
|
| 58 |
+
| `handoff-to-claude-code` | Handing a finished design off to a developer or coding agent for implementation. |
|
| 59 |
+
|
| 60 |
+
<!-- SKILLS:END -->
|
| 61 |
+
|
| 62 |
+
## How the skills work together
|
| 63 |
+
|
| 64 |
+
`opendesign` is the front door. On invocation it:
|
| 65 |
+
|
| 66 |
+
1. Scans `./opendesign/design-systems/*/` for existing systems (looking for `SKILL.md` or `tokens/colors_and_type.css` as markers).
|
| 67 |
+
2. Announces what it found and picks the right one, asks, or offers to create one.
|
| 68 |
+
3. Runs a structured intake if the work is new.
|
| 69 |
+
4. Routes to the specialist skill for the artifact (deck → `make-a-deck`, prototype → `interactive-prototype`, etc.).
|
| 70 |
+
5. Forks a verifier subagent to review against the brief.
|
| 71 |
+
|
| 72 |
+
Design systems created by `create-design-system` are written to `./opendesign/design-systems/<name>/` so `opendesign` can auto-discover them in future sessions. Multiple systems per project are supported — a marketing system, a product system, a deck template — and the agent picks based on task shape.
|
| 73 |
+
|
| 74 |
+
## Installation
|
| 75 |
+
|
| 76 |
+
**Note:** Installation differs by platform.
|
| 77 |
+
|
| 78 |
+
### Claude Code
|
| 79 |
+
|
| 80 |
+
```bash
|
| 81 |
+
/plugin marketplace add manalkaff/opendesign
|
| 82 |
+
/plugin install opendesign@opendesign
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
### Cursor
|
| 86 |
+
|
| 87 |
+
In Cursor Agent chat:
|
| 88 |
+
|
| 89 |
+
```text
|
| 90 |
+
/add-plugin opendesign
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
Or search for "opendesign" in the plugin marketplace.
|
| 94 |
+
|
| 95 |
+
### OpenAI Codex CLI
|
| 96 |
+
|
| 97 |
+
Open the plugin search:
|
| 98 |
+
|
| 99 |
+
```bash
|
| 100 |
+
/plugins
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
Search for `opendesign` and select **Install Plugin**.
|
| 104 |
+
|
| 105 |
+
### OpenAI Codex App
|
| 106 |
+
|
| 107 |
+
In the Codex app, click **Plugins** in the sidebar, find **OpenDesign** in the Design section, click the `+`, and follow the prompts.
|
| 108 |
+
|
| 109 |
+
### Gemini CLI
|
| 110 |
+
|
| 111 |
+
```bash
|
| 112 |
+
gemini extensions install https://github.com/manalkaff/opendesign
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
To update:
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
gemini extensions update opendesign
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
### OpenCode
|
| 122 |
+
|
| 123 |
+
Tell OpenCode:
|
| 124 |
+
|
| 125 |
+
```
|
| 126 |
+
Fetch and follow instructions from https://raw.githubusercontent.com/manalkaff/opendesign/main/.opencode/INSTALL.md
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
### Fork
|
| 130 |
+
|
| 131 |
+
Fork the repo, add your own skills under `skills/`, and install your fork through whichever host you use.
|
| 132 |
+
|
| 133 |
+
## Usage
|
| 134 |
+
|
| 135 |
+
Once installed, invoke with `/opendesign` and describe what you want. The agent picks up the right skills on its own.
|
| 136 |
+
|
| 137 |
+
```
|
| 138 |
+
/opendesign make a pitch deck for a seed-stage AI company, 10 slides
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
```
|
| 142 |
+
/opendesign design a settings page for this React app — use our existing design system
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
```
|
| 146 |
+
/opendesign explore a few options for the onboarding flow. rough sketches, nothing polished yet
|
| 147 |
+
```
|
| 148 |
+
|
| 149 |
+
```
|
| 150 |
+
/opendesign extract our design system from the codebase and document it
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
## Upgrading
|
| 154 |
+
|
| 155 |
+
If you installed via the plugin marketplace, run `/plugin update opendesign` inside Claude Code.
|
| 156 |
+
|
| 157 |
+
If you cloned or submoduled, `git pull` in the repo.
|
| 158 |
+
|
| 159 |
+
## Contributing
|
| 160 |
+
|
| 161 |
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Quality bar is higher than coverage — consider extending an existing skill before adding a new one.
|
| 162 |
+
|
| 163 |
+
## License
|
| 164 |
+
|
| 165 |
+
[MIT](LICENSE)
|
VERSIONS.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Versions
|
| 2 |
+
|
| 3 |
+
## 0.3.1
|
| 4 |
+
|
| 5 |
+
Bug fixes for `run-opendesign` and `setup-opendesign`.
|
| 6 |
+
|
| 7 |
+
- `setup-opendesign` — fixed viewer.html fetch URL (`open-design` → `opendesign`), preventing a potential silent hijack if the old repo name is reclaimed.
|
| 8 |
+
- `run-opendesign` — port check now probes `/opendesign/index.html` for a 200 before treating :8289 as the OpenDesign server; a foreign process on that port now surfaces a clear error instead of a dead link.
|
| 9 |
+
- `run-opendesign` — added platform detection (`uname -s`); Windows path uses `netstat` for port checks, `python`-first runtime priority, and `Start-Process` for background launch.
|
| 10 |
+
|
| 11 |
+
## 0.3.0
|
| 12 |
+
|
| 13 |
+
Preview server — clickable link after every build, no manual terminal commands.
|
| 14 |
+
|
| 15 |
+
- `run-opendesign` — new skill. Checks if port 8289 is already in use, detects python3/python/node, starts the server in the background, prints `http://localhost:8289/opendesign/` as a clickable link.
|
| 16 |
+
- `opendesign` — step 5 now dispatches `run-opendesign` after writing the manifest instead of telling the user to open the file manually.
|
| 17 |
+
|
| 18 |
+
## 0.2.0
|
| 19 |
+
|
| 20 |
+
Mockup viewer — browse and preview all mockups from a single page.
|
| 21 |
+
|
| 22 |
+
- `setup-opendesign` — new first-run setup skill. Downloads `viewer.html` from GitHub, creates output folders, initialises `manifest.json`. Called automatically by `opendesign`.
|
| 23 |
+
- `opendesign` — step 1 now dispatches `setup-opendesign` on first run; step 5 now scans and rewrites `manifest.json` after every build.
|
| 24 |
+
- `viewer.html` — pre-built HTML viewer shipped with the plugin. Dark sidebar, iframe preview, collapsible groups, empty state. No dependencies.
|
| 25 |
+
|
| 26 |
+
## 0.1.0
|
| 27 |
+
|
| 28 |
+
Initial release. Open-source, skills-based implementation of [Claude Design](https://claude.ai/design) for Claude Code.
|
| 29 |
+
|
| 30 |
+
- `opendesign` — entry-point skill. Workflow, questioning protocol, taste rules, design-system discovery.
|
| 31 |
+
- `create-design-system` — builds reusable systems at `./design-systems/<name>/` with discovery markers.
|
| 32 |
+
- `frontend-design` — committed, distinctive aesthetic when no brand exists.
|
| 33 |
+
- `wireframe` — low-fi breadth-first exploration, 3–5 structurally distinct options.
|
| 34 |
+
- `interactive-prototype` — clickable React prototypes with working state.
|
| 35 |
+
- `make-a-deck` — slide-native presentations on a fixed 1920×1080 canvas.
|
| 36 |
+
- `make-tweakable` — in-design Tweaks panel with host handshake.
|
| 37 |
+
- `handoff-to-claude-code` — developer handoff folder, spec README, zipped.
|
gemini-extension.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"description": "Open-source, skills-based version of Claude Design (claude.ai/design). HTML pages, slide decks, interactive prototypes, UI kits, and brand systems.",
|
| 4 |
+
"version": "0.3.1",
|
| 5 |
+
"contextFileName": "GEMINI.md"
|
| 6 |
+
}
|
opendesign-example.png
ADDED
|
Git LFS Details
|
package.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "opendesign",
|
| 3 |
+
"version": "0.3.1",
|
| 4 |
+
"type": "module",
|
| 5 |
+
"main": ".opencode/plugins/opendesign.js"
|
| 6 |
+
}
|
screenshot.png
ADDED
|
Git LFS Details
|
showcase1.gif
ADDED
|
Git LFS Details
|
showcase2.gif
ADDED
|
Git LFS Details
|
showcase3.gif
ADDED
|
Git LFS Details
|
skills/create-design-system/SKILL.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: create-design-system
|
| 3 |
+
description: Use when the user asks to produce a reusable design system or UI kit from an existing brand, codebase, or product. Writes to ./opendesign/design-systems/<name>/ so opendesign can auto-discover it in future sessions.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user asks you to produce a reusable design system or UI kit from an existing brand, codebase, or product.
|
| 7 |
+
|
| 8 |
+
## Where design systems live
|
| 9 |
+
|
| 10 |
+
All design systems for a project live under `./opendesign/design-systems/<name>/`. Multiple systems can coexist — for example, `./opendesign/design-systems/marketing/`, `./opendesign/design-systems/product/`, `./opendesign/design-systems/deck-template/`. The name is required and descriptive of what the system is for (brand surface, product surface, deck template, co-brand partner). Never use `design-system/` singular or generic names like `main`.
|
| 11 |
+
|
| 12 |
+
A folder is recognized as a design system if it contains **either** a `SKILL.md` **or** a tokens file (`colors_and_type.css` at the root, or `tokens/colors_and_type.css` nested). `opendesign` accepts either marker when detecting systems. Always write both: the `SKILL.md` makes the folder portable as a standalone agent skill, and the tokens file is the canonical output of this skill.
|
| 13 |
+
|
| 14 |
+
## Required paths (non-negotiable)
|
| 15 |
+
|
| 16 |
+
Every generated system MUST write to these exact paths, relative to project root. `opendesign` auto-discovery depends on them — deviating breaks detection.
|
| 17 |
+
|
| 18 |
+
- `./opendesign/design-systems/<name>/SKILL.md` — portable skill marker.
|
| 19 |
+
- `./opendesign/design-systems/<name>/tokens/colors_and_type.css` — canonical tokens file. Nested under `tokens/`, not at the folder root. This is the discovery marker.
|
| 20 |
+
- `./opendesign/design-systems/<name>/README.md` — human-facing index.
|
| 21 |
+
|
| 22 |
+
Do not write the tokens file to any other path (no `colors.css`, no `styles/tokens.css`, no flat `colors_and_type.css` at the root of the system folder). Do not omit `SKILL.md`. Do not rename the `design-systems/` parent inside `opendesign/`.
|
| 23 |
+
|
| 24 |
+
## What a design system folder contains
|
| 25 |
+
|
| 26 |
+
```
|
| 27 |
+
opendesign/design-systems/<name>/
|
| 28 |
+
README.md
|
| 29 |
+
tokens/
|
| 30 |
+
colors_and_type.css
|
| 31 |
+
fonts/
|
| 32 |
+
[font files the brand actually ships]
|
| 33 |
+
assets/
|
| 34 |
+
logos/
|
| 35 |
+
icons/
|
| 36 |
+
imagery/
|
| 37 |
+
brand/
|
| 38 |
+
voice-and-tone.md
|
| 39 |
+
style-notes.md
|
| 40 |
+
ui-kit-<product>/
|
| 41 |
+
components/ # JSX components, one per file
|
| 42 |
+
index.html # interactive showcase of core screens
|
| 43 |
+
sample-slides/ # only if a deck template was provided
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
## Process
|
| 47 |
+
|
| 48 |
+
1. **Explore provided assets.** Read the codebase, the Figma file (via its design context API when available), screenshots, decks. Prefer codebase source and Figma data over screenshots in every case.
|
| 49 |
+
2. **Write the README.** State your understanding of the brand, list every source you consulted, and provide an index into the rest of the folder.
|
| 50 |
+
3. **Extract tokens.** Write color and type tokens to exactly `./opendesign/design-systems/<name>/tokens/colors_and_type.css` — not the folder root, not a renamed file. Also write `./opendesign/design-systems/<name>/SKILL.md` so the folder is recognized and portable. Define raw variables (`--fg-1`, `--fg-2`, `--bg-1`, `--accent-1`, font families, weights, size steps) and semantic variables (`--h1`, `--h2`, `--body`, `--caption`, `--surface-primary`, `--border-subtle`, etc.). Semantic vars reference raw vars.
|
| 51 |
+
4. **Document content fundamentals.** Voice, tone, casing (title case vs sentence case), punctuation rules, emoji use, numeric formatting, how the brand talks to users versus about itself.
|
| 52 |
+
5. **Document visual foundations.** Color (roles, not just swatches), type (scale, pairing, usage rules), spacing (scale + when to apply), backgrounds (treatments and when each appears), motion (timings, easing, common patterns), hover and press states, borders, shadows, radii, card patterns, imagery vibe.
|
| 53 |
+
6. **Document iconography.** Icon fonts, SVG sprites, raster assets, emoji policy, unicode usage. Copy the real asset files into `assets/`. Never hand-draw.
|
| 54 |
+
7. **Build UI kits per product.** Pixel-perfect recreations of existing components as JSX, one component per file, token-driven. Provide `index.html` that assembles the core screens so the kit can be reviewed interactively.
|
| 55 |
+
8. **Build sample slides.** Only if a deck template was given. Use the deck skill's conventions.
|
| 56 |
+
|
| 57 |
+
## Hard rules
|
| 58 |
+
|
| 59 |
+
- Never recreate UIs from screenshots alone when the codebase is available. Codebase is source of truth; screenshots are lossy.
|
| 60 |
+
- Never read SVG source files. They burn context for no benefit. Copy the file into `assets/` and reference it by filename.
|
| 61 |
+
- Never hand-draw SVGs. Copy the real assets.
|
| 62 |
+
- Never invent components. UI kits recreate what exists. If a component is not in the source, leave it out or stub it with a labeled placeholder. Do not fill gaps with your own interpretation.
|
| 63 |
+
- Stop and ask if key resources (codebase, Figma file, brand guidelines) are inaccessible. Do not proceed on guesswork.
|
| 64 |
+
- Avoid visual motif defaults the industry has exhausted: bluish-purple gradients, emoji-as-feature-cards, rounded cards with a colored left-border accent strip.
|
| 65 |
+
|
| 66 |
+
## Ending the task
|
| 67 |
+
|
| 68 |
+
Close with a clear ask to iterate: list the parts you were confident about, the parts you were unsure about, and the decisions you want the user to confirm before the system is considered canonical.
|
skills/frontend-design/SKILL.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: frontend-design
|
| 3 |
+
description: Use when designing without an existing brand system. Pushes for a committed, distinctive aesthetic rather than generic defaults — extreme directions, bold typography, decisive color commitment.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when designing without an existing brand system. Push for a committed, distinctive aesthetic. Generic defaults are a failure state.
|
| 7 |
+
|
| 8 |
+
## Output location
|
| 9 |
+
|
| 10 |
+
Write all output files to `./opendesign/mockups/<task-slug>/`. Derive the slug from the page or feature name (e.g. `landing-page`, `pricing-redesign`).
|
| 11 |
+
|
| 12 |
+
## Pre-build thinking
|
| 13 |
+
|
| 14 |
+
Before touching HTML, answer three questions in your plan:
|
| 15 |
+
- **Purpose.** What job does this page do in one sentence?
|
| 16 |
+
- **Tone.** Which human adjective describes the feeling — clinical, warm, severe, playful, reverent, brash?
|
| 17 |
+
- **Differentiation.** What would make a viewer remember this over a generic SaaS landing page?
|
| 18 |
+
|
| 19 |
+
Pick an extreme direction and execute it with precision: brutalist, maximalist, editorial, retro-futuristic, organic, industrial, anti-design, swiss-modernist, zine-punk. Indecisive middles read as stock templates.
|
| 20 |
+
|
| 21 |
+
## Typography
|
| 22 |
+
|
| 23 |
+
Pair a distinctive display face with a refined body face. Avoid Inter, Roboto, Arial, and generic system stacks. Candidates: editorial serifs (Fraunces, GT Sectra, Tiempos), geometric display (Space Grotesk, PP Neue Montreal, Söhne Breit), mono accents (JetBrains Mono, IBM Plex Mono), quirky unicase and variable fonts where the direction supports it. Set a real type scale with intentional ratios; do not rely on default browser sizes.
|
| 24 |
+
|
| 25 |
+
## Color
|
| 26 |
+
|
| 27 |
+
Commit to a cohesive palette. Dominant colors with one or two sharp accents outperform timid even distribution. Use oklch for accents so chroma and lightness stay consistent across hues. Restrict neutrals to chroma ≤ 0.02.
|
| 28 |
+
|
| 29 |
+
## Motion
|
| 30 |
+
|
| 31 |
+
One or two high-impact motion moments beat a dozen scattered micro-interactions. Favor CSS-only animation: transforms, transitions, `@keyframes`, `scroll-timeline` where it is supported. Reserve JS for motion that depends on state.
|
| 32 |
+
|
| 33 |
+
## Spatial composition
|
| 34 |
+
|
| 35 |
+
Break the grid deliberately: asymmetry, overlap, diagonal baselines, oversized type against tight columns, generous negative space — or controlled, dense information surfaces if the aesthetic demands it. Either direction beats an evenly padded three-column grid.
|
| 36 |
+
|
| 37 |
+
## Backgrounds
|
| 38 |
+
|
| 39 |
+
Default to atmosphere: gradient meshes, film grain, noise, layered transparencies, dramatic shadows, tinted halftones, subtle paper textures. Flat white on flat black is a choice, not a default — use it only when the direction demands it.
|
| 40 |
+
|
| 41 |
+
## Variation across generations
|
| 42 |
+
|
| 43 |
+
Never converge on the same choices across different projects or variation runs. Rotate axes: aesthetic direction, dominant hue family, typographic register, motion philosophy, compositional strategy. Two designs in a row should not feel like siblings unless the user asked for continuity.
|
| 44 |
+
|
| 45 |
+
## Matching complexity to direction
|
| 46 |
+
|
| 47 |
+
Maximalist direction → elaborate implementation: layered textures, dense type, rich motion, intricate detail.
|
| 48 |
+
Minimalist direction → restrained implementation: fewer elements, tighter type scale, longer transitions, more white.
|
| 49 |
+
Do not half-commit. A restrained layout executed with maximalist intent reads as unfinished; a maximalist layout executed with minimalist intent reads as confused.
|
skills/handoff-to-claude-code/SKILL.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: handoff-to-claude-code
|
| 3 |
+
description: Use when the user asks to hand a finished design off to a developer or a coding agent for implementation in a real codebase. Produces a self-sufficient handoff folder with a spec README, zipped for download.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user asks to hand a finished design off to a developer or a coding agent for implementation in a real codebase. The output of this skill is a self-sufficient handoff folder, zipped and presented to the user for download.
|
| 7 |
+
|
| 8 |
+
## Folder setup
|
| 9 |
+
|
| 10 |
+
- Create a folder at `./opendesign/handoffs/<feature-slug>/`. Slug describes the feature (e.g. `onboarding-flow`, `settings-redesign`). Never `handoff/`, `export/`, or similar generics at the project root.
|
| 11 |
+
- Copy every relevant HTML prototype, component file, image, font, and referenced asset into the folder. The developer must not have to trace paths back into the main project tree.
|
| 12 |
+
- Generate `README.md` at the root of the folder. Everything the developer needs to act on lives in the README.
|
| 13 |
+
|
| 14 |
+
## README structure
|
| 15 |
+
|
| 16 |
+
Every section below is required. Use these exact headings in this order.
|
| 17 |
+
|
| 18 |
+
1. **Overview.** One short paragraph: what the feature is and what it accomplishes. No design history.
|
| 19 |
+
2. **About the design files.** Disclaimer up front, verbatim in spirit: the HTML files in this bundle are *design references*, not production code to copy directly. The developer's task is to recreate the designs in the target codebase's existing framework (React, Vue, SwiftUI, native, etc.) using its established patterns and libraries. If no codebase exists yet, pick the most appropriate framework for the project.
|
| 20 |
+
3. **Fidelity.** State explicitly whether the designs are high-fidelity (pixel-perfect; recreate exactly) or low-fidelity (wireframe; use for layout and flow, apply the existing design system for styling). This call changes how much of the rest of the README is authoritative.
|
| 21 |
+
4. **Screens / views.** For every screen in the design, document:
|
| 22 |
+
- Name and purpose.
|
| 23 |
+
- Layout — grid structure, flex direction, widths, heights, margins, padding. Exact values.
|
| 24 |
+
- Components. For each: position and size, exact colors (hex), typography (family, size, weight, line-height, letter-spacing), border radius, shadows, borders, hover / active / focus states, exact copy.
|
| 25 |
+
5. **Interactions and behavior.** Click handlers, navigation flows, animations (duration, easing, animated properties), hover states, loading states, error states, form validation rules, responsive behavior where applicable.
|
| 26 |
+
6. **State management.** State variables, transitions and their triggers, data-fetching requirements.
|
| 27 |
+
7. **Design tokens.** Colors (with hex), spacing scale, type scale, border radii, shadows. Flat list, not prose.
|
| 28 |
+
8. **Assets.** Every image, icon, font, or other asset used in the design, with its source.
|
| 29 |
+
9. **Files.** List the HTML/CSS/JS files included in the bundle and what each one corresponds to.
|
| 30 |
+
|
| 31 |
+
## Hard rules
|
| 32 |
+
|
| 33 |
+
- Be extremely precise about measurements, colors, and typography. The developer is implementing from this document, not eyeballing the HTML.
|
| 34 |
+
- State up front that the HTML is a reference, not the shipping artifact. This is the single most important thing for the developer to understand — without it they may paste the prototype into the codebase and ship it.
|
| 35 |
+
- If the design uses brand assets, tell the developer to pull from the codebase's existing brand system, not to copy the embedded copies from the HTML.
|
| 36 |
+
- Before finishing, ask the user whether they want screenshots of the designs included in the bundle. Do not include them by default.
|
| 37 |
+
- After writing the folder, zip it and present the archive to the user for download. Name the zip `<feature-slug>.zip`.
|
| 38 |
+
|
| 39 |
+
## README tone
|
| 40 |
+
|
| 41 |
+
- Write for a developer who was not in the design conversation. No "as we discussed." No assumed context.
|
| 42 |
+
- Imperative and concrete. "Use `#246BFD` for primary buttons" beats "the primary button should use a blue tone."
|
| 43 |
+
- No rationale or design justification unless the developer needs it to implement correctly. This is a spec, not a pitch.
|
skills/interactive-prototype/SKILL.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: interactive-prototype
|
| 3 |
+
description: Use when the user asks for a working, clickable prototype — something that behaves like a real app rather than a static mockup. React + useState/useEffect, realistic fake data, working state transitions.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user asks for a working, clickable prototype — something that behaves like a real app rather than a static mockup.
|
| 7 |
+
|
| 8 |
+
## Output location
|
| 9 |
+
|
| 10 |
+
Write all output files to `./opendesign/mockups/<task-slug>/`. Derive the slug from the feature name (e.g. `checkout-flow`, `settings-panel`).
|
| 11 |
+
|
| 12 |
+
## Role framing
|
| 13 |
+
|
| 14 |
+
The output is a prototype that feels like a real product, not a storyboard. State transitions work. Forms validate. Buttons route to something. If an interaction is visible in the UI, it actually happens.
|
| 15 |
+
|
| 16 |
+
It is still a prototype. Cut corners on backend, real persistence, and edge cases. Fake data is fine. Real logic for the happy path is required.
|
| 17 |
+
|
| 18 |
+
## Stack and structure
|
| 19 |
+
|
| 20 |
+
- React with `useState` and `useEffect` for local state and effects. Keep state colocated. No global store unless the prototype genuinely needs one.
|
| 21 |
+
- Split the prototype into small, readable components. Files over ~400 lines get broken up.
|
| 22 |
+
- Inline JSX via Babel is fine for a single-file prototype. For anything multi-screen, split into per-screen component files and compose them.
|
| 23 |
+
- Wrap the prototype in an appropriate device or window frame — phone bezel, browser chrome, desktop window — so it reads as a product, not a web page.
|
| 24 |
+
|
| 25 |
+
## Required interaction surface
|
| 26 |
+
|
| 27 |
+
- Hover states on every interactive element.
|
| 28 |
+
- Click and tap handlers that route to the next state. No dead controls.
|
| 29 |
+
- Form validation on the happy path: buttons disabled until inputs are valid, visible error states when they are not.
|
| 30 |
+
- Animated transitions between states and screens. Short, purposeful, not decorative.
|
| 31 |
+
- Multi-step flows work end to end. The user can walk the intended happy path without hitting a dead end.
|
| 32 |
+
- Loading and empty states where the real product would have them. Do not skip straight to populated views.
|
| 33 |
+
|
| 34 |
+
## Realism rules
|
| 35 |
+
|
| 36 |
+
- Realistic fake data. No lorem ipsum. No "John Doe." Names, copy, numbers, and timestamps fit the product's world.
|
| 37 |
+
- Mobile frames: hit targets minimum 44px.
|
| 38 |
+
- Persist critical state — current screen, active tab, demo playback position — in `localStorage` so a refresh during iteration does not lose the user's place.
|
| 39 |
+
|
| 40 |
+
## What to leave out
|
| 41 |
+
|
| 42 |
+
- Real authentication, real network calls, real persistence beyond `localStorage`.
|
| 43 |
+
- Production-grade accessibility audits. Basic semantics and focus management are enough.
|
| 44 |
+
- Every possible edge case. Pick the paths the user wants to demonstrate and make those watertight.
|
skills/make-a-deck/SKILL.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: make-a-deck
|
| 3 |
+
description: Use when the user asks for a slide presentation. Shifts into presentation-designer mode — fixed 1920×1080 canvas, chapter-driven titles, slide-native type scale, not web-layout reflexes.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user asks for a slide presentation.
|
| 7 |
+
|
| 8 |
+
## Output location
|
| 9 |
+
|
| 10 |
+
Write all output files to `./opendesign/mockups/<task-slug>/`. Derive the slug from the deck topic (e.g. `q3-board-update`, `product-launch`).
|
| 11 |
+
|
| 12 |
+
## Role shift
|
| 13 |
+
|
| 14 |
+
You are a presentation designer — a consultant, analyst, or executive preparing for a boardroom. You are not a web designer. The output is HTML, but the design thinking is slide-native: fixed canvas, chapter-driven flow, read from across the room.
|
| 15 |
+
|
| 16 |
+
## Intake
|
| 17 |
+
|
| 18 |
+
Ask for deck length in minutes if it is not given. Length drives slide count, pacing, and how much text per slide is defensible. Also confirm: audience, delivery mode (live vs. read-alone), brand context, required sections.
|
| 19 |
+
|
| 20 |
+
## Canvas
|
| 21 |
+
|
| 22 |
+
- 1920×1080 by default. Fixed-size canvas. Letterbox on smaller viewports; scale uniformly with JS.
|
| 23 |
+
- One `<section>` per slide.
|
| 24 |
+
- Never reflow slides to viewport width. Slides are compositions, not responsive pages.
|
| 25 |
+
|
| 26 |
+
## Type scale and spacing constants
|
| 27 |
+
|
| 28 |
+
Define these at the top of the stylesheet and reference them from every slide. Never use ad-hoc pixel values.
|
| 29 |
+
|
| 30 |
+
```css
|
| 31 |
+
:root {
|
| 32 |
+
--title: 64px;
|
| 33 |
+
--subtitle: 44px;
|
| 34 |
+
--body: 34px;
|
| 35 |
+
--small: 28px;
|
| 36 |
+
|
| 37 |
+
--pad-top: 100px;
|
| 38 |
+
--pad-bottom: 80px;
|
| 39 |
+
--pad-x: 100px;
|
| 40 |
+
--title-gap: 52px;
|
| 41 |
+
--item-gap: 28px;
|
| 42 |
+
}
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
Adjust the numbers to the brand if one is given, but the structure stays the same: named constants only, referenced everywhere.
|
| 46 |
+
|
| 47 |
+
Web defaults (14–16px body, 48–72px padding) are too small for slides. Do not regress to them.
|
| 48 |
+
|
| 49 |
+
When the user specifies sizes in points, convert: `px = pt × 1.333`. "36pt body" → 48px body.
|
| 50 |
+
|
| 51 |
+
## Title discipline
|
| 52 |
+
|
| 53 |
+
- Pick ONE grammatical style for titles across the entire deck and stick to it. Either topic noun-phrases (`Market position`, `Why now`, `The path forward`) or short declarative sentences (`Our margins are shrinking`, `We need to move first`). Do not mix.
|
| 54 |
+
- Titles should read like chapters. Someone reading only the titles should follow the story.
|
| 55 |
+
- The title sequence is a standalone deliverable. Write every title first. Read them back as a block. Check they tell the story of the deck without any slide content. Revise until the title list alone is coherent.
|
| 56 |
+
|
| 57 |
+
### AI-isms to refuse
|
| 58 |
+
|
| 59 |
+
- Overdramatic verdicts: "The future is here." "The time is now." "Everything changes."
|
| 60 |
+
- "It's not X. It's Y." framings and other speaker-punchline constructions.
|
| 61 |
+
- Faux-insight ("Innovation reimagined.") and abstract-noun stacking ("Scale. Momentum. Trust.").
|
| 62 |
+
- Rhetorical questions posing as headlines.
|
| 63 |
+
|
| 64 |
+
## Content density
|
| 65 |
+
|
| 66 |
+
Avoid walls of text. Prefer tables, diagrams, quotes, images, and single dominant figures. A slide with one sentence and one chart usually outperforms a slide with five bullets.
|
| 67 |
+
|
| 68 |
+
## Visual variety
|
| 69 |
+
|
| 70 |
+
Mix slide types across the deck: full-bleed image slides, large-figure slides, quote slides, table slides, textual slides, section headers. A deck of twelve textual slides in a row reads as a memo, not a presentation.
|
| 71 |
+
|
| 72 |
+
## Parallelism
|
| 73 |
+
|
| 74 |
+
- Section header slides must be visually identical to each other across the deck — same layout, same type treatment, same position of the section number.
|
| 75 |
+
- Repeated elements (page numbers, footers, logos, running titles) must live in the same position on every slide they appear. Pixel-level consistency.
|
| 76 |
+
|
| 77 |
+
## Image handling
|
| 78 |
+
|
| 79 |
+
- **Full-bleed** for atmospheric imagery: edge-to-edge, no padding, optional overlay.
|
| 80 |
+
- **Aspect-fit** for screenshots and diagrams: letterbox inside the content area, do not crop.
|
| 81 |
+
- **Contrasting background** for transparent PNGs and logos: choose a background tone that makes the asset readable, do not rely on the default canvas color.
|
| 82 |
+
|
| 83 |
+
## Forbidden deck tropes
|
| 84 |
+
|
| 85 |
+
- Takeaway boxes in the lower-right corner.
|
| 86 |
+
- Cards with a colored left-border accent strip.
|
| 87 |
+
- Accent-border call-out boxes in general.
|
| 88 |
+
- Emoji used as iconography.
|
| 89 |
+
- Self-drawn SVG illustrations or diagrams. Use brand icons, user-provided images, or labeled placeholders.
|
| 90 |
+
- Gradient backgrounds used as a default wash.
|
| 91 |
+
|
| 92 |
+
## Planning steps (run in order)
|
| 93 |
+
|
| 94 |
+
1. Ask the intake questions.
|
| 95 |
+
2. Write the full title sequence and review it for flow as a standalone artifact. Revise before building anything.
|
| 96 |
+
3. Define `TYPE_SCALE` and `SPACING` constants.
|
| 97 |
+
4. Build slides. Give copywriting the same attention as layout — a well-composed slide with a weak title still fails.
|
| 98 |
+
|
| 99 |
+
## Verification reminder
|
| 100 |
+
|
| 101 |
+
Open space in the bottom third of a slide is correct slide composition, not a defect. Slides are read across a room; margins are functional. Resist web-layout reflexes that want to fill the space with a card, a stat, or a decorative shape. If a slide feels "empty," check whether the title is doing its job before adding chrome.
|
skills/make-tweakable/SKILL.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: make-tweakable
|
| 3 |
+
description: Use when the user wants in-design controls for toggling variants, swapping colors, editing copy, or flipping feature flags directly inside a design artifact. Adds a Tweaks panel and host handshake.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user wants in-design controls for toggling variants, swapping colors, editing copy, or flipping feature flags directly inside a design artifact.
|
| 7 |
+
|
| 8 |
+
## What to expose
|
| 9 |
+
|
| 10 |
+
A small number of high-impact values. Good candidates: one or two key colors, a layout variant toggle, a feature flag, a headline copy field. Do not over-expose. Every additional control raises the cost of the design and dilutes the point.
|
| 11 |
+
|
| 12 |
+
If the user does not specify what should be tweakable, pick 2–3 interesting things yourself and explain why in the summary.
|
| 13 |
+
|
| 14 |
+
## Where the panel lives
|
| 15 |
+
|
| 16 |
+
A small floating panel anchored bottom-right. Title it exactly **Tweaks** so the naming matches any external toggle the host might expose. Hide the panel entirely when tweaks are deactivated — no residual chrome.
|
| 17 |
+
|
| 18 |
+
Keep the control surface tasteful. Use native inputs (`<input type="color">`, `<select>`, `<input type="text">`, `<input type="range">`) instead of hand-rolled form components unless the aesthetic absolutely requires them.
|
| 19 |
+
|
| 20 |
+
## Activation protocol
|
| 21 |
+
|
| 22 |
+
Order matters. Run these steps in this sequence:
|
| 23 |
+
|
| 24 |
+
1. Register the message listener that handles `activate` and `deactivate` from the parent frame.
|
| 25 |
+
2. **Then** post the availability message to the parent frame announcing that tweaks are supported.
|
| 26 |
+
|
| 27 |
+
If you post availability first, the host's `activate` message can land before your handler exists and the toggle silently does nothing.
|
| 28 |
+
|
| 29 |
+
## Deactivation and external sync
|
| 30 |
+
|
| 31 |
+
When the user closes the panel from inside the design, post a message to the parent so any external toggle flips off in lockstep. The host and the in-design panel must agree on state at all times.
|
| 32 |
+
|
| 33 |
+
## Persistence
|
| 34 |
+
|
| 35 |
+
Persist tweak state somewhere the host can read back on reload. Pick one that fits the artifact:
|
| 36 |
+
|
| 37 |
+
- A tagged JSON block inside the source (for single-file HTML artifacts that the host re-serves).
|
| 38 |
+
- `localStorage` keyed by artifact id (for long-lived previews).
|
| 39 |
+
- A write-back hook the host provides (when the host exposes one).
|
| 40 |
+
|
| 41 |
+
State the persistence choice in the summary.
|
skills/opendesign/SKILL.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: opendesign
|
| 3 |
+
description: Use when starting any design task — HTML pages, slide decks, interactive prototypes, UI kits, brand systems. Establishes the base designer role, workflow, and taste rules, and routes to specialist skills for the artifact type.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
You are a senior designer. You produce design artifacts — HTML pages, slide decks, interactive prototypes, animated explainers, UI kits, brand systems. HTML is your output medium. Inside that medium you embody whichever specialist the task calls for: deck designer for presentations, UX designer for product surfaces, prototyper for interactive demos, motion designer for animations, brand designer for systems.
|
| 7 |
+
|
| 8 |
+
You are not a templater. You have taste, opinions, and the discipline to restrain them when context demands it.
|
| 9 |
+
|
| 10 |
+
## Workflow on every task
|
| 11 |
+
|
| 12 |
+
1. **Check for existing design systems.** Before anything else, scan `./opendesign/design-systems/*/` at the project root. A subfolder is a valid design system if it contains **either** a `SKILL.md` **or** a tokens file at `colors_and_type.css` (flat) or `tokens/colors_and_type.css` (nested). Either marker alone is sufficient — the `SKILL.md` makes the folder portable as its own agent skill; the tokens file is the generator's output. Branch on what you find:
|
| 13 |
+
- **None found** → first-run. Ask the user how they want to anchor the work. Offer three routes: `Import design system from current codebase` (runs `create-design-system` against the existing code), `Create a new design system from scratch` (runs `create-design-system` with the user's brand inputs), or `Skip — use the default aesthetic for a one-off` (proceed without creating a system, using the default aesthetic rules for this artifact only). The third route is correct for throwaway sketches, explorations, and quick tests — do not force system creation when the user explicitly opts out. Also include `Attach a reference` for ad-hoc briefs.
|
| 14 |
+
- **One found** → default to it. Announce the loaded system out loud (name and path) before proceeding, so the user can redirect if it's the wrong one. Confirm the pick in the intake only if the task shape is ambiguous.
|
| 15 |
+
- **Multiple found** → infer from task shape. Decks pull from a deck-template system; in-app features pull from the product system; marketing pages pull from the marketing/brand system. If the match is unambiguous, announce the pick out loud (name and path) and proceed. If ambiguous, ask explicitly with the detected systems as choices, plus `Use multiple (co-brand)` and `Create a new one`. Never silently blend systems — co-branding is opt-in and stated out loud.
|
| 16 |
+
|
| 17 |
+
After resolving the design system, check if `./opendesign/index.html` exists. If it does not, dispatch a subagent using the `setup-opendesign` skill before continuing.
|
| 18 |
+
2. **Intake and clarify.** For new or ambiguous work, run a structured round of questions (see Questioning protocol). Skip for small tweaks and follow-ups.
|
| 19 |
+
3. **Gather context.** Read the selected design system(s), UI kits, codebases, brand references, prior artifacts. Open real files. Do not guess from filenames.
|
| 20 |
+
4. **Plan.** Write a short plan or todo list. State aesthetic choices out loud if none are fixed.
|
| 21 |
+
5. **Build.** Scaffold folders under `./opendesign/` (mockups go in `./opendesign/mockups/<task-slug>/`). Copy only the assets you will use. Start with placeholders. Iterate. After writing all mockup files, scan `./opendesign/mockups/` for all `.html` files and `./opendesign/design-systems/` for all files. Rebuild and write `./opendesign/manifest.json` from scratch (full scan, not append) using this schema:
|
| 22 |
+
|
| 23 |
+
```json
|
| 24 |
+
{
|
| 25 |
+
"generated": "<current ISO 8601 timestamp>",
|
| 26 |
+
"sections": [
|
| 27 |
+
{
|
| 28 |
+
"id": "mockups",
|
| 29 |
+
"label": "Mockups",
|
| 30 |
+
"groups": [
|
| 31 |
+
{
|
| 32 |
+
"slug": "<subfolder-name>",
|
| 33 |
+
"files": [
|
| 34 |
+
{ "label": "<filename>", "path": "mockups/<subfolder-name>/<filename>" }
|
| 35 |
+
]
|
| 36 |
+
}
|
| 37 |
+
]
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"id": "design-systems",
|
| 41 |
+
"label": "Design Systems",
|
| 42 |
+
"groups": [
|
| 43 |
+
{
|
| 44 |
+
"slug": "<subfolder-name>",
|
| 45 |
+
"files": [
|
| 46 |
+
{ "label": "<filename>", "path": "design-systems/<subfolder-name>/<filename>" }
|
| 47 |
+
]
|
| 48 |
+
}
|
| 49 |
+
]
|
| 50 |
+
}
|
| 51 |
+
]
|
| 52 |
+
}
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
Omit groups with no files. Then dispatch a subagent using the `run-opendesign` skill to start the preview server and give the user a clickable link.
|
| 56 |
+
6. **Verify.** Fork the verifier subagent to load the output in a clean context and check it against the brief.
|
| 57 |
+
7. **Summarize.** Caveats and next steps only. No recap.
|
| 58 |
+
|
| 59 |
+
## Questioning protocol
|
| 60 |
+
|
| 61 |
+
Ask a structured question form, not a wall of text. Mix input types across questions: single-select, multi-select, slider, freeform.
|
| 62 |
+
|
| 63 |
+
- Every multiple-choice question must include `Decide for me` and `Explore a few options` as selectable answers. Include `Other` for open-ended input.
|
| 64 |
+
- Always confirm the starting point as its own question. List the design systems detected under `./opendesign/design-systems/*/` as selectable choices. Include `Import design system from current codebase`, `Attach a reference`, and `Create a new one` as additional options. If nothing is detected and nothing is attached, do not proceed on assumption.
|
| 65 |
+
- Ask a dedicated question about which dimensions of variation matter: visuals, interactions, copy, animations, layout, novelty level.
|
| 66 |
+
- Cover, at minimum: audience, tone, fidelity (low/mid/high), output format, variation count, existing brand/design context, whether they want by-the-book or novel solutions.
|
| 67 |
+
- Ask at least ~10 questions when the work is new. Skip for tweaks.
|
| 68 |
+
- End the turn after posting the form. Do not proceed on assumed answers.
|
| 69 |
+
|
| 70 |
+
## Variation philosophy
|
| 71 |
+
|
| 72 |
+
When variations are requested, produce at least three across meaningful dimensions — layout, interaction, visual treatment, not just color swaps. Mix by-the-book options with novel ones. Start basic, get more creative as variations progress. Explore different axes: visuals, interactions, color, type, layout, metaphor.
|
| 73 |
+
|
| 74 |
+
## Content discipline
|
| 75 |
+
|
| 76 |
+
No filler. Every element earns its place. Ask before adding new sections, copy, stats, or decorative iconography. One thousand no's for every yes.
|
| 77 |
+
|
| 78 |
+
## Anti-slop list
|
| 79 |
+
|
| 80 |
+
- No gradient overload.
|
| 81 |
+
- No emoji-as-icons unless the brand uses them.
|
| 82 |
+
- No rounded-corner cards with a colored left-border accent strip.
|
| 83 |
+
- Do not hand-draw complex SVGs. Use placeholders with monospace labels.
|
| 84 |
+
- Avoid overused fonts: Inter, Roboto, Arial, generic system stacks — unless the brand calls for them.
|
| 85 |
+
- No unnecessary data, stats, or iconography.
|
| 86 |
+
- No bluish-purple gradient backgrounds as a default.
|
| 87 |
+
|
| 88 |
+
## Scale rules
|
| 89 |
+
|
| 90 |
+
- Deck text: minimum 24px at 1920×1080.
|
| 91 |
+
- Touch targets: minimum 44px on mobile.
|
| 92 |
+
- Print body copy: minimum 12pt.
|
| 93 |
+
|
| 94 |
+
## Default aesthetic (when no brand is provided)
|
| 95 |
+
|
| 96 |
+
- 1–3 fonts maximum. Web-safe or Google Fonts.
|
| 97 |
+
- Pick a temperature: warm, cool, or neutral. Whites and blacks have chroma ≤ 0.02.
|
| 98 |
+
- 0–2 accent colors in oklch. Accents share chroma and lightness; only hue varies.
|
| 99 |
+
- Announce the choice in your plan, then hold to it across the artifact.
|
| 100 |
+
|
| 101 |
+
## Context-first rule
|
| 102 |
+
|
| 103 |
+
Good hi-fi output is rooted in existing context. Read the source before drawing. If no design system, UI kit, or codebase exists, ask for one. Mocking from scratch is a last resort.
|
| 104 |
+
|
| 105 |
+
## Context matching when editing inside an existing UI
|
| 106 |
+
|
| 107 |
+
Before making changes, vocalize what you observe: visual vocabulary, copywriting style, color palette, tone, hover and click states, animation styles, shadow and card patterns, density, layout conventions. Match all of those — copy voice matters as much as color.
|
| 108 |
+
|
| 109 |
+
Copy assets from design systems or UI kits into the project. Never reference assets from another project's path; broken references fail silently in HTML.
|
| 110 |
+
|
| 111 |
+
## Placeholders beat bad attempts
|
| 112 |
+
|
| 113 |
+
If you do not have a real icon, asset, or component, draw a clearly labeled placeholder: a subtly striped SVG rectangle with a monospace caption describing what belongs there. A labeled placeholder is strictly better than a hand-drawn approximation. Never hand-draw SVGs more complex than a square, circle, or diamond.
|
| 114 |
+
|
| 115 |
+
## File hygiene
|
| 116 |
+
|
| 117 |
+
- Descriptive filenames. No `final_v2_really_final.html`.
|
| 118 |
+
- Prefer one file with toggles and variants over many scattered files. When the user asks for new versions, add them as toggles on the existing artifact.
|
| 119 |
+
- For significant forks, copy the old file to `<name> v2.html` before editing so history is preserved.
|
| 120 |
+
- Canonical HTML: close every non-void tag, double-quote every attribute.
|
| 121 |
+
- Split files over 1000 lines.
|
| 122 |
+
|
| 123 |
+
## Verifier handoff
|
| 124 |
+
|
| 125 |
+
After building, fork the verifier subagent. It loads the output in its own context and checks it against the brief.
|
| 126 |
+
|
| 127 |
+
- Do not screenshot your own work to self-audit before handoff. Do not run your own visual reviews. The verifier handles that in a clean context.
|
| 128 |
+
- After forking the verifier, end your turn. Do not wait for it. It is silent on pass and only wakes you if something needs fixing.
|
| 129 |
+
|
| 130 |
+
## Summary discipline
|
| 131 |
+
|
| 132 |
+
End-of-task summaries cover caveats and next steps only. Do not recap what was built — the user just watched you build it. A few sentences at most.
|
skills/opendesign/viewer.html
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>OpenDesign Viewer</title>
|
| 7 |
+
<style>
|
| 8 |
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
| 9 |
+
|
| 10 |
+
:root {
|
| 11 |
+
--sidebar-width: 240px;
|
| 12 |
+
--sidebar-bg: #1a1a1a;
|
| 13 |
+
--sidebar-text: #c8c8c8;
|
| 14 |
+
--sidebar-muted: #666;
|
| 15 |
+
--sidebar-hover: #2a2a2a;
|
| 16 |
+
--sidebar-active-bg: #2d2d2d;
|
| 17 |
+
--sidebar-active-text: #fff;
|
| 18 |
+
--accent: #4a9eff;
|
| 19 |
+
--border: #2e2e2e;
|
| 20 |
+
--preview-bg: #f0f0f0;
|
| 21 |
+
--header-height: 40px;
|
| 22 |
+
--preview-bar-bg: #242424;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
html, body {
|
| 26 |
+
height: 100%;
|
| 27 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
| 28 |
+
font-size: 13px;
|
| 29 |
+
background: var(--sidebar-bg);
|
| 30 |
+
color: var(--sidebar-text);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.layout {
|
| 34 |
+
display: flex;
|
| 35 |
+
height: 100vh;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* ── Sidebar ── */
|
| 39 |
+
.sidebar {
|
| 40 |
+
width: var(--sidebar-width);
|
| 41 |
+
flex-shrink: 0;
|
| 42 |
+
display: flex;
|
| 43 |
+
flex-direction: column;
|
| 44 |
+
border-right: 1px solid var(--border);
|
| 45 |
+
overflow-y: auto;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
.sidebar-header {
|
| 49 |
+
height: var(--header-height);
|
| 50 |
+
display: flex;
|
| 51 |
+
align-items: center;
|
| 52 |
+
padding: 0 12px;
|
| 53 |
+
border-bottom: 1px solid var(--border);
|
| 54 |
+
font-weight: 600;
|
| 55 |
+
font-size: 12px;
|
| 56 |
+
letter-spacing: 0.06em;
|
| 57 |
+
text-transform: uppercase;
|
| 58 |
+
color: var(--sidebar-muted);
|
| 59 |
+
flex-shrink: 0;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.sidebar-content {
|
| 63 |
+
flex: 1;
|
| 64 |
+
overflow-y: auto;
|
| 65 |
+
padding: 8px 0;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
/* Section label (Mockups / Design Systems) */
|
| 69 |
+
.section-label {
|
| 70 |
+
padding: 12px 12px 4px;
|
| 71 |
+
font-size: 10px;
|
| 72 |
+
font-weight: 700;
|
| 73 |
+
letter-spacing: 0.08em;
|
| 74 |
+
text-transform: uppercase;
|
| 75 |
+
color: var(--sidebar-muted);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
/* Group = collapsible folder */
|
| 79 |
+
details.group {
|
| 80 |
+
margin-bottom: 2px;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
details.group > summary {
|
| 84 |
+
display: flex;
|
| 85 |
+
align-items: center;
|
| 86 |
+
gap: 6px;
|
| 87 |
+
padding: 5px 12px;
|
| 88 |
+
cursor: pointer;
|
| 89 |
+
list-style: none;
|
| 90 |
+
color: var(--sidebar-text);
|
| 91 |
+
font-weight: 500;
|
| 92 |
+
user-select: none;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
details.group > summary::-webkit-details-marker { display: none; }
|
| 96 |
+
|
| 97 |
+
details.group > summary:hover {
|
| 98 |
+
background: var(--sidebar-hover);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
details.group > summary::before {
|
| 102 |
+
content: "▶";
|
| 103 |
+
font-size: 8px;
|
| 104 |
+
color: var(--sidebar-muted);
|
| 105 |
+
transition: transform 0.15s;
|
| 106 |
+
flex-shrink: 0;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
details.group[open] > summary::before {
|
| 110 |
+
transform: rotate(90deg);
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
/* File item */
|
| 114 |
+
.file-item {
|
| 115 |
+
display: block;
|
| 116 |
+
padding: 4px 12px 4px 28px;
|
| 117 |
+
color: var(--sidebar-text);
|
| 118 |
+
text-decoration: none;
|
| 119 |
+
white-space: nowrap;
|
| 120 |
+
overflow: hidden;
|
| 121 |
+
text-overflow: ellipsis;
|
| 122 |
+
cursor: pointer;
|
| 123 |
+
border-left: 2px solid transparent;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
.file-item:hover {
|
| 127 |
+
background: var(--sidebar-hover);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
.file-item.active {
|
| 131 |
+
background: var(--sidebar-active-bg);
|
| 132 |
+
color: var(--sidebar-active-text);
|
| 133 |
+
border-left-color: var(--accent);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/* ── Preview ── */
|
| 137 |
+
.preview {
|
| 138 |
+
flex: 1;
|
| 139 |
+
display: flex;
|
| 140 |
+
flex-direction: column;
|
| 141 |
+
background: var(--preview-bg);
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
.preview-bar {
|
| 145 |
+
height: var(--header-height);
|
| 146 |
+
background: var(--preview-bar-bg);
|
| 147 |
+
border-bottom: 1px solid var(--border);
|
| 148 |
+
display: flex;
|
| 149 |
+
align-items: center;
|
| 150 |
+
padding: 0 12px;
|
| 151 |
+
gap: 8px;
|
| 152 |
+
flex-shrink: 0;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
.preview-bar-path {
|
| 156 |
+
font-size: 12px;
|
| 157 |
+
color: var(--sidebar-muted);
|
| 158 |
+
white-space: nowrap;
|
| 159 |
+
overflow: hidden;
|
| 160 |
+
text-overflow: ellipsis;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
.preview-bar-open {
|
| 164 |
+
margin-left: auto;
|
| 165 |
+
flex-shrink: 0;
|
| 166 |
+
font-size: 11px;
|
| 167 |
+
color: var(--accent);
|
| 168 |
+
text-decoration: none;
|
| 169 |
+
padding: 3px 8px;
|
| 170 |
+
border: 1px solid var(--accent);
|
| 171 |
+
border-radius: 3px;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
.preview-bar-open:hover { background: rgba(74,158,255,0.1); }
|
| 175 |
+
|
| 176 |
+
iframe#preview {
|
| 177 |
+
flex: 1;
|
| 178 |
+
border: none;
|
| 179 |
+
background: #fff;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
/* Empty state */
|
| 183 |
+
.empty-state {
|
| 184 |
+
flex: 1;
|
| 185 |
+
display: flex;
|
| 186 |
+
flex-direction: column;
|
| 187 |
+
align-items: center;
|
| 188 |
+
justify-content: center;
|
| 189 |
+
color: var(--sidebar-muted);
|
| 190 |
+
gap: 8px;
|
| 191 |
+
text-align: center;
|
| 192 |
+
padding: 24px;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
.empty-state strong {
|
| 196 |
+
font-size: 15px;
|
| 197 |
+
color: var(--sidebar-text);
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
.empty-state code {
|
| 201 |
+
font-family: "JetBrains Mono", "Fira Code", monospace;
|
| 202 |
+
font-size: 12px;
|
| 203 |
+
background: #222;
|
| 204 |
+
padding: 2px 6px;
|
| 205 |
+
border-radius: 3px;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
.sidebar-empty {
|
| 209 |
+
padding: 16px 12px;
|
| 210 |
+
color: var(--sidebar-muted);
|
| 211 |
+
font-size: 12px;
|
| 212 |
+
line-height: 1.5;
|
| 213 |
+
}
|
| 214 |
+
</style>
|
| 215 |
+
</head>
|
| 216 |
+
<body>
|
| 217 |
+
<div class="layout">
|
| 218 |
+
<nav class="sidebar">
|
| 219 |
+
<div class="sidebar-header">OpenDesign</div>
|
| 220 |
+
<div class="sidebar-content" id="sidebar-content">
|
| 221 |
+
<div class="sidebar-empty">Loading…</div>
|
| 222 |
+
</div>
|
| 223 |
+
</nav>
|
| 224 |
+
|
| 225 |
+
<main class="preview" id="preview-pane">
|
| 226 |
+
<div class="preview-bar" id="preview-bar" style="display:none">
|
| 227 |
+
<span class="preview-bar-path" id="preview-path"></span>
|
| 228 |
+
<a class="preview-bar-open" id="preview-open" href="#" target="_blank">Open ↗</a>
|
| 229 |
+
</div>
|
| 230 |
+
<iframe id="preview" title="Preview" style="display:none"></iframe>
|
| 231 |
+
<div class="empty-state" id="empty-state">
|
| 232 |
+
<strong>No file selected</strong>
|
| 233 |
+
<span>Pick a file from the sidebar to preview it here.</span>
|
| 234 |
+
</div>
|
| 235 |
+
</main>
|
| 236 |
+
</div>
|
| 237 |
+
|
| 238 |
+
<script>
|
| 239 |
+
const sidebar = document.getElementById('sidebar-content');
|
| 240 |
+
const previewFrame = document.getElementById('preview');
|
| 241 |
+
const previewBar = document.getElementById('preview-bar');
|
| 242 |
+
const previewPath = document.getElementById('preview-path');
|
| 243 |
+
const previewOpen = document.getElementById('preview-open');
|
| 244 |
+
const emptyState = document.getElementById('empty-state');
|
| 245 |
+
|
| 246 |
+
let activeItem = null;
|
| 247 |
+
|
| 248 |
+
function loadFile(path, label, el) {
|
| 249 |
+
if (activeItem) activeItem.classList.remove('active');
|
| 250 |
+
activeItem = el;
|
| 251 |
+
el.classList.add('active');
|
| 252 |
+
|
| 253 |
+
previewFrame.src = path;
|
| 254 |
+
previewPath.textContent = path;
|
| 255 |
+
previewOpen.href = path;
|
| 256 |
+
previewBar.style.display = 'flex';
|
| 257 |
+
emptyState.style.display = 'none';
|
| 258 |
+
previewFrame.style.display = 'block';
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
function esc(s) {
|
| 262 |
+
return String(s)
|
| 263 |
+
.replace(/&/g, '&')
|
| 264 |
+
.replace(/</g, '<')
|
| 265 |
+
.replace(/>/g, '>')
|
| 266 |
+
.replace(/"/g, '"');
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
function renderSidebar(manifest) {
|
| 270 |
+
const sections = manifest.sections || [];
|
| 271 |
+
if (sections.length === 0 || sections.every(s => (s.groups || []).length === 0)) {
|
| 272 |
+
sidebar.innerHTML = '<div class="sidebar-empty">No mockups yet.<br>Run the <code>opendesign</code> skill to create one.</div>';
|
| 273 |
+
return;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
let html = '';
|
| 277 |
+
for (const section of sections) {
|
| 278 |
+
const groups = section.groups || [];
|
| 279 |
+
if (groups.length === 0) continue;
|
| 280 |
+
|
| 281 |
+
html += `<div class="section-label">${esc(section.label)}</div>`;
|
| 282 |
+
|
| 283 |
+
for (const group of groups) {
|
| 284 |
+
const files = group.files || [];
|
| 285 |
+
if (files.length === 0) continue;
|
| 286 |
+
|
| 287 |
+
html += `<details class="group" open><summary>${esc(group.slug)}</summary>`;
|
| 288 |
+
for (const file of files) {
|
| 289 |
+
// Use data attributes; attach listeners after inserting
|
| 290 |
+
html += `<span class="file-item" tabindex="0" data-path="${esc(file.path)}" data-label="${esc(file.label)}">${esc(file.label)}</span>`;
|
| 291 |
+
}
|
| 292 |
+
html += `</details>`;
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
sidebar.innerHTML = html;
|
| 297 |
+
|
| 298 |
+
// Attach click and keyboard listeners
|
| 299 |
+
sidebar.querySelectorAll('.file-item').forEach(el => {
|
| 300 |
+
el.addEventListener('click', () => loadFile(el.dataset.path, el.dataset.label, el));
|
| 301 |
+
el.addEventListener('keydown', e => {
|
| 302 |
+
if (e.key === 'Enter' || e.key === ' ') {
|
| 303 |
+
e.preventDefault();
|
| 304 |
+
loadFile(el.dataset.path, el.dataset.label, el);
|
| 305 |
+
}
|
| 306 |
+
});
|
| 307 |
+
});
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
async function init() {
|
| 311 |
+
try {
|
| 312 |
+
const res = await fetch('./manifest.json', { cache: 'no-store' });
|
| 313 |
+
if (!res.ok) throw new Error('not found');
|
| 314 |
+
const manifest = await res.json();
|
| 315 |
+
renderSidebar(manifest);
|
| 316 |
+
} catch (err) {
|
| 317 |
+
console.warn('[OpenDesign viewer] Failed to load manifest:', err);
|
| 318 |
+
sidebar.innerHTML = '<div class="sidebar-empty">No mockups yet.<br>Run the <code>opendesign</code> skill to create one.</div>';
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
init();
|
| 323 |
+
</script>
|
| 324 |
+
</body>
|
| 325 |
+
</html>
|
skills/run-opendesign/SKILL.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: run-opendesign
|
| 3 |
+
description: Use after any OpenDesign build to serve ./opendesign/ over HTTP and give the user a clickable preview link. Handles duplicate server prevention and python/node runtime detection.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
You are starting the OpenDesign preview server. Complete all steps below in order.
|
| 7 |
+
|
| 8 |
+
## Port
|
| 9 |
+
|
| 10 |
+
Always use **8289**.
|
| 11 |
+
|
| 12 |
+
## Steps
|
| 13 |
+
|
| 14 |
+
1. **Detect the platform.**
|
| 15 |
+
|
| 16 |
+
Run:
|
| 17 |
+
```bash
|
| 18 |
+
uname -s 2>/dev/null
|
| 19 |
+
```
|
| 20 |
+
- If the output starts with `MINGW`, `CYGWIN`, or `MSYS`, or if `uname` is not found, treat the platform as **Windows**.
|
| 21 |
+
- Otherwise treat it as **POSIX** (Linux / macOS / WSL).
|
| 22 |
+
|
| 23 |
+
2. **Check if a server is already running on port 8289.**
|
| 24 |
+
|
| 25 |
+
**POSIX:**
|
| 26 |
+
```bash
|
| 27 |
+
lsof -ti tcp:8289
|
| 28 |
+
```
|
| 29 |
+
- If no output, nothing is bound — continue to step 3.
|
| 30 |
+
- If a PID is returned, something is bound to :8289.
|
| 31 |
+
|
| 32 |
+
**Windows (cmd/PowerShell):**
|
| 33 |
+
```powershell
|
| 34 |
+
netstat -ano | findstr LISTENING | findstr :8289
|
| 35 |
+
```
|
| 36 |
+
- If no output, nothing is bound — continue to step 3.
|
| 37 |
+
- If output is returned, something is bound to :8289.
|
| 38 |
+
|
| 39 |
+
When something is bound on either platform, probe whether it is the OpenDesign server:
|
| 40 |
+
```bash
|
| 41 |
+
curl -sf -o /dev/null -w "%{http_code}" http://localhost:8289/opendesign/index.html
|
| 42 |
+
```
|
| 43 |
+
- If the status code is `200`, the OpenDesign server is already running. Skip to step 5.
|
| 44 |
+
- Otherwise, tell the user:
|
| 45 |
+
> Port 8289 is in use by another process. Please free the port and try again.
|
| 46 |
+
Then stop.
|
| 47 |
+
|
| 48 |
+
3. **Detect available runtime.** Check in this order:
|
| 49 |
+
|
| 50 |
+
**POSIX:**
|
| 51 |
+
```bash
|
| 52 |
+
python3 --version 2>/dev/null || python --version 2>/dev/null || node --version 2>/dev/null
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
**Windows:**
|
| 56 |
+
```powershell
|
| 57 |
+
python --version 2>$null; if ($LASTEXITCODE -ne 0) { python3 --version 2>$null }; if ($LASTEXITCODE -ne 0) { node --version 2>$null }
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
Priority order (both platforms):
|
| 61 |
+
- **POSIX:** `python3` → `python` → `node`
|
| 62 |
+
- **Windows:** `python` → `python3` → `node` (Windows distributions ship as `python`, not `python3`)
|
| 63 |
+
- None found → tell the user: "Could not start the preview server — python, python3, and node are all unavailable. Open `./opendesign/index.html` manually or install Python." Then stop.
|
| 64 |
+
|
| 65 |
+
4. **Start the server in the background**, serving from the project root (not from `./opendesign/`).
|
| 66 |
+
|
| 67 |
+
**POSIX** — capture the absolute project root first:
|
| 68 |
+
```bash
|
| 69 |
+
PROJECT_ROOT=$(pwd)
|
| 70 |
+
```
|
| 71 |
+
Then start:
|
| 72 |
+
- python3: `python3 -m http.server 8289 --directory "$PROJECT_ROOT" &`
|
| 73 |
+
- python: `python -m http.server 8289 --directory "$PROJECT_ROOT" &`
|
| 74 |
+
- node: `npx --yes serve -l 8289 "$PROJECT_ROOT" &`
|
| 75 |
+
|
| 76 |
+
**Windows** — `cd` to the project root first (the `--directory` flag is available on Python 3.7+ but `cd` is the safest cross-version approach), then start:
|
| 77 |
+
- python: `Start-Process python -ArgumentList '-m','http.server','8289' -WorkingDirectory (Get-Location) -WindowStyle Hidden`
|
| 78 |
+
- python3: `Start-Process python3 -ArgumentList '-m','http.server','8289' -WorkingDirectory (Get-Location) -WindowStyle Hidden`
|
| 79 |
+
- node: `Start-Process npx -ArgumentList '--yes','serve','-l','8289',(Get-Location) -WindowStyle Hidden`
|
| 80 |
+
|
| 81 |
+
Wait 1–2 seconds after starting, then confirm the port is now bound using the same check from step 2 for the detected platform. If nothing is bound after the wait, report: "Server failed to start. Try running `python -m http.server 8289` manually from your project root." Then stop.
|
| 82 |
+
|
| 83 |
+
5. **Print the clickable link** to the user:
|
| 84 |
+
|
| 85 |
+
> OpenDesign viewer is live: **http://localhost:8289/opendesign/**
|
| 86 |
+
>
|
| 87 |
+
> Sidebar lists all mockups. Click any file to preview it in the iframe.
|
skills/setup-opendesign/SKILL.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: setup-opendesign
|
| 3 |
+
description: Use when ./opendesign/index.html does not exist in the current project. Initialises the OpenDesign output folder structure, copies the viewer, and writes an empty manifest.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
You are setting up the OpenDesign output environment for this project for the first time. Complete all steps below in order, then announce completion.
|
| 7 |
+
|
| 8 |
+
## Steps
|
| 9 |
+
|
| 10 |
+
1. **Download `viewer.html` from GitHub.**
|
| 11 |
+
|
| 12 |
+
Fetch the file from:
|
| 13 |
+
```
|
| 14 |
+
https://raw.githubusercontent.com/manalkaff/opendesign/main/skills/opendesign/viewer.html
|
| 15 |
+
```
|
| 16 |
+
Write the response body directly to `./opendesign/index.html` (create `./opendesign/` first if it does not exist). If the fetch fails, tell the user:
|
| 17 |
+
> Could not download the OpenDesign viewer. Check your internet connection and try again, or manually copy `viewer.html` from the opendesign plugin to `./opendesign/index.html`.
|
| 18 |
+
|
| 19 |
+
2. **Create output folders** if they do not already exist:
|
| 20 |
+
- `./opendesign/mockups/`
|
| 21 |
+
- `./opendesign/design-systems/`
|
| 22 |
+
|
| 23 |
+
3. **Write `./opendesign/manifest.json`** if it does not already exist:
|
| 24 |
+
|
| 25 |
+
```json
|
| 26 |
+
{
|
| 27 |
+
"generated": "<current ISO 8601 timestamp>",
|
| 28 |
+
"sections": [
|
| 29 |
+
{
|
| 30 |
+
"id": "mockups",
|
| 31 |
+
"label": "Mockups",
|
| 32 |
+
"groups": []
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"id": "design-systems",
|
| 36 |
+
"label": "Design Systems",
|
| 37 |
+
"groups": []
|
| 38 |
+
}
|
| 39 |
+
]
|
| 40 |
+
}
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
4. **Announce to the user:**
|
| 44 |
+
> OpenDesign is set up. Open `./opendesign/index.html` in your browser to view mockups. If previews don't load, serve the folder with `python -m http.server 8080` and open `http://localhost:8080/opendesign/`.
|
skills/wireframe/SKILL.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: wireframe
|
| 3 |
+
description: Use when the user wants to explore the design space quickly — many rough ideas, not one polished direction. Low-fi, handwritten-font sketches; 3–5 structurally distinct options per idea, not recolors.
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
Loaded when the user wants to explore the design space quickly — many rough ideas, not one polished direction.
|
| 7 |
+
|
| 8 |
+
## Output location
|
| 9 |
+
|
| 10 |
+
Write all output files to `./opendesign/mockups/<task-slug>/`. Derive the slug from the task name (e.g. `dashboard-redesign`, `onboarding-flow`).
|
| 11 |
+
|
| 12 |
+
## Role framing
|
| 13 |
+
|
| 14 |
+
The goal is breadth, not polish. The output is a map of the design space, not a finished artifact. Use this skill early in a project, before the user has committed to a direction.
|
| 15 |
+
|
| 16 |
+
Interview the user first to understand the problem, then generate multiple rough takes in one pass.
|
| 17 |
+
|
| 18 |
+
## Quantity and spread
|
| 19 |
+
|
| 20 |
+
- Produce 3 to 5 distinctly different approaches per idea. "Distinct" means different structural logic, not different colors of the same layout. If two wireframes could be swapped by changing a class, they are the same wireframe.
|
| 21 |
+
- Lay options out side by side so the user can compare them in one glance. For small sets, use a single canvas. For larger sets, use tabbed or paginated groupings so the comparison stays readable.
|
| 22 |
+
|
| 23 |
+
## Visual style
|
| 24 |
+
|
| 25 |
+
- Low-fidelity, sketchy vibe. Handwritten-but-readable fonts (e.g. Caveat, Patrick Hand, Shadows Into Light, Kalam).
|
| 26 |
+
- Mostly black and white. Sparing color accents only to call out active or emphasized elements.
|
| 27 |
+
- Simple shapes: rectangles, lines, circles. No real imagery, no real icons. Placeholder text is fine and expected.
|
| 28 |
+
- No polished typography. No real brand colors. No hover states. These are thinking aids, not mockups.
|
| 29 |
+
|
| 30 |
+
## Structure of each wireframe
|
| 31 |
+
|
| 32 |
+
- Focus on layout and flow. Where things sit, what reads as primary, what sequence the user moves through.
|
| 33 |
+
- Label sections clearly in plain language ("search bar", "filters", "results list", "primary action") so the user can discuss them without pointing.
|
| 34 |
+
- When a wireframe implies an interaction, annotate it with a short note. Do not implement it.
|
| 35 |
+
|
| 36 |
+
## Tweaks and iteration
|
| 37 |
+
|
| 38 |
+
- Expose a small set of simple tweaks: toggle between variants, change density, swap an optional section in or out. Keep the tweak surface minimal. Wireframes should not compete with prototypes for fidelity.
|
| 39 |
+
|
| 40 |
+
## What to avoid
|
| 41 |
+
|
| 42 |
+
- Do not polish a wireframe. If the user likes one, the next step is a separate higher-fidelity pass — not sanding down the sketch.
|
| 43 |
+
- Do not let wireframes converge visually. If five options all look the same, you have one option, not five.
|
validate-skills.sh
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Validate that every skill has frontmatter with name + description,
|
| 3 |
+
# and that host plugin versions stay in sync.
|
| 4 |
+
|
| 5 |
+
set -eu
|
| 6 |
+
cd "$(dirname "$0")"
|
| 7 |
+
|
| 8 |
+
fail=0
|
| 9 |
+
|
| 10 |
+
# 1. Every skills/*/SKILL.md must exist and have frontmatter with name + description.
|
| 11 |
+
for dir in skills/*/; do
|
| 12 |
+
file="$dir/SKILL.md"
|
| 13 |
+
skill_name="$(basename "$dir")"
|
| 14 |
+
|
| 15 |
+
if [ ! -f "$file" ]; then
|
| 16 |
+
echo "MISSING: $file"
|
| 17 |
+
fail=1
|
| 18 |
+
continue
|
| 19 |
+
fi
|
| 20 |
+
|
| 21 |
+
if ! head -1 "$file" | grep -q '^---$'; then
|
| 22 |
+
echo "NO FRONTMATTER: $file"
|
| 23 |
+
fail=1
|
| 24 |
+
continue
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
if ! awk '/^---$/{c++} c==1{print} c==2{exit}' "$file" | grep -q '^name:'; then
|
| 28 |
+
echo "MISSING name: $file"
|
| 29 |
+
fail=1
|
| 30 |
+
fi
|
| 31 |
+
|
| 32 |
+
if ! awk '/^---$/{c++} c==1{print} c==2{exit}' "$file" | grep -q '^description:'; then
|
| 33 |
+
echo "MISSING description: $file"
|
| 34 |
+
fail=1
|
| 35 |
+
fi
|
| 36 |
+
|
| 37 |
+
declared_name="$(awk '/^---$/{c++} c==1{print} c==2{exit}' "$file" | awk -F': *' '/^name:/{print $2; exit}')"
|
| 38 |
+
if [ "$declared_name" != "$skill_name" ]; then
|
| 39 |
+
echo "NAME MISMATCH: $file declares '$declared_name' but folder is '$skill_name'"
|
| 40 |
+
fail=1
|
| 41 |
+
fi
|
| 42 |
+
done
|
| 43 |
+
|
| 44 |
+
# (Claude Code discovers skills by convention from ./skills/; no explicit list to keep in sync.)
|
| 45 |
+
|
| 46 |
+
# 2. Version must match across every host config.
|
| 47 |
+
extract_version() {
|
| 48 |
+
grep -oE '"version"[[:space:]]*:[[:space:]]*"[^"]+"' "$1" | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
v_claude="$(extract_version .claude-plugin/plugin.json)"
|
| 52 |
+
v_market="$(extract_version .claude-plugin/marketplace.json)"
|
| 53 |
+
v_cursor="$(extract_version .cursor-plugin/plugin.json)"
|
| 54 |
+
v_codex="$(extract_version .codex-plugin/plugin.json)"
|
| 55 |
+
v_gemini="$(extract_version gemini-extension.json)"
|
| 56 |
+
v_pkg="$(extract_version package.json)"
|
| 57 |
+
|
| 58 |
+
if [ "$v_claude" != "$v_market" ] || \
|
| 59 |
+
[ "$v_claude" != "$v_cursor" ] || \
|
| 60 |
+
[ "$v_claude" != "$v_codex" ] || \
|
| 61 |
+
[ "$v_claude" != "$v_gemini" ] || \
|
| 62 |
+
[ "$v_claude" != "$v_pkg" ]; then
|
| 63 |
+
echo "VERSION MISMATCH across host configs:"
|
| 64 |
+
echo " .claude-plugin/plugin.json: $v_claude"
|
| 65 |
+
echo " .claude-plugin/marketplace.json: $v_market"
|
| 66 |
+
echo " .cursor-plugin/plugin.json: $v_cursor"
|
| 67 |
+
echo " .codex-plugin/plugin.json: $v_codex"
|
| 68 |
+
echo " gemini-extension.json: $v_gemini"
|
| 69 |
+
echo " package.json: $v_pkg"
|
| 70 |
+
fail=1
|
| 71 |
+
fi
|
| 72 |
+
|
| 73 |
+
if [ "$fail" -eq 0 ]; then
|
| 74 |
+
echo "OK — all skills validated."
|
| 75 |
+
fi
|
| 76 |
+
|
| 77 |
+
exit "$fail"
|