init
This commit is contained in:
192
.opencode/skills/preview/references/generation-modes.md
Normal file
192
.opencode/skills/preview/references/generation-modes.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# Generation Modes
|
||||
|
||||
## Step 1: Determine Output Location
|
||||
|
||||
1. Check if there's an active plan context (from `## Plan Context` in hook injection)
|
||||
2. If active plan exists: save to `{plan_dir}/visuals/{topic-slug}.md`
|
||||
3. If no active plan: save to `plans/visuals/{topic-slug}.md`
|
||||
4. Create `visuals/` directory if it doesn't exist
|
||||
|
||||
## Step 2: Generate Content
|
||||
|
||||
**Mermaid Diagram Syntax:**
|
||||
When generating mermaid code blocks, use `/ck:mermaidjs-v11` skill for v11 syntax rules.
|
||||
|
||||
**Essential rules (always apply):**
|
||||
- Quote node text with special characters: `A["text with /slashes"]`
|
||||
- Escape brackets in labels: `A["array[0]"]`
|
||||
|
||||
Use the appropriate template based on flag:
|
||||
|
||||
### --explain (Visual Explanation)
|
||||
```markdown
|
||||
# Visual Explanation: {topic}
|
||||
|
||||
## Overview
|
||||
Brief description of what we're explaining.
|
||||
|
||||
## Quick View (ASCII)
|
||||
[ASCII diagram of component relationships]
|
||||
|
||||
## Detailed Flow
|
||||
[Mermaid sequence/flowchart diagram]
|
||||
|
||||
## Key Concepts
|
||||
1. **Concept A** - Explanation
|
||||
2. **Concept B** - Explanation
|
||||
|
||||
## Code Example (if applicable)
|
||||
[Relevant code snippet with comments]
|
||||
```
|
||||
|
||||
### --slides (Presentation Format)
|
||||
```markdown
|
||||
# {Topic} - Visual Presentation
|
||||
|
||||
---
|
||||
## Slide 1: Introduction
|
||||
- One concept per slide
|
||||
- Bullet points only
|
||||
|
||||
---
|
||||
## Slide 2: The Problem
|
||||
[Mermaid flowchart]
|
||||
|
||||
---
|
||||
## Slide 3: The Solution
|
||||
- Key point 1
|
||||
- Key point 2
|
||||
|
||||
---
|
||||
## Slide 4: Summary
|
||||
Key takeaways...
|
||||
```
|
||||
|
||||
### --diagram (Focused Diagram)
|
||||
```markdown
|
||||
# Diagram: {topic}
|
||||
|
||||
## ASCII Version
|
||||
[ASCII architecture diagram]
|
||||
|
||||
## Mermaid Version
|
||||
[Mermaid flowchart/graph]
|
||||
```
|
||||
|
||||
### --ascii (Terminal-Friendly Only)
|
||||
```
|
||||
[ASCII-only box diagram with legend]
|
||||
```
|
||||
|
||||
## Step 3: Save and Preview
|
||||
|
||||
1. Write generated content to determined path
|
||||
2. Start preview server with the generated file:
|
||||
```bash
|
||||
node .opencode/skills/markdown-novel-viewer/scripts/server.cjs \
|
||||
--file "<generated-file-path>" --host 0.0.0.0 --open --foreground
|
||||
```
|
||||
|
||||
## Step 4: Report to User
|
||||
|
||||
Report:
|
||||
- Generated file path
|
||||
- Preview URL (local + network)
|
||||
- Remind: file saved in plan's `visuals/` folder for future reference
|
||||
|
||||
---
|
||||
|
||||
## HTML Mode Generation
|
||||
|
||||
When `--html` flag is present (or implied by `--diff`, `--plan-review`, `--recap`), generate self-contained HTML instead of Markdown.
|
||||
|
||||
### HTML Step 1: Determine Output Location
|
||||
- Same plan-aware logic as markdown mode but with `.html` extension
|
||||
- Active plan: `{plan_dir}/visuals/{topic-slug}.html`
|
||||
- No plan: `plans/visuals/{topic-slug}.html`
|
||||
- Create `visuals/` directory if needed
|
||||
|
||||
### HTML Step 2: Read References
|
||||
Always read `html-design-guidelines.md` first (anti-slop rules, style presets).
|
||||
|
||||
Then read mode-specific references:
|
||||
|
||||
| Mode | References | Templates to study |
|
||||
|------|------------|-------------------|
|
||||
| --html --explain | html-css-patterns.md, html-libraries.md | architecture.html |
|
||||
| --html --diagram | html-css-patterns.md, html-libraries.md | mermaid-flowchart.html or architecture.html |
|
||||
| --html --slides | html-slide-patterns.md, html-css-patterns.md, html-libraries.md | slide-deck.html |
|
||||
| --html --diff | html-css-patterns.md, html-libraries.md | data-table.html, architecture.html |
|
||||
| --html --plan-review | html-css-patterns.md, html-libraries.md | architecture.html, data-table.html |
|
||||
| --html --recap | html-css-patterns.md, html-libraries.md | architecture.html, data-table.html |
|
||||
|
||||
For multi-section pages (explain, diff, plan-review, recap): also read `html-responsive-nav.md`.
|
||||
|
||||
### HTML Step 3: Generate Content
|
||||
|
||||
Follow the 4-phase workflow:
|
||||
|
||||
**Think:** Determine content-type routing:
|
||||
- Mermaid for topology (flowcharts, sequence, ER, state, mind maps, class, C4)
|
||||
- CSS Grid for text-heavy architecture (cards with descriptions, code references)
|
||||
- HTML `<table>` for data (requirement audits, comparisons, matrices)
|
||||
- Chart.js for real charts (KPI dashboards, sparklines)
|
||||
- Hybrid for complex systems (15+ elements): simple Mermaid overview + detailed CSS Grid cards
|
||||
|
||||
**Structure:** Pick template pattern, plan sections, assign depth tiers (hero/elevated/default/recessed).
|
||||
|
||||
**Style:** Select font pairing + palette from curated presets. Vary from previous outputs. Apply anti-slop checks:
|
||||
- No Inter/Roboto/system-ui alone as body font
|
||||
- No indigo/violet (#8b5cf6, #7c3aed) as accent
|
||||
- No animated glowing box-shadows
|
||||
- No gradient text on headings
|
||||
- No emoji icons in section headers
|
||||
- No three-dot window chrome on code blocks
|
||||
|
||||
**Deliver:** Write single self-contained `.html` file — all CSS and JavaScript inline. External resources: CDN only (Google Fonts, Mermaid.js v11, Chart.js, anime.js).
|
||||
|
||||
**MANDATORY — Theme Toggle:** Every HTML page MUST include the light/dark theme toggle button from `html-css-patterns.md` → "Theme Toggle Button" section. This is non-negotiable. The toggle button (`<button class="theme-toggle">`) must be the first child of `<body>`, with its CSS and JS inlined. Pages without the toggle are considered incomplete.
|
||||
|
||||
For `--slides`: recommend invoking `/ck:ui-ux-pro-max` for richer style selection.
|
||||
Must use `/ck:mermaidjs-v11` for any Mermaid diagrams.
|
||||
|
||||
### HTML Step 4: Open in Browser
|
||||
- macOS: `open "{output-path}"`
|
||||
- Linux: `xdg-open "{output-path}"`
|
||||
- Windows: `start "{output-path}"`
|
||||
- No server needed — file is self-contained
|
||||
- Report file path and confirm browser opened
|
||||
|
||||
### Data Gathering for HTML-Only Modes
|
||||
|
||||
#### --diff [ref]
|
||||
1. Detect scope: branch name → working tree diff; commit hash → `git show`; HEAD → uncommitted; PR number → `gh pr diff`; range → two commits; no arg → diff against main
|
||||
2. Run: `git diff --stat`, `git diff --name-status`, line counts
|
||||
3. Read all changed files + surrounding context
|
||||
4. Scan new public API surface (grep exports, functions, classes, interfaces)
|
||||
5. Check CHANGELOG.md, README.md, docs updates
|
||||
6. Reconstruct decision rationale from commits/conversation/progress docs
|
||||
|
||||
#### --plan-review [plan-file]
|
||||
1. Input: explicit plan file path OR detect from active plan context
|
||||
2. Read plan in full (problem, changes, rejected alternatives, scope)
|
||||
3. Read every file the plan references + their dependencies
|
||||
4. Map blast radius (imports, tests, config, public API)
|
||||
5. Cross-reference: plan assumptions vs actual code state
|
||||
|
||||
#### --recap [timeframe]
|
||||
1. Parse time window: shorthand (2w, 30d, 3m) → git `--since` format; default 2w
|
||||
2. Project identity: README, CHANGELOG, package.json, file structure
|
||||
3. Recent activity: `git log --oneline --since=...`, `git shortlog`
|
||||
4. Current state: `git status`, stale branches, TODOs, progress docs
|
||||
5. Decision context: commit messages, plans, ADRs
|
||||
6. Architecture scan: key files, module structure, frequently changed areas
|
||||
|
||||
### Quality Checklist
|
||||
Before delivering HTML output, verify:
|
||||
- [ ] **Squint test:** Visual hierarchy visible at arm's length?
|
||||
- [ ] **Swap test:** Would this look AI-generated? Check against forbidden patterns
|
||||
- [ ] **Theme toggle (MANDATORY):** Toggle button present as first child of `<body>`? Both light and dark modes render correctly? See `html-css-patterns.md` → "Theme Toggle Button".
|
||||
- [ ] **Overflow:** No horizontal scroll on content (tables excepted, wrapped in scroll container)
|
||||
- [ ] **Mermaid:** Zoom controls present? ELK layout for 10+ nodes?
|
||||
- [ ] **Responsiveness:** Readable on mobile width?
|
||||
1717
.opencode/skills/preview/references/html-css-patterns.md
Normal file
1717
.opencode/skills/preview/references/html-css-patterns.md
Normal file
File diff suppressed because it is too large
Load Diff
393
.opencode/skills/preview/references/html-design-guidelines.md
Normal file
393
.opencode/skills/preview/references/html-design-guidelines.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# HTML Design Guidelines
|
||||
|
||||
Guidelines for generating distinctive, high-quality HTML pages. Read this before generating any HTML output.
|
||||
|
||||
---
|
||||
|
||||
## Anti-Slop: Forbidden Patterns
|
||||
|
||||
These patterns are explicitly forbidden — they signal "AI-generated template" and undermine quality. Check every page against this list before delivering.
|
||||
|
||||
### Typography — Forbidden Fonts as Primary `--font-body`
|
||||
|
||||
- **Inter** — the single most overused AI default
|
||||
- **Roboto, Arial, Helvetica** — generic system fallbacks promoted to primary
|
||||
- **system-ui, sans-serif alone** — no character, no intent
|
||||
|
||||
**Required:** Pick from the font pairings in `html-libraries.md`. Every generation should use a different pairing from the last.
|
||||
|
||||
### Color Palette — Forbidden Accents
|
||||
|
||||
- `#8b5cf6`, `#7c3aed`, `#a78bfa` — Tailwind's indigo/violet defaults
|
||||
- `#d946ef` — fuchsia
|
||||
- `#06b6d4` + `#d946ef` + `#f472b6` — the cyan + magenta + pink neon gradient combination
|
||||
- Any palette describable as "Tailwind defaults with purple/pink/cyan accents"
|
||||
|
||||
**Forbidden color effects:**
|
||||
- Gradient text on headings (`background: linear-gradient(...); background-clip: text;`) — screams AI-generated
|
||||
- Animated glowing box-shadows (`@keyframes glow { box-shadow: 0 0 20px... }`) — always produces AI slop
|
||||
- Multiple overlapping radial glows in accent colors creating a "neon haze"
|
||||
- Pulsing/breathing effects on static content
|
||||
- Continuous animations that run after page load (except progress indicators)
|
||||
|
||||
**Required accents (use these):**
|
||||
- Terracotta + sage (`#c2410c`, `#65a30d`) — warm, earthy
|
||||
- Teal + slate (`#0891b2`, `#0369a1`) — technical, precise
|
||||
- Rose + cranberry (`#be123c`, `#881337`) — editorial, refined
|
||||
- Amber + emerald (`#d97706`, `#059669`) — data-focused
|
||||
- Deep blue + gold (`#1e3a5f`, `#d4a73a`) — premium, sophisticated
|
||||
|
||||
### Section Headers — Forbidden
|
||||
|
||||
- Emoji icons in section headers (🏗️ ⚙️ 📁 💻 📅 🔗 ⚡ 🔧 📦 🚀, etc.)
|
||||
- Section headers that all use the same icon-in-rounded-box pattern
|
||||
|
||||
**Required:** Use styled monospace labels with colored dot indicators (`.section-label` + `.ve-card__label` pattern), numbered badges, or asymmetric section dividers. If an icon is genuinely needed, use inline SVG matching the palette.
|
||||
|
||||
### Layout — Forbidden
|
||||
|
||||
- Perfectly centered everything with uniform padding
|
||||
- All cards styled identically with the same border-radius, shadow, and spacing
|
||||
- Every section getting equal visual treatment — no hero/primary vs. secondary distinction
|
||||
- Symmetric layouts where left and right halves mirror each other
|
||||
|
||||
### Template Clichés — Forbidden
|
||||
|
||||
- Three-dot window chrome (red/yellow/green dots) on code blocks
|
||||
- KPI cards where every metric has identical gradient text treatment
|
||||
- "Neon Dashboard" aesthetic
|
||||
- Gradient meshes with pink/purple/cyan blobs in the background
|
||||
|
||||
### The Slop Test
|
||||
|
||||
Before delivering, check: **Would a developer immediately think "AI generated this"?**
|
||||
|
||||
Signs of slop:
|
||||
1. Inter or Roboto font with purple/violet gradient accents
|
||||
2. Every heading has `background-clip: text` gradient
|
||||
3. Emoji icons leading every section
|
||||
4. Glowing cards with animated shadows
|
||||
5. Cyan-magenta-pink color scheme on dark background
|
||||
6. Perfectly uniform card grid with no visual hierarchy
|
||||
7. Three-dot code block chrome
|
||||
|
||||
If two or more are present: regenerate with Blueprint, Editorial, Paper/ink, or a specific IDE theme.
|
||||
|
||||
---
|
||||
|
||||
## Palette Cohesion Principles
|
||||
|
||||
**Every generated page must feel like one intentional color story.** This is the single most important readability rule.
|
||||
|
||||
1. **Background warmth must match accent warmth.** Terracotta accents need warm cream backgrounds (`#faf7f5`), not cool gray (`#f8f9fa`). Teal accents need cool-tinted backgrounds (`#f0fdfa`). Mixing warm accents on cool backgrounds (or vice versa) creates visual dissonance that makes pages feel generic.
|
||||
|
||||
2. **Text-dim must belong to the same family.** On warm backgrounds, use warm grays (`#8a7e72`, `#a69889`). On cool backgrounds, use cool grays (`#5f8a85`, `#8b949e`). Never use GitHub-style `#6b7280` on warm cream.
|
||||
|
||||
3. **Borders should be tinted, not neutral.** Use `rgba(0, 0, 0, 0.07)` or palette-tinted borders instead of flat `#e5e7eb`. Borders should be barely visible — felt, not seen.
|
||||
|
||||
4. **Surface layers create depth without fighting.** Define `--surface`, `--surface2`, and `--surface-elevated` as gradations of the same hue, not different colors.
|
||||
|
||||
5. **Extend every palette with semantic colors.** Every preset below should also define `--green`, `--red`, `--amber`, `--sage`, `--teal`, `--plum` (and their `*-dim` variants) that harmonize with the base palette. Richer semantic sets prevent monotony without clashing.
|
||||
|
||||
---
|
||||
|
||||
## 6 Curated Style Presets
|
||||
|
||||
Pick one and commit. The constrained presets (Blueprint, Editorial, Paper/Ink, Terminal Mono) are safer — they have specific requirements that prevent defaulting to generic patterns.
|
||||
|
||||
**IMPORTANT:** After choosing a preset, extend it with semantic colors (`--green`, `--red`, `--amber`, `--sage`, `--teal`, `--plum` + `*-dim` variants) that harmonize with the base palette. The default palette in `html-css-patterns.md` shows the full semantic structure — replicate that structure for whichever preset you choose.
|
||||
|
||||
### Blueprint
|
||||
|
||||
Technical drawing feel. Subtle grid background, deep slate/blue palette, monospace labels, precise borders.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'DM Sans', system-ui, sans-serif;
|
||||
--font-mono: 'Fira Code', 'SF Mono', monospace;
|
||||
--bg: #0d1421;
|
||||
--surface: #111d2e;
|
||||
--surface-elevated: #162438;
|
||||
--border: rgba(100, 160, 220, 0.12);
|
||||
--border-bright: rgba(100, 160, 220, 0.22);
|
||||
--text: #c8d8e8;
|
||||
--text-dim: #607080;
|
||||
--accent: #4a90d9;
|
||||
--accent-dim: rgba(74, 144, 217, 0.1);
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--bg: #f0f4f8;
|
||||
--surface: #ffffff;
|
||||
--surface-elevated: #e8eef4;
|
||||
--border: rgba(30, 60, 100, 0.1);
|
||||
--text: #1a2a3a;
|
||||
--text-dim: #5a7090;
|
||||
--accent: #1a5fa8;
|
||||
--accent-dim: rgba(26, 95, 168, 0.08);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Background: faint dot grid (`background-image: radial-gradient(circle, var(--border) 1px, transparent 1px); background-size: 24px 24px`). Monospace labels throughout.
|
||||
|
||||
### Editorial
|
||||
|
||||
Serif headlines (Instrument Serif or Crimson Pro), generous whitespace, muted earth tones or deep navy + gold.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'Instrument Serif', Georgia, serif;
|
||||
--font-mono: 'JetBrains Mono', 'SF Mono', monospace;
|
||||
--bg: #0f1729;
|
||||
--surface: #162040;
|
||||
--surface-elevated: #1d2b52;
|
||||
--border: rgba(200, 180, 140, 0.08);
|
||||
--text: #e8e4d8;
|
||||
--text-dim: #9a9484;
|
||||
--accent: #d4a73a;
|
||||
--accent-dim: rgba(212, 167, 58, 0.1);
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--bg: #faf8f2;
|
||||
--surface: #ffffff;
|
||||
--surface-elevated: #f5f0e6;
|
||||
--border: rgba(30, 30, 50, 0.08);
|
||||
--text: #1a1814;
|
||||
--text-dim: #7a7468;
|
||||
--accent: #b8860b;
|
||||
--accent-dim: rgba(184, 134, 11, 0.08);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Paper/Ink
|
||||
|
||||
Warm cream `#faf7f5` background, terracotta/sage accents, informal feel.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'Plus Jakarta Sans', system-ui, sans-serif;
|
||||
--font-mono: 'Azeret Mono', 'SF Mono', monospace;
|
||||
--bg: #faf6f0;
|
||||
--surface: #ffffff;
|
||||
--surface-elevated: #fffdf5;
|
||||
--border: rgba(60, 40, 20, 0.08);
|
||||
--text: #2c2a25;
|
||||
--text-dim: #7c756a;
|
||||
--accent: #c2410c;
|
||||
--accent-dim: rgba(194, 65, 12, 0.08);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #1c1916;
|
||||
--surface: #262220;
|
||||
--surface-elevated: #3a3430;
|
||||
--border: rgba(200, 180, 160, 0.08);
|
||||
--text: #f0e8dc;
|
||||
--text-dim: #a09888;
|
||||
--accent: #e85d2a;
|
||||
--accent-dim: rgba(232, 93, 42, 0.1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Terminal Mono
|
||||
|
||||
Green/amber on near-black, monospace everything. Developer-native.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'Geist Mono', 'SF Mono', Consolas, monospace;
|
||||
--font-mono: 'Geist Mono', 'SF Mono', Consolas, monospace;
|
||||
--bg: #0a0e14;
|
||||
--surface: #12161e;
|
||||
--surface-elevated: #222836;
|
||||
--border: rgba(80, 250, 123, 0.06);
|
||||
--text: #c8d6e5;
|
||||
--text-dim: #5a6a7a;
|
||||
--accent: #50fa7b;
|
||||
--accent-dim: rgba(80, 250, 123, 0.08);
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--bg: #f4f6f8;
|
||||
--surface: #ffffff;
|
||||
--border: rgba(0, 80, 40, 0.08);
|
||||
--text: #1a2332;
|
||||
--text-dim: #5a6a7a;
|
||||
--accent: #0d7a3e;
|
||||
--accent-dim: rgba(13, 122, 62, 0.08);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Background: faint dot grid. Everything monospace. CRT glow optional (CSS only, no animation).
|
||||
|
||||
### Swiss Clean
|
||||
|
||||
White, geometric sans, single bold accent, visible grid. Minimal and precise.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'DM Sans', system-ui, sans-serif;
|
||||
--font-mono: 'Fira Code', 'SF Mono', monospace;
|
||||
--bg: #ffffff;
|
||||
--surface: #f8f8f8;
|
||||
--surface-elevated: #ffffff;
|
||||
--border: rgba(0, 0, 0, 0.08);
|
||||
--text: #111111;
|
||||
--text-dim: #666666;
|
||||
--accent: #0055ff;
|
||||
--accent-dim: rgba(0, 85, 255, 0.06);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #111111;
|
||||
--surface: #1a1a1a;
|
||||
--surface-elevated: #2a2a2a;
|
||||
--border: rgba(255, 255, 255, 0.08);
|
||||
--text: #f0f0f0;
|
||||
--text-dim: #888888;
|
||||
--accent: #3b82f6;
|
||||
--accent-dim: rgba(59, 130, 246, 0.08);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Warm Signal
|
||||
|
||||
Cream paper, bold sans, terracotta accents. Confident, modern. Same as Paper/Ink but bolder.
|
||||
|
||||
Uses Plus Jakarta Sans + Azeret Mono, terracotta `#c2410c` accent. See Paper/Ink preset above — Warm Signal is the same palette with higher contrast headings and stronger section dividers.
|
||||
|
||||
---
|
||||
|
||||
## Typography Rules
|
||||
|
||||
### Font Pairings (12 options — rotate, never repeat consecutively)
|
||||
|
||||
| Body / Headings | Mono / Labels | Feel | Use for |
|
||||
|---|---|---|---|
|
||||
| DM Sans | Fira Code | Friendly, developer | Blueprint, technical docs |
|
||||
| Instrument Serif | JetBrains Mono | Editorial, refined | Plan reviews, decision logs |
|
||||
| IBM Plex Sans | IBM Plex Mono | Reliable, readable | Architecture diagrams |
|
||||
| Bricolage Grotesque | Fragment Mono | Bold, characterful | Data tables, dashboards |
|
||||
| Plus Jakarta Sans | Azeret Mono | Rounded, approachable | Status reports, audits |
|
||||
| Outfit | Space Mono | Clean geometric, modern | Flowcharts, pipelines |
|
||||
| Sora | IBM Plex Mono | Technical, precise | ER diagrams, schemas |
|
||||
| Crimson Pro | Noto Sans Mono | Scholarly, serious | RFC reviews, specs |
|
||||
| Fraunces | Source Code Pro | Warm, distinctive | Project recaps |
|
||||
| Geist | Geist Mono | Vercel-inspired, sharp | Modern API docs |
|
||||
| Red Hat Display | Red Hat Mono | Cohesive family | System overviews |
|
||||
| Libre Franklin | Inconsolata | Classic, reliable | Data-dense tables |
|
||||
|
||||
The first 5 pairings are recommended for most use cases.
|
||||
|
||||
### Load via Google Fonts
|
||||
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
Always use `display=swap` for fast rendering. Include system font fallback in `font-family` stack.
|
||||
|
||||
### Typography by Content Voice
|
||||
|
||||
For prose-heavy pages, match fonts to content voice:
|
||||
|
||||
| Voice | Fonts | Best For |
|
||||
|-------|-------|----------|
|
||||
| Literary / Thoughtful | Literata, Lora, Newsreader, Merriweather | Essays, personal posts, long-form |
|
||||
| Technical / Precise | IBM Plex Sans + Mono, Geist + Geist Mono | Documentation, READMEs, API refs |
|
||||
| Bold / Contemporary | Bricolage Grotesque, Space Grotesk, DM Sans | Product pages, announcements |
|
||||
| Minimal / Focused | Source Serif 4 + Source Sans 3, Karla + Inconsolata | Tutorials, focused reading |
|
||||
|
||||
---
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before delivering any HTML page:
|
||||
|
||||
- **Squint test**: Blur your eyes. Can you still perceive hierarchy? Are sections visually distinct?
|
||||
- **Swap test**: Would replacing fonts and colors with a generic dark theme make this indistinguishable? If yes, push the aesthetic further.
|
||||
- **Theme toggle (MANDATORY)**: Toggle button MUST be present (first child of `<body>`). Switch between light and dark using the button. Both themes should look intentional, not broken. See `html-css-patterns.md` → "Theme Toggle Button".
|
||||
- **Information completeness**: Does the page actually convey what was asked? Pretty but incomplete is a failure.
|
||||
- **No overflow**: Resize the browser. No content should clip or escape its container. Every grid/flex child needs `min-width: 0`. Side-by-side panels need `overflow-wrap: break-word`.
|
||||
- **Mermaid zoom controls**: Every `.mermaid-wrap` must have zoom controls (+/−/reset/expand), Ctrl/Cmd+scroll zoom, click-and-drag panning, and click-to-expand. See `html-css-patterns.md`.
|
||||
- **File opens cleanly**: No console errors, no broken font loads, no layout shifts.
|
||||
|
||||
---
|
||||
|
||||
## Depth Tier System
|
||||
|
||||
Vary card depth to signal importance. Hero sections dominate; reference sections stay compact.
|
||||
|
||||
```css
|
||||
/* Default — flat, no shadow */
|
||||
.ve-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
/* Elevated — KPIs, key sections */
|
||||
.ve-card--elevated {
|
||||
background: var(--surface-elevated);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* Recessed — code blocks, secondary content */
|
||||
.ve-card--recessed {
|
||||
background: color-mix(in srgb, var(--bg) 70%, var(--surface) 30%);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* Hero — executive summaries, focal elements */
|
||||
.ve-card--hero {
|
||||
background: color-mix(in srgb, var(--surface) 92%, var(--accent) 8%);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||
border-color: color-mix(in srgb, var(--border) 50%, var(--accent) 50%);
|
||||
}
|
||||
```
|
||||
|
||||
Rule: Don't make everything elevated — when everything pops, nothing does.
|
||||
|
||||
---
|
||||
|
||||
## Content-Type Routing
|
||||
|
||||
When deciding how to render content:
|
||||
|
||||
| Content type | Approach | Why |
|
||||
|---|---|---|
|
||||
| Architecture (text-heavy) | CSS Grid cards + flow arrows | Rich card content needs CSS control |
|
||||
| Architecture (topology-focused) | **Mermaid** | Visible connections need automatic edge routing |
|
||||
| Flowchart / pipeline | **Mermaid** | Automatic node positioning |
|
||||
| Sequence diagram | **Mermaid** | Lifelines need automatic layout |
|
||||
| Data flow | **Mermaid** with edge labels | Connections need auto-routing |
|
||||
| ER / schema diagram | **Mermaid** | Relationship lines between entities |
|
||||
| State machine | **Mermaid** | State transitions with labeled edges |
|
||||
| Mind map | **Mermaid** | Hierarchical branching |
|
||||
| Class diagram | **Mermaid** | Inheritance lines with auto-routing |
|
||||
| C4 architecture | **Mermaid** `graph TD` + `subgraph` | Native C4 hardcodes its own styles |
|
||||
| Data table | HTML `<table>` | Semantic markup, accessibility, copy-paste |
|
||||
| Timeline | CSS (central line + cards) | Simple linear layout |
|
||||
| Dashboard | CSS Grid + Chart.js | Card grid with embedded charts |
|
||||
| Simple A→B→C flows in slides | CSS Pipeline cards | Mermaid renders too small for simple linear flows |
|
||||
|
||||
---
|
||||
|
||||
## AI Image Generation
|
||||
|
||||
If `/ck:ai-multimodal` skill is available and image generation is appropriate, it can be used for hero banners, conceptual illustrations, and decorative accents that establish the page's visual tone.
|
||||
|
||||
**When to use:** Hero banners, conceptual illustrations for abstract systems, educational diagrams benefiting from artistic rendering, decorative accents reinforcing the aesthetic.
|
||||
|
||||
**When to skip:** Anything Mermaid or CSS handles well. Generic decoration that doesn't convey meaning. Data-heavy pages where images would distract. Always degrade gracefully — the page should stand on its own with CSS and typography alone.
|
||||
|
||||
For `--slides` presentation-grade output, consider invoking `/ck:ui-ux-pro-max` for richer style selection and distinctive font/palette pairing.
|
||||
592
.opencode/skills/preview/references/html-libraries.md
Normal file
592
.opencode/skills/preview/references/html-libraries.md
Normal file
@@ -0,0 +1,592 @@
|
||||
# External Libraries (CDN)
|
||||
|
||||
Optional CDN libraries for cases where pure CSS/HTML isn't enough. Only include what the diagram actually needs — most diagrams need zero external JS.
|
||||
|
||||
## Mermaid.js — Diagramming Engine
|
||||
|
||||
Use for flowcharts, sequence diagrams, ER diagrams, state machines, mind maps, class diagrams, and any diagram where automatic node positioning and edge routing saves effort. Mermaid handles layout — you handle theming.
|
||||
|
||||
Do NOT use for dashboards — CSS Grid card layouts with Chart.js look better for those. Data tables use `<table>` elements.
|
||||
|
||||
**CDN:**
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
|
||||
mermaid.initialize({ startOnLoad: true, /* ... */ });
|
||||
</script>
|
||||
```
|
||||
|
||||
**With ELK layout** (required for `layout: 'elk'` — it's a separate package, not bundled in core):
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import elkLayouts from 'https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs';
|
||||
|
||||
mermaid.registerLayoutLoaders(elkLayouts);
|
||||
mermaid.initialize({ startOnLoad: true, layout: 'elk', /* ... */ });
|
||||
</script>
|
||||
```
|
||||
|
||||
Without the ELK import and registration, `layout: 'elk'` silently falls back to dagre. Only import ELK when you actually need it — it adds significant bundle weight. Most simple diagrams render fine with dagre.
|
||||
|
||||
### Deep Theming
|
||||
|
||||
Always use `theme: 'base'` — it's the only theme where all `themeVariables` are fully customizable. The built-in themes (`default`, `dark`, `forest`, `neutral`) ignore most variable overrides.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
|
||||
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'base',
|
||||
look: 'classic',
|
||||
themeVariables: {
|
||||
// Background and surfaces — teal/slate palette (not violet/indigo!)
|
||||
primaryColor: isDark ? '#134e4a' : '#ccfbf1',
|
||||
primaryBorderColor: isDark ? '#14b8a6' : '#0d9488',
|
||||
primaryTextColor: isDark ? '#f0fdfa' : '#134e4a',
|
||||
secondaryColor: isDark ? '#1e293b' : '#f0fdf4',
|
||||
secondaryBorderColor: isDark ? '#059669' : '#16a34a',
|
||||
secondaryTextColor: isDark ? '#f1f5f9' : '#1e293b',
|
||||
tertiaryColor: isDark ? '#27201a' : '#fef3c7',
|
||||
tertiaryBorderColor: isDark ? '#d97706' : '#f59e0b',
|
||||
tertiaryTextColor: isDark ? '#fef3c7' : '#27201a',
|
||||
// Lines and edges
|
||||
lineColor: isDark ? '#64748b' : '#94a3b8',
|
||||
// Text
|
||||
fontSize: '16px',
|
||||
fontFamily: 'var(--font-body)',
|
||||
// Notes and labels
|
||||
noteBkgColor: isDark ? '#1e293b' : '#fefce8',
|
||||
noteTextColor: isDark ? '#f1f5f9' : '#1e293b',
|
||||
noteBorderColor: isDark ? '#fbbf24' : '#d97706',
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
**FORBIDDEN in Mermaid themeVariables:** `#8b5cf6`, `#7c3aed`, `#a78bfa` (indigo/violet), `#d946ef` (fuchsia). Use teal, slate, amber, emerald, or colors from your page's palette.
|
||||
|
||||
### CSS Overrides on Mermaid SVG
|
||||
|
||||
Mermaid renders SVG. Override its classes for pixel-perfect control that `themeVariables` can't reach:
|
||||
|
||||
```css
|
||||
/* Container — see html-css-patterns.md "Mermaid Zoom Controls" for the full zoom pattern */
|
||||
.mermaid-wrap {
|
||||
position: relative;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* CRITICAL: Force node/edge text to follow the page's color scheme.
|
||||
Without this, themeVariables.primaryTextColor works for DEFAULT nodes,
|
||||
but any classDef that sets color: will hardcode a single value that
|
||||
breaks in the opposite color scheme. Fix: never set color: in classDef,
|
||||
and always include these CSS overrides. */
|
||||
.mermaid .nodeLabel { color: var(--text) !important; }
|
||||
.mermaid .edgeLabel { color: var(--text-dim) !important; background-color: var(--bg) !important; }
|
||||
.mermaid .edgeLabel rect { fill: var(--bg) !important; }
|
||||
|
||||
/* Node shapes */
|
||||
.mermaid .node rect,
|
||||
.mermaid .node circle,
|
||||
.mermaid .node polygon {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
/* Edge paths */
|
||||
.mermaid .edge-pattern-solid {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
/* Edge labels — smaller than node labels for visual hierarchy */
|
||||
.mermaid .edgeLabel {
|
||||
font-family: var(--font-mono) !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
/* Node labels — 16px default; drop to 14px for complex diagrams (20+ nodes) */
|
||||
.mermaid .nodeLabel {
|
||||
font-family: var(--font-body) !important;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
/* Sequence diagram actors */
|
||||
.mermaid .actor {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
/* Sequence diagram messages */
|
||||
.mermaid .messageText {
|
||||
font-family: var(--font-mono) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
/* ER diagram entities */
|
||||
.mermaid .er.entityBox {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
/* Mind map nodes */
|
||||
.mermaid .mindmap-node rect {
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
```
|
||||
|
||||
### classDef and style Gotchas
|
||||
|
||||
`classDef` values and per-node `style` directives are static text inside `<pre>` — they can't use CSS variables or JS ternaries. Two rules:
|
||||
|
||||
1. **Never set `color:` in classDef or per-node `style` directives.** It hardcodes a text color that breaks in the opposite color scheme. Let the CSS overrides above handle text color via `var(--text)`.
|
||||
|
||||
2. **Use semi-transparent fills (8-digit hex) for node backgrounds.** They layer over whatever Mermaid's base theme background is, producing a tint that works in both light and dark modes. Use `20`–`44` alpha for subtle, `55`–`77` for prominent:
|
||||
|
||||
```
|
||||
classDef highlight fill:#b5761433,stroke:#b57614,stroke-width:2px
|
||||
classDef muted fill:#7c6f6411,stroke:#7c6f6444,stroke-width:1px
|
||||
```
|
||||
|
||||
### Node Label Special Characters
|
||||
|
||||
Mermaid uses certain characters for shape syntax. Node labels containing these characters cause syntax errors unless quoted.
|
||||
|
||||
**Shape characters to watch:**
|
||||
- `[/text/]` — parallelogram
|
||||
- `[(text)]` — cylindrical
|
||||
- `[[text]]` — subroutine
|
||||
- `((text))` — circle
|
||||
- `{{text}}` — hexagon
|
||||
|
||||
**If your node label starts with `/`, `\`, `(`, or `{`, wrap it in quotes:**
|
||||
|
||||
```
|
||||
%% WRONG — syntax error (/ starts parallelogram shape)
|
||||
CMD[/gallery command] --> SRV[server]
|
||||
|
||||
%% RIGHT — quotes escape the special character
|
||||
CMD["/gallery command"] --> SRV[server]
|
||||
```
|
||||
|
||||
**Edge labels with special characters also need quotes:**
|
||||
|
||||
```
|
||||
%% WRONG
|
||||
UI -->|"Use as Reference"| RET
|
||||
|
||||
%% RIGHT — use single quotes or no quotes for simple text
|
||||
UI -->|Use as Reference| RET
|
||||
```
|
||||
|
||||
Avoid opaque light fills like `fill:#fefce8` — they render as bright boxes in dark mode.
|
||||
|
||||
### stateDiagram-v2 Label Limitations
|
||||
|
||||
State diagram transition labels have a strict parser. Avoid:
|
||||
- `<br/>` — only works in flowcharts; causes a parse error in state diagrams
|
||||
- Parentheses in labels — `cancel()` can confuse the parser
|
||||
- Multiple colons — the first `:` is the label delimiter; extra colons may break parsing
|
||||
|
||||
If you need multi-line labels or special characters, use a `flowchart` instead of `stateDiagram-v2`. Flowcharts support quoted labels (`|"label with: special chars"|`) and `<br/>` for line breaks.
|
||||
|
||||
### Writing Valid Mermaid
|
||||
|
||||
Most Mermaid failures come from a few recurring issues.
|
||||
|
||||
**For multi-line flowchart node labels, use `<br/>` (not `\n`):**
|
||||
|
||||
```
|
||||
%% WRONG — renders literal "\n" in node text
|
||||
A["Copilot Backend\n/api + /api/voicebot"] --> B["Redis"]
|
||||
|
||||
%% RIGHT — renders on two lines
|
||||
A["Copilot Backend<br/>/api + /api/voicebot"] --> B["Redis"]
|
||||
```
|
||||
|
||||
**Quote labels with special characters.** Parentheses, colons, commas, brackets, and ampersands break the parser when unquoted:
|
||||
|
||||
```
|
||||
A["handleRequest(ctx)"] --> B["DB: query users"]
|
||||
A[handleRequest] --> B[query users]
|
||||
```
|
||||
|
||||
**Keep IDs simple.** Node IDs should be alphanumeric with no spaces or punctuation:
|
||||
|
||||
```
|
||||
userSvc["User Service"] --> authSvc["Auth Service"]
|
||||
```
|
||||
|
||||
**Max 10-12 nodes per Mermaid diagram.** Beyond that, readability collapses even with zoom controls. For complex architectures (15+ elements), use the **hybrid pattern**: a simple 5-8 node Mermaid overview showing module relationships, followed by CSS Grid cards with detailed function lists.
|
||||
|
||||
```
|
||||
subgraph Auth
|
||||
login --> validate --> token
|
||||
end
|
||||
subgraph API
|
||||
gateway --> router --> handler
|
||||
end
|
||||
Auth --> API
|
||||
```
|
||||
|
||||
**Arrow styles for semantic meaning:**
|
||||
|
||||
| Arrow | Meaning | Use for |
|
||||
|-------|---------|---------|
|
||||
| `-->` | Solid | Primary flow |
|
||||
| `-.->` | Dotted | Optional, async, or fallback paths |
|
||||
| `==>` | Thick | Critical or highlighted path |
|
||||
| `--x` | Cross | Rejected or blocked |
|
||||
| `-->\|label\|` | Labeled | Decision branches, data descriptions |
|
||||
|
||||
**Sequence diagram messages must be plain text.** Unlike flowchart labels, sequence diagram messages cannot be quoted or escaped. Curly braces `{}`, square brackets `[]`, angle brackets `<>`, and `&` will silently break the parser:
|
||||
|
||||
```
|
||||
%% WRONG — parser chokes on braces, brackets, ampersand
|
||||
A->>B: web_search({ queries: [...] })
|
||||
B->>B: User removes query 2, keeps 1 & 3
|
||||
|
||||
%% RIGHT — plain English, no special characters
|
||||
A->>B: Call web_search with queries
|
||||
B->>B: User removes query 2, keeps 1 and 3
|
||||
```
|
||||
|
||||
### Layout Direction: TD vs LR
|
||||
|
||||
`flowchart LR` (left-to-right) spreads horizontally. With many nodes, Mermaid scales everything down to fit the width, making text unreadable. `flowchart TD` (top-down) is almost always better.
|
||||
|
||||
| Direction | Use when | Avoid when |
|
||||
|-----------|----------|------------|
|
||||
| `TD` (top-down) | Complex diagrams, 5+ nodes, hierarchies | Simple A→B→C linear flows |
|
||||
| `LR` (left-to-right) | Simple linear flows, 3-4 nodes | Complex graphs, many branches |
|
||||
|
||||
**Rule of thumb:** If the diagram has more than one row of nodes or any branching, use `TD`.
|
||||
|
||||
### Diagram Type Examples
|
||||
|
||||
**Flowchart with decisions:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
graph TD
|
||||
A[Request] --> B{Authenticated?}
|
||||
B -->|Yes| C[Load Dashboard]
|
||||
B -->|No| D[Login Page]
|
||||
D --> E[Submit Credentials]
|
||||
E --> B
|
||||
C --> F{Role?}
|
||||
F -->|Admin| G[Admin Panel]
|
||||
F -->|User| H[User Dashboard]
|
||||
</pre>
|
||||
```
|
||||
|
||||
**Sequence diagram:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant C as Client
|
||||
participant G as Gateway
|
||||
participant S as Service
|
||||
participant D as Database
|
||||
C->>G: POST /api/data
|
||||
G->>G: Validate JWT
|
||||
G->>S: Forward request
|
||||
S->>D: Query
|
||||
D-->>S: Results
|
||||
S-->>G: Response
|
||||
G-->>C: 200 OK
|
||||
</pre>
|
||||
```
|
||||
|
||||
**ER diagram:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
erDiagram
|
||||
USERS ||--o{ ORDERS : places
|
||||
ORDERS ||--|{ LINE_ITEMS : contains
|
||||
LINE_ITEMS }o--|| PRODUCTS : references
|
||||
USERS { string email PK }
|
||||
ORDERS { int id PK }
|
||||
LINE_ITEMS { int quantity }
|
||||
PRODUCTS { string name }
|
||||
</pre>
|
||||
```
|
||||
|
||||
**State diagram:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
stateDiagram-v2
|
||||
[*] --> Draft
|
||||
Draft --> Review : submit
|
||||
Review --> Approved : approve
|
||||
Review --> Draft : request_changes
|
||||
Approved --> Published : publish
|
||||
Published --> Archived : archive
|
||||
Archived --> [*]
|
||||
</pre>
|
||||
```
|
||||
|
||||
**Mind map:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
mindmap
|
||||
root((Project))
|
||||
Frontend
|
||||
React
|
||||
Next.js
|
||||
Tailwind
|
||||
Backend
|
||||
Node.js
|
||||
PostgreSQL
|
||||
Redis
|
||||
Infrastructure
|
||||
AWS
|
||||
Docker
|
||||
Terraform
|
||||
</pre>
|
||||
```
|
||||
|
||||
**Class diagram:**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class User {
|
||||
+string email
|
||||
+string name
|
||||
+login()
|
||||
+logout()
|
||||
}
|
||||
class Order {
|
||||
+int id
|
||||
+decimal total
|
||||
+submit()
|
||||
}
|
||||
class Product {
|
||||
+string name
|
||||
+decimal price
|
||||
}
|
||||
User "1" --> "*" Order : places
|
||||
Order "*" --> "*" Product : contains
|
||||
</pre>
|
||||
```
|
||||
|
||||
**C4 architecture (flowchart-as-C4):**
|
||||
```html
|
||||
<pre class="mermaid">
|
||||
graph TD
|
||||
user("User<br/><small>Browser client</small>")
|
||||
subgraph boundary["Web Platform"]
|
||||
app["Web App<br/><small>Node.js</small>"]
|
||||
db[("Database<br/><small>PostgreSQL</small>")]
|
||||
end
|
||||
email["Email Service"]:::ext
|
||||
payment["Payment Gateway"]:::ext
|
||||
user -->|"HTTPS"| app
|
||||
app -->|"SQL"| db
|
||||
app -->|"SMTP"| email
|
||||
app -->|"API"| payment
|
||||
classDef ext fill:none,stroke-dasharray:5 5
|
||||
</pre>
|
||||
```
|
||||
|
||||
Do NOT use native `C4Context` / `C4Container` syntax — it hardcodes sharp corners, its own font, and inline colors that ignore `themeVariables`. Use `graph TD` + `subgraph` for C4 boundaries instead.
|
||||
|
||||
### Which Mermaid Diagram Type?
|
||||
|
||||
| You want to show... | Use | Syntax keyword |
|
||||
|---|---|---|
|
||||
| Process flow, decisions, pipelines | Flowchart | `graph TD` / `graph LR` |
|
||||
| Request/response, API calls, temporal interactions | Sequence diagram | `sequenceDiagram` |
|
||||
| Database tables and relationships | ER diagram | `erDiagram` |
|
||||
| OOP classes, domain models with methods | Class diagram | `classDiagram` |
|
||||
| System architecture at multiple zoom levels | C4 diagram | `graph TD` + `subgraph` |
|
||||
| State transitions, lifecycles | State diagram | `stateDiagram-v2` |
|
||||
| Hierarchical breakdowns, brainstorms | Mind map | `mindmap` |
|
||||
|
||||
### Dark Mode Handling
|
||||
|
||||
Mermaid initializes once — it can't reactively switch themes. Read the preference at load time inside your `<script type="module">`:
|
||||
|
||||
```javascript
|
||||
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
// Use isDark to pick light or dark values in themeVariables
|
||||
```
|
||||
|
||||
The CSS overrides on the container (`.mermaid-wrap`) and page will still respond to `prefers-color-scheme` normally — only the Mermaid SVG internals are static.
|
||||
|
||||
---
|
||||
|
||||
## Chart.js — Data Visualizations
|
||||
|
||||
Use for bar charts, line charts, pie/doughnut charts, radar charts, and other data-driven visualizations in dashboard-type diagrams. Overkill for static numbers — use pure SVG/CSS for simple progress bars and sparklines.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
||||
|
||||
<canvas id="myChart" width="600" height="300"></canvas>
|
||||
|
||||
<script>
|
||||
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const textColor = isDark ? '#8b949e' : '#6b7280';
|
||||
const gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
|
||||
const fontFamily = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--font-body').trim() || 'system-ui, sans-serif';
|
||||
|
||||
new Chart(document.getElementById('myChart'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
|
||||
datasets: [{
|
||||
label: 'Feedback Items',
|
||||
data: [45, 62, 78, 91, 120],
|
||||
backgroundColor: isDark ? 'rgba(129, 140, 248, 0.6)' : 'rgba(79, 70, 229, 0.6)',
|
||||
borderColor: isDark ? '#818cf8' : '#4f46e5',
|
||||
borderWidth: 1,
|
||||
borderRadius: 4,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { labels: { color: textColor, font: { family: fontFamily } } },
|
||||
},
|
||||
scales: {
|
||||
x: { ticks: { color: textColor, font: { family: fontFamily } }, grid: { color: gridColor } },
|
||||
y: { ticks: { color: textColor, font: { family: fontFamily } }, grid: { color: gridColor } },
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
Wrap the canvas in a styled container:
|
||||
```css
|
||||
.chart-container {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart-container canvas {
|
||||
max-height: 300px;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## anime.js — Orchestrated Animations
|
||||
|
||||
Use when a diagram has 10+ elements and you want a choreographed entrance sequence (staggered reveals, path drawing, count-up numbers). For simpler diagrams, CSS `animation-delay` staggering is sufficient.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/animejs@3.2.2/lib/anime.min.js"></script>
|
||||
|
||||
<script>
|
||||
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
if (!prefersReduced) {
|
||||
anime({
|
||||
targets: '.ve-card',
|
||||
opacity: [0, 1],
|
||||
translateY: [20, 0],
|
||||
delay: anime.stagger(80, { start: 200 }),
|
||||
easing: 'easeOutCubic',
|
||||
duration: 500,
|
||||
});
|
||||
|
||||
anime({
|
||||
targets: '.connector path',
|
||||
strokeDashoffset: [anime.setDashoffset, 0],
|
||||
easing: 'easeInOutCubic',
|
||||
duration: 800,
|
||||
delay: anime.stagger(150, { start: 600 }),
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-count]').forEach(el => {
|
||||
anime({
|
||||
targets: { val: 0 },
|
||||
val: parseInt(el.dataset.count),
|
||||
round: 1,
|
||||
duration: 1200,
|
||||
delay: 400,
|
||||
easing: 'easeOutExpo',
|
||||
update: (anim) => { el.textContent = anim.animations[0].currentValue; }
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
When using anime.js, set initial opacity to 0 in CSS so elements don't flash before the animation:
|
||||
```css
|
||||
.ve-card { opacity: 0; }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.ve-card { opacity: 1 !important; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Google Fonts — Typography
|
||||
|
||||
Always load with `display=swap` for fast rendering. Pick a distinctive pairing — body + mono at minimum, optionally a display font for the title.
|
||||
|
||||
**FORBIDDEN as `--font-body` (AI slop signals):**
|
||||
- Inter — the single most overused AI default font
|
||||
- Roboto — generic Android/Google default
|
||||
- Arial, Helvetica — system defaults with no character
|
||||
- system-ui alone without a named font — signals zero design intent
|
||||
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
Define as CSS variables for easy reference:
|
||||
```css
|
||||
:root {
|
||||
--font-body: 'Outfit', system-ui, sans-serif;
|
||||
--font-mono: 'Space Mono', 'SF Mono', Consolas, monospace;
|
||||
}
|
||||
```
|
||||
|
||||
**Font pairings** (rotate — never use the same pairing twice in a row):
|
||||
|
||||
| Body / Headings | Mono / Labels | Feel | Use for |
|
||||
|---|---|---|---|
|
||||
| DM Sans | Fira Code | Friendly, developer | Blueprint, technical docs |
|
||||
| Instrument Serif | JetBrains Mono | Editorial, refined | Plan reviews, decision logs |
|
||||
| IBM Plex Sans | IBM Plex Mono | Reliable, readable | Architecture diagrams |
|
||||
| Bricolage Grotesque | Fragment Mono | Bold, characterful | Data tables, dashboards |
|
||||
| Plus Jakarta Sans | Azeret Mono | Rounded, approachable | Status reports, audits |
|
||||
| Outfit | Space Mono | Clean geometric, modern | Flowcharts, pipelines |
|
||||
| Sora | IBM Plex Mono | Technical, precise | ER diagrams, schemas |
|
||||
| Crimson Pro | Noto Sans Mono | Scholarly, serious | RFC reviews, specs |
|
||||
| Fraunces | Source Code Pro | Warm, distinctive | Project recaps |
|
||||
| Geist | Geist Mono | Vercel-inspired, sharp | Modern API docs |
|
||||
| Red Hat Display | Red Hat Mono | Cohesive family | System overviews |
|
||||
| Libre Franklin | Inconsolata | Classic, reliable | Data-dense tables |
|
||||
| Playfair Display | Roboto Mono | Elegant contrast | Executive summaries |
|
||||
|
||||
The first 5 pairings are recommended for most use cases. Vary across consecutive diagrams.
|
||||
|
||||
### Typography by Content Voice
|
||||
|
||||
For prose-heavy pages (documentation, articles, essays), match typography to the content's voice:
|
||||
|
||||
| Voice | Fonts | Best For |
|
||||
|-------|-------|----------|
|
||||
| **Literary / Thoughtful** | Literata, Lora, Newsreader, Merriweather | Essays, personal posts, long-form articles |
|
||||
| **Technical / Precise** | IBM Plex Sans + Mono, Geist + Geist Mono, Source family | Documentation, READMEs, API references |
|
||||
| **Bold / Contemporary** | Bricolage Grotesque, Space Grotesk, DM Sans | Product pages, feature announcements |
|
||||
| **Minimal / Focused** | Source Serif 4 + Source Sans 3, Karla + Inconsolata | Tutorials, how-tos, focused reading |
|
||||
|
||||
**Literata** deserves special mention — it has optical sizing designed specifically for screen reading. Google's answer to Georgia, but modernized.
|
||||
212
.opencode/skills/preview/references/html-responsive-nav.md
Normal file
212
.opencode/skills/preview/references/html-responsive-nav.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# Responsive Section Navigation
|
||||
|
||||
Navigation pattern for multi-section pages (reviews, recaps, dashboards). Provides a sticky sidebar TOC on desktop and a sticky horizontal scrollable bar on mobile.
|
||||
|
||||
## Layout Structure
|
||||
|
||||
The page uses a two-column CSS Grid: sidebar (TOC) + main content. On mobile it collapses to single-column with the TOC becoming a horizontal bar.
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<nav class="toc" id="toc">
|
||||
<div class="toc-title">Contents</div>
|
||||
<a href="#s1">1. First Section</a>
|
||||
<a href="#s2">2. Second Section</a>
|
||||
<!-- one link per section -->
|
||||
</nav>
|
||||
|
||||
<div class="main">
|
||||
<h1>Page Title</h1>
|
||||
<p class="subtitle">Subtitle text</p>
|
||||
|
||||
<div id="s1" class="sec-head ...">1 — First Section</div>
|
||||
<!-- section content -->
|
||||
|
||||
<div id="s2" class="sec-head ...">2 — Second Section</div>
|
||||
<!-- section content -->
|
||||
</div><!-- /main -->
|
||||
|
||||
</div><!-- /wrap -->
|
||||
</body>
|
||||
```
|
||||
|
||||
Key structural rules:
|
||||
- `<nav class="toc">` is the **first child** of `.wrap`
|
||||
- All page content goes inside `<div class="main">`
|
||||
- Every section heading gets an `id="s1"`, `id="s2"`, etc.
|
||||
- TOC links use `href="#s1"` matching those IDs
|
||||
- Keep TOC link text short (truncate long section names)
|
||||
|
||||
## CSS
|
||||
|
||||
### Wrap (grid layout)
|
||||
|
||||
```css
|
||||
.wrap {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 170px 1fr;
|
||||
gap: 0 40px;
|
||||
}
|
||||
.main { min-width: 0; }
|
||||
```
|
||||
|
||||
### TOC — Desktop (sticky sidebar)
|
||||
|
||||
```css
|
||||
.toc {
|
||||
position: sticky;
|
||||
top: 24px;
|
||||
align-self: start;
|
||||
padding: 14px 0;
|
||||
grid-row: 1 / -1;
|
||||
max-height: calc(100dvh - 48px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.toc::-webkit-scrollbar { width: 3px; }
|
||||
.toc::-webkit-scrollbar-thumb { background: var(--surface-elevated); border-radius: 2px; }
|
||||
|
||||
.toc-title {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: var(--text-dim);
|
||||
padding: 0 0 10px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.toc a {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: var(--text-dim);
|
||||
text-decoration: none;
|
||||
padding: 4px 8px;
|
||||
border-radius: 5px;
|
||||
border-left: 2px solid transparent;
|
||||
transition: all 0.15s;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.toc a:hover { color: var(--text); background: var(--surface2); }
|
||||
.toc a.active { color: var(--text); border-left-color: var(--accent); }
|
||||
```
|
||||
|
||||
Replace `var(--accent)` with your page's primary accent color variable (e.g., `var(--orange)`, `var(--blue)`).
|
||||
|
||||
### TOC — Mobile (sticky horizontal bar)
|
||||
|
||||
```css
|
||||
@media (max-width: 1000px) {
|
||||
.wrap { grid-template-columns: 1fr; padding-top: 0; }
|
||||
body { padding-top: 0; }
|
||||
|
||||
.toc {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 200;
|
||||
max-height: none;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: var(--bg);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 10px 0;
|
||||
margin: 0 -40px;
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
grid-row: auto;
|
||||
}
|
||||
.toc::-webkit-scrollbar { display: none; }
|
||||
.toc-title { display: none; }
|
||||
|
||||
.toc a {
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
border-left: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
border-radius: 4px 4px 0 0;
|
||||
padding: 6px 10px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.toc a.active {
|
||||
border-left: none;
|
||||
border-bottom-color: var(--accent);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.main { padding-top: 20px; }
|
||||
|
||||
/* Offset scroll target so headings clear the sticky bar */
|
||||
.sec-head { scroll-margin-top: 52px; }
|
||||
}
|
||||
```
|
||||
|
||||
Adjust `margin: 0 -40px` and `padding-left/right: 40px` to match your `body` padding so the bar bleeds edge-to-edge.
|
||||
|
||||
## JavaScript — Scroll Spy
|
||||
|
||||
Place before `</body>`, after any Mermaid init:
|
||||
|
||||
```html
|
||||
<script>
|
||||
(function() {
|
||||
const toc = document.getElementById('toc');
|
||||
const links = toc.querySelectorAll('a');
|
||||
const sections = [];
|
||||
|
||||
links.forEach(link => {
|
||||
const id = link.getAttribute('href').slice(1);
|
||||
const el = document.getElementById(id);
|
||||
if (el) sections.push({ id, el, link });
|
||||
});
|
||||
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
links.forEach(l => l.classList.remove('active'));
|
||||
const match = sections.find(s => s.el === entry.target);
|
||||
if (match) {
|
||||
match.link.classList.add('active');
|
||||
// On mobile, auto-scroll the active tab into view
|
||||
if (window.innerWidth <= 1000) {
|
||||
match.link.scrollIntoView({
|
||||
behavior: 'smooth', block: 'nearest', inline: 'center'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '-10% 0px -80% 0px' });
|
||||
|
||||
sections.forEach(s => observer.observe(s.el));
|
||||
|
||||
links.forEach(link => {
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
const id = link.getAttribute('href').slice(1);
|
||||
const el = document.getElementById(id);
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
history.replaceState(null, '', '#' + id);
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
## Adaptation Notes
|
||||
|
||||
- The `.toc-title` text, link labels, accent color, and section IDs change per page. Everything else is copy-paste.
|
||||
- For pages with fewer than 4 sections, skip the TOC entirely — it adds clutter without value.
|
||||
- The `grid-template-columns: 170px 1fr` width works for most TOCs. If section names are longer, go up to `200px`.
|
||||
- The `rootMargin: '-10% 0px -80% 0px'` means a section is "active" when its heading enters the top 10-20% of the viewport. This works well with sticky headers.
|
||||
- On mobile, the horizontal bar uses `overflow-x: auto` with hidden scrollbar. The active tab auto-scrolls into the center of the bar as the user scrolls the page.
|
||||
1401
.opencode/skills/preview/references/html-slide-patterns.md
Normal file
1401
.opencode/skills/preview/references/html-slide-patterns.md
Normal file
File diff suppressed because it is too large
Load Diff
42
.opencode/skills/preview/references/view-mode.md
Normal file
42
.opencode/skills/preview/references/view-mode.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# View Mode
|
||||
|
||||
## Execution
|
||||
|
||||
**IMPORTANT:** Run server as Claude Code background task using `run_in_background: true` with the Bash tool.
|
||||
|
||||
The skill is located at `.opencode/skills/markdown-novel-viewer/`.
|
||||
|
||||
### Stop Server
|
||||
|
||||
If `--stop` flag is provided:
|
||||
|
||||
```bash
|
||||
node .opencode/skills/markdown-novel-viewer/scripts/server.cjs --stop
|
||||
```
|
||||
|
||||
### Start Server
|
||||
|
||||
Run the `markdown-novel-viewer` server as CC background task with `--foreground` flag:
|
||||
|
||||
```bash
|
||||
INPUT_PATH="<resolved-path>"
|
||||
if [[ -d "$INPUT_PATH" ]]; then
|
||||
node .opencode/skills/markdown-novel-viewer/scripts/server.cjs \
|
||||
--dir "$INPUT_PATH" --host 0.0.0.0 --open --foreground
|
||||
else
|
||||
node .opencode/skills/markdown-novel-viewer/scripts/server.cjs \
|
||||
--file "$INPUT_PATH" --host 0.0.0.0 --open --foreground
|
||||
fi
|
||||
```
|
||||
|
||||
**Critical:** When calling the Bash tool:
|
||||
- Set `run_in_background: true`
|
||||
- Set `timeout: 300000` (5 minutes)
|
||||
- Parse JSON output and report URL to user
|
||||
|
||||
After starting, report:
|
||||
- Local URL for browser access
|
||||
- Network URL for remote device access
|
||||
- Inform user that server is now running as CC background task (visible in `/tasks`)
|
||||
|
||||
**CRITICAL:** MUST display the FULL URL including path and query string. NEVER truncate to just `host:port`.
|
||||
Reference in New Issue
Block a user