Self-contained design transformer — invoke directly, do not decompose. Transforms a design reference HTML file into a Vibes app. Use when user provides a design.html, mockup, or static prototype to match exactly.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add popmechanic/VibesOS --skill design --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Design?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/popmechanic-design-vibesos)More formats (shields.io, HTML) on the badges page.
---
name: design
argument-hint: "<design.html>"
description: Self-contained design transformer — invoke directly, do not decompose. Transforms a design reference HTML file into a Vibes app. Use when user provides a design.html, mockup, or static prototype to match exactly.
license: MIT
allowed-tools: Read, Write, Bash, AskUserQuestion
metadata:
author: "Marcus Estes"
---
> **Plan mode**: If you are planning work, this entire skill is ONE plan step: "Invoke /vibes:design". Do not decompose the steps below into separate plan tasks.
**Display this ASCII art immediately when starting:**
```
░▒▓███████▓▒░░▒▓████████▓▒░░▒▓███████▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓██████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░
░▒▓███████▓▒░░▒▓████████▓▒░▒▓███████▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░
```
# Design Reference Transformer
Transform a complete design reference HTML file into a working Vibes app with TinyBase reactive data.
---
## Core Principle
> **Preserve and adapt, don't interpret and recreate.**
The design reference is **source code to transform**, not inspiration to interpret. When given a complete HTML file with styles, your job is to make **minimal surgical changes** to connect it to React/TinyBase—not to recreate it from your understanding of its aesthetic.
---
## When to Use This Skill
Use this skill when:
- User provides a `design.html`, mockup, or static prototype file
- User says "match this design exactly" or "use this as a reference"
- User wants their existing HTML converted to a Vibes app
- A previous implementation didn't match the design reference
---
## The Transformation is Mechanical
The conversion from design HTML to React/TinyBase is **deterministic, not creative**:
| Transformation | Rule | Example |
|----------------|------|---------|
| Attributes | `class` → `className` | `class="btn"` → `className="btn"` |
| Attributes | `for` → `htmlFor` | `for="email"` → `htmlFor="email"` |
| Attributes | kebab-case → camelCase | `stroke-width` → `strokeWidth` |
| Self-closing | Add explicit close | `<input>` → `<input />` |
| Comments | HTML → JSX | `<!-- x -->` → `{/* x */}` |
| Inline styles | String → Object | `style="color: red"` → `style={{ color: 'red' }}` |
| Event handlers | Lowercase → camelCase | `onclick` → `onClick` |
**CSS requires NO changes.** Copy the entire `<style>` block verbatim.
---
## Workflow
### Step 1: Read the Design Reference
```bash
# Read the design file completely
Read design.html
```
Note the structure:
- `<style>` block (copy verbatim)
- HTML structure (preserve exactly)
- Any vanilla JavaScript (will be replaced with React)
### Step 2: Identify Dynamic Content
Ask: "What content comes from the database?"
Typical dynamic elements:
- List items that repeat (`.map()`)
- Text that users enter (controlled inputs)
- Counts, totals, timestamps
- User-specific content
**Everything else stays static.**
### Step 3: Create the React Component
```jsx
function App() {
// TinyBase hooks are globals — no imports, no initialization call needed
const rowIds = useRowIds('items');
const handleAdd = useAddRowCallback('items', (e) => ({
text: '', type: 'item', created: Date.now()
}));
return (
<>
{/* CSS copied VERBATIM from design.html */}
<style>{`
/* Paste entire <style> block here unchanged */
`}</style>
{/* HTML structure preserved, only syntax converted */}
{/* Dynamic content replaced with {expressions} */}
</>
);
}
```
### Step 4: Handle Dark Mode Override (If Needed)
The Vibes template has dark mode support. If your design is light-only, add this CSS override:
```css
/* Force light theme regardless of system preference */
html, body, #container, #container > div {
background-color: var(--your-bg-color) !important;
}
```
**Note:** Avoid targeting `[style*="position: fixed"]` as this will style the VibesSwitch toggle button.
### Step 4b: Scope CSS to Avoid VibesSwitch/VibesPanel Conflicts
The template includes a VibesSwitch toggle button and VibesPanel admin menu that sit **outside** your app container. Broad CSS selectors can accidentally style these components.
**Watch for these problematic patterns:**
| Problematic | Why | Safe Alternative |
|-------------|-----|------------------|
| `button { ... }` | Styles VibesSwitch toggle | `.app button { ... }` or `#container button { ... }` |
| `* { ... }` (with colors/backgrounds) | Cascades everywhere | Scope to specific containers |
| `[style*="position: fixed"]` | Targets VibesSwitch | Target by class/ID instead |
| `body > div` | May match menu wrapper | Use `#container > div` |
**If your design has global button/element styles:**
1. Wrap your app content in a container with a class: `<div className="app">...</div>`
2. Scope broad rules: `button { }` → `.app button { }`
3. Or use `#container` which is the template's app root
**The template already protects components with:**
```css
button[aria-controls="hidden-menu"] { background: transparent !important; }
#hidden-menu { /* menu-specific variable resets */ }
```
But defense-in-depth is better—scope your CSS to avoid conflicts.
### Step 5: Assemble and Test
```bash
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
bun "$VIBES_ROOT/scripts/assemble.js" app.jsx index.html
```
Open in browser and **visually diff against the design reference**. They should be pixel-identical except for dynamic content.
---
## Anti-Patterns (DO NOT DO THESE)
| Anti-Pattern | Why It's Wrong | Correct Approach |
|--------------|----------------|------------------|
| Translate colors to OKLCH | Changes the design | Use exact hex values from reference |
| Restructure HTML "for React" | Breaks layout | Preserve structure, only change syntax |
| "Improve" the CSS | Not your job | Copy verbatim |
| Add your own classes | Introduces drift | Use exact classes from reference |
| Interpret the "vibe" | Creates divergence | Be literal, not interpretive |
| Skip vanilla JS analysis | Miss functionality | Understand what it does, then React-ify |
---
## Transformation Checklist
Before writing code, verify:
- [ ] Read the entire design.html file
- [ ] Identified all `<style>` blocks (will copy verbatim)
- [ ] Identified dynamic content (lists, inputs, user data)
- [ ] Identified vanilla JS functionality (will convert to React)
- [ ] Noted any custom fonts (add to imports if needed)
- [ ] Checked for dark/light theme assumptions
During transformation:
- [ ] CSS pasted unchanged (no "improvements")
- [ ] HTML structure preserved exactly
- [ ] Only syntax converted (class→className, etc.)
- [ ] Dynamic content uses `{expressions}` and `.map()`
- [ ] Vanilla JS replaced with React hooks and handlers
- [ ] Dark mode override added if design is light-only
After assembly:
- [ ] Visual comparison with design reference
- [ ] All interactive elements work
- [ ] Data persists on refresh
- [ ] No console errors
- [ ] VibesSwitch toggle (bottom-right) displays correctly with no background box
- [ ] VibesPanel menu opens when toggle is clicked
- [ ] Menu buttons are correctly styled (not inheriting app button styles)
---
## Example: Static List → Dynamic List
**Design HTML:**
```html
<ul class="item-list">
<li class="item">First item</li>
<li class="item">Second item</li>
</ul>
```
**React with TinyBase:**
```jsx
const rowIds = useRowIds('items');
<ul className="item-list">
{rowIds.map(id => (
<ItemRow key={id} id={id} />
))}
</ul>
// Child component uses useCell for reactive per-row data
function ItemRow({ id }) {
const text = useCell('items', id, 'text');
return <li className="item">{text}</li>;
}
```
Note: Only the content changed. The classes, structure, and styling are identical.
---
## Example: Static Form → Controlled Form
**Design HTML:**
```html
<form>
<input type="text" class="input" placeholder="Enter text...">
<button class="btn">Submit</button>
</form>
```
**React with TinyBase:**
```jsx
const [text, setText] = useState('');
const handleAdd = useAddRowCallback('items', () => ({
text, type: 'item', created: Date.now()
}));
<form onSubmit={(e) => { e.preventDefault(); handleAdd(); setText(''); }}>
<input
type="text"
className="input"
placeholder="Enter text..."
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button type="submit" className="btn">Submit</button>
</form>
```
Note: Same structure, same classes, same placeholder. Only added React bindings.
---
## Integration with Vibes Assembly
This skill produces an `app.jsx` that works with the standard Vibes assembly:
```bash
# In the working directory
VIBES_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "${CLAUDE_SKILL_DIR}")")}"
bun "$VIBES_ROOT/scripts/assemble.js" app.jsx index.html
```
The assembly script:
- Inserts your JSX into the Vibes template
- Handles OIDC authentication wrapper (via Pocket ID)
- Sets up import maps for React and TinyBase
- Configures sync URLs if present (auth is automatic via Pocket ID)
---
## What's Next?
After transforming a design reference, present these options using AskUserQuestion:
```
Question: "Design reference transformed! What's next?"
Header: "Next"
Options:
- Label: "Test locally"
Description: "Open index.html in browser to verify it matches the design exactly"
- Label: "Deploy to Cloudflare (/cloudflare)"
Description: "Push the app live to Cloudflare Workers"
- Label: "Make adjustments"
Description: "Fine-tune specific elements while preserving the design"
- Label: "I'm done"
Description: "Wrap up - files are saved locally"
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!