htmlify-v2
Convert any content (markdown, specs, plans, findings) into a polished, self-contained static HTML document with a modern light/muted design. V2 standalone.
Works with
Agent Skills format with YAML frontmatter. Claude Code reads it as-is.
---
name: "htmlify-v2"
description: "Convert any content (markdown, specs, plans, findings) into a polished, self-contained static HTML document with a modern light/muted design. V2 standalone."
license: "MIT"
---
Please deep think / ultrathink as this is a complex task.
# htmlify-v2
**Static HTML document generator** — takes any content the user points to (markdown files, notes, specs, plans, conversation context) and produces a polished, self-contained HTML file. Zero dependencies, opens directly in a browser, ready to share or print to PDF.
````md
User input:
$ARGUMENTS
Expected usage patterns:
```bash
/htmlify <source> # HTMLify a file or path
/htmlify <source> --output path/to/out.html # Specify output path
/htmlify # HTMLify from conversation context
/htmlify --dark # Use dark variant
```
Where `<source>` can be:
- A file path (markdown, text, any readable file)
- A directory (concatenates relevant files)
- Omitted — uses the current conversation context or the user's description
````
## Purpose
Produce beautiful, zero-dependency static HTML documents from raw content. The output should look like a polished report you'd share with stakeholders — not a raw markdown render. Think Notion page or Linear changelog — clean, readable, professional.
## Flow
### 1) Parse Arguments
- Determine the **source** content (file path, directory, or conversation context)
- Determine the **output path** (default: same directory as source, with `.html` extension; for context-based, use `./scratch/` or current directory)
- Determine **theme** (default: light; `--dark` for dark variant)
### 2) Load & Analyse Source Content
- Read the source content fully
- Identify the document structure:
- Title and subtitle
- Sections and their hierarchy
- Tables, lists, code blocks
- Diagrams (mermaid candidates)
- Key findings, recommendations, callouts
- Metrics or summary data
- Determine which components best represent each content element
### 3) Generate HTML
**Rules:**
- Use semantic HTML throughout — real HTML elements, NOT markdown rendered at runtime
- **First line** of the output file MUST be: `<!-- Generated by htmlify-v2 -->`
- All CSS is inlined in a `<style>` block — single self-contained file
- Select appropriate accent colours from the palette to visually distinguish sections
- Use callout variants to match tone (see palette below)
- Use tables for structured comparisons — don't force everything into cards
- Add anchor navigation bar if the document has 3+ sections
- Include mermaid diagrams where content describes flows, architectures, or relationships
- Add mermaid.js CDN script ONLY if mermaid diagrams are present
- Preserve the substance and detail of the source — don't summarise or truncate
### 4) Write Output
- Write the HTML file to the determined output path
- Confirm the output path and file size to the user
- Suggest `open <path>` to preview
---
## Built-in Design System
The skill carries its own CSS. No external template files needed.
### Design Principles
- **Light and airy** — generous whitespace, muted backgrounds, subtle borders
- **Typography-first** — Inter/system font stack, clear hierarchy, comfortable reading width
- **Muted accents** — no saturated primaries; use soft, desaturated tones
- **Minimal chrome** — content speaks, UI disappears
### Colour Palette (Light Mode)
```css
:root {
/* Surface & text */
--bg: #FAFAFA;
--bg-card: #FFFFFF;
--bg-nav: #F5F5F4;
--text: #1C1917;
--text-muted: #78716C;
--text-subtle: #A8A29E;
--border: #E7E5E4;
--border-hover: #D6D3D1;
/* Accent palette — muted, desaturated */
--accent-blue: #6B9BD2;
--accent-green: #6BA387;
--accent-amber: #C4985A;
--accent-rose: #C47A7A;
--accent-purple: #9B8EC4;
--accent-teal: #5DA3A3;
/* Semantic callouts */
--info-bg: #EFF6FF; --info-border: #93C5FD;
--success-bg: #F0FDF4; --success-border: #86EFAC;
--warning-bg: #FFFBEB; --warning-border: #FCD34D;
--error-bg: #FEF2F2; --error-border: #FCA5A5;
--insight-bg: #FAF5FF; --insight-border: #C4B5FD;
--neutral-bg: #F5F5F4; --neutral-border: #D6D3D1;
/* Code */
--code-bg: #F5F5F4;
--code-text: #292524;
/* Spacing */
--radius: 8px;
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2.5rem;
}
```
### Colour Palette (Dark Mode — `--dark` flag)
```css
:root {
--bg: #1A1A1A;
--bg-card: #242424;
--bg-nav: #1E1E1E;
--text: #E7E5E4;
--text-muted: #A8A29E;
--text-subtle: #78716C;
--border: #333333;
--border-hover: #444444;
--accent-blue: #7DADE2;
--accent-green: #7DB89B;
--accent-amber: #D4A86A;
--accent-rose: #D48A8A;
--accent-purple: #ADA0D4;
--accent-teal: #6DB3B3;
--info-bg: #1E293B; --info-border: #60A5FA;
--success-bg: #14291E; --success-border: #6EE7A0;
--warning-bg: #2D2410; --warning-border: #FBBF24;
--error-bg: #2D1414; --error-border: #F87171;
--insight-bg: #1E1533; --insight-border: #A78BFA;
--neutral-bg: #262626; --neutral-border: #404040;
--code-bg: #2A2A2A;
--code-text: #E7E5E4;
}
```
### Core CSS
```css
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
max-width: 860px;
margin: 0 auto;
padding: var(--space-xl) var(--space-lg);
}
/* Typography */
h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; margin-bottom: var(--space-xs); }
h2 { font-size: 1.35rem; font-weight: 600; letter-spacing: -0.01em; margin-top: var(--space-xl); margin-bottom: var(--space-md); color: var(--text); }
h3 { font-size: 1.1rem; font-weight: 600; margin-top: var(--space-lg); margin-bottom: var(--space-sm); }
.subtitle { color: var(--text-muted); font-size: 0.95rem; margin-bottom: var(--space-xl); }
p { margin-bottom: var(--space-md); }
/* Navigation */
.nav {
display: flex; flex-wrap: wrap; gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
background: var(--bg-nav); border-radius: var(--radius);
margin-bottom: var(--space-xl); border: 1px solid var(--border);
}
.nav a {
color: var(--text-muted); text-decoration: none; font-size: 0.85rem;
font-weight: 500; padding: var(--space-xs) var(--space-sm);
border-radius: 4px; transition: all 0.15s;
}
.nav a:hover { color: var(--text); background: var(--border); }
/* Cards */
.card {
background: var(--bg-card); border: 1px solid var(--border);
border-radius: var(--radius); padding: var(--space-lg);
margin-bottom: var(--space-lg);
}
.card.border-blue { border-left: 3px solid var(--accent-blue); }
.card.border-green { border-left: 3px solid var(--accent-green); }
.card.border-amber { border-left: 3px solid var(--accent-amber); }
.card.border-rose { border-left: 3px solid var(--accent-rose); }
.card.border-purple { border-left: 3px solid var(--accent-purple); }
.card.border-teal { border-left: 3px solid var(--accent-teal); }
/* Callouts */
.callout {
padding: var(--space-md) var(--space-lg);
border-radius: var(--radius); margin-bottom: var(--space-md);
border-left: 3px solid; font-size: 0.92rem;
}
.callout.info { background: var(--info-bg); border-color: var(--info-border); }
.callout.success { background: var(--success-bg); border-color: var(--success-border); }
.callout.warning { background: var(--warning-bg); border-color: var(--warning-border); }
.callout.error { background: var(--error-bg); border-color: var(--error-border); }
.callout.insight { background: var(--insight-bg); border-color: var(--insight-border); }
.callout.neutral { background: var(--neutral-bg); border-color: var(--neutral-border); }
/* Badges */
.badge {
display: inline-block; font-size: 0.75rem; font-weight: 600;
padding: 2px 8px; border-radius: 10px;
background: var(--neutral-bg); color: var(--text-muted);
}
.badge.blue { background: var(--info-bg); color: var(--accent-blue); }
.badge.green { background: var(--success-bg); color: var(--accent-green); }
.badge.amber { background: var(--warning-bg); color: var(--accent-amber); }
.badge.rose { background: var(--error-bg); color: var(--accent-rose); }
.badge.purple { background: var(--insight-bg); color: var(--accent-purple); }
/* Tables */
table { width: 100%; border-collapse: collapse; margin-bottom: var(--space-md); font-size: 0.9rem; }
th { text-align: left; font-weight: 600; color: var(--text-muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; padding: var(--space-sm) var(--space-md); border-bottom: 2px solid var(--border); }
td { padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border); }
tr:last-child td { border-bottom: none; }
/* Code */
code { font-family: 'JetBrains Mono', 'Fira Code', monospace; font-size: 0.85em; background: var(--code-bg); color: var(--code-text); padding: 2px 6px; border-radius: 4px; }
pre { background: var(--code-bg); padding: var(--space-md); border-radius: var(--radius); overflow-x: auto; margin-bottom: var(--space-md); border: 1px solid var(--border); }
pre code { background: none; padding: 0; }
/* Verdict / summary block */
.verdict {
background: var(--bg-card); border: 2px solid var(--accent-green);
border-radius: var(--radius); padding: var(--space-lg);
margin: var(--space-xl) 0; text-align: center;
}
.verdict h3 { margin-top: 0; color: var(--accent-green); }
/* Flow steps */
.flow-step {
display: flex; align-items: flex-start; gap: var(--space-md);
margin-bottom: var(--space-md); padding: var(--space-md);
background: var(--bg-card); border-radius: var(--radius); border: 1px solid var(--border);
}
.flow-step .step-num {
flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%;
background: var(--accent-blue); color: white; font-weight: 700;
font-size: 0.8rem; display: flex; align-items: center; justify-content: center;
}
/* Grid layouts */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--space-md); }
@media (max-width: 640px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }
/* Phase labels */
.phase-label {
display: inline-block; font-size: 0.75rem; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.08em;
color: var(--text-muted); margin-bottom: var(--space-sm);
}
/* Lists */
ul, ol { padding-left: var(--space-lg); margin-bottom: var(--space-md); }
li { margin-bottom: var(--space-xs); }
/* Horizontal rule */
hr { border: none; border-top: 1px solid var(--border); margin: var(--space-xl) 0; }
/* Mermaid */
.mermaid { margin: var(--space-md) 0; text-align: center; }
/* Print */
@media print {
body { max-width: 100%; padding: 1cm; }
.nav { display: none; }
.card { break-inside: avoid; }
}
```
### Component Catalogue
| Component | Class | When to Use |
|-----------|-------|-------------|
| **Card** | `.card .border-{colour}` | Wrap sections; vary border colour per section |
| **Callout** | `.callout .{info\|success\|warning\|error\|insight\|neutral}` | Highlight key points, warnings, tips |
| **Badge** | `.badge .{blue\|green\|amber\|rose\|purple}` | Status labels, categories, tags |
| **Table** | `<table>` | Structured data, comparisons |
| **Verdict** | `.verdict` | Key conclusions, final recommendations |
| **Flow Step** | `.flow-step` + `.step-num` | Sequential processes, numbered steps |
| **Grid** | `.grid-2` / `.grid-3` | Side-by-side layouts |
| **Phase Label** | `.phase-label` | Phase markers in phased work |
| **Nav** | `.nav` | Anchor navigation for 3+ sections |
| **Code** | `<pre><code>` | Code blocks |
| **Mermaid** | `.mermaid` | Architecture diagrams, flows |
### Colour Selection Guide
Rotate border colours across sections for visual distinction:
```
Section 1 → border-blue
Section 2 → border-teal
Section 3 → border-purple
Section 4 → border-amber
Section 5 → border-green
Section 6 → border-rose
```
Don't use the same colour for adjacent cards.
---
## Example Output Structure
```html
<!-- Generated by htmlify-v2 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Title</title>
<style>
/* [full built-in CSS from above] */
</style>
</head>
<body>
<h1>Document Title</h1>
<p class="subtitle">Context · Date</p>
<nav class="nav">
<a href="#overview">Overview</a>
<a href="#findings">Findings</a>
<a href="#recommendations">Recommendations</a>
</nav>
<div id="overview" class="card border-blue">
<h2>Overview</h2>
<p>Content goes here...</p>
</div>
<div class="callout info">
<strong>Note:</strong> Important context the reader should know.
</div>
<div id="findings" class="card border-teal">
<h2>Key Findings</h2>
<table>
<tr><th>Finding</th><th>Impact</th><th>Status</th></tr>
<tr><td>Finding 1</td><td>High</td><td><span class="badge rose">Critical</span></td></tr>
<tr><td>Finding 2</td><td>Medium</td><td><span class="badge amber">Review</span></td></tr>
</table>
</div>
<div id="recommendations" class="card border-purple">
<h2>Recommendations</h2>
<div class="flow-step">
<div class="step-num">1</div>
<div><strong>First step</strong> — do this thing first.</div>
</div>
<div class="flow-step">
<div class="step-num">2</div>
<div><strong>Second step</strong> — then do this.</div>
</div>
</div>
<div class="verdict">
<h3>Verdict</h3>
<p>Summary conclusion here.</p>
</div>
</body>
</html>
```
## Quality Standards
- Output must be visually polished — intentionally designed, not auto-generated
- Content hierarchy must be clear — use card borders, headings, and spacing
- Don't over-componentise — plain paragraphs inside cards are fine
- Tables should be used for tabular data; don't convert tables to cards
- Mermaid diagrams must be syntactically correct
- HTML must render correctly when opened directly in a browser (file:// protocol)
- Preserve the substance and detail of the source — don't summarise or truncate
## Anti-Patterns
- Rendering markdown at runtime with a JS library
- Using the same card border colour for every section
- Converting every paragraph into a callout
- Losing content detail during conversion
- Adding build tools, npm, or any dependencies
- Generating broken mermaid syntax
- Forgetting the comment on line 1More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

