Explainer Site Skill

SkillWeb & browsing

Create "How X Works" deep-dive explainer websites with the curious, technical-but-accessible style of howkeyboardswork.com. Use when asked to explain how something works, create an educational single-page guide, or build an interactive explainer site on any topic.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Explainer Site Skill skill

What this skill tells your AI

The instructions your AI receives, as published by drpedapati/sciclaw in skills/explainer-site/SKILL.md and read by ahel’s review.

Create deep-dive, single-page explainer websites in the style of howkeyboardswork.com — technically rigorous but accessible, personal yet authoritative, with progressive disclosure from overview to implementation details.

Key Insight: The magic is in three things: (1) personal voice that invites exploration, (2) pipeline thinking that shows the journey, and (3) beautiful Mermaid diagrams that explain visually what words struggle to convey.

When to Use This Skill

Trigger phrases:

  • "Create a 'How X Works' site"
  • "Build an explainer page for..."
  • "I want a deep-dive guide on..."
  • "Make a site like howkeyboardswork.com but for..."
  • "Educational single-page site about..."

The Formula

This pattern works for any technical topic: keyboards, databases, compilers, HTTP, neural networks, coffee machines, refrigerators, etc. The magic is in the combination of personal voice, progressive depth, and pipeline thinking.


Reference Examples

Study these implementations before building your own:

Inspiration

  • howkeyboardswork.com — The gold standard. Personal voice, pipeline thinking, interactive toys, beautiful diagrams. Study the opening hook, the section rhythm, and how it balances accessibility with depth.

Working Demo

  • how-memory-works — A complete implementation of this skill pattern, explaining how AI memory systems work.
    • Stack: Nuxt 4 + TailwindCSS + beautiful-mermaid
    • Features: 4 interactive SVG toys (MemoryPipeline, ContextWindow, SearchSequence, HeartbeatState)
    • Design: Monochrome by default, substantial figure captions, prose-first
    • Clone it, run npm install && npm run dev, and explore the code

Use the demo as a starting point. Copy the project structure, component patterns, and diagram setup. Replace the content with your topic.


Voice & Tone Guidelines

The Opening Hook

Start with genuine personal curiosity. This establishes credibility through passion, not credentials.

Pattern:

I'm obsessed with [TOPIC] and the [ASPECT] we [USE/ENCOUNTER] every day without thinking twice about.
We [ACTION] [FREQUENCY], yet most of us have no idea what actually happens [BEHIND THE SCENES DESCRIPTION].
I wanted to figure out how all of that worked — [LIST KEY COMPONENTS] — and decided to document what I learned on this site.
It's been a way to deepen my own understanding and hopefully make it easier for others to appreciate the [QUALITY] behind something we all [USE/TAKE FOR GRANTED].
Let's go deep. [RELEVANT EMOJI]

Example for databases:

I'm obsessed with databases and the invisible infrastructure we rely on every day without thinking twice about.
We query data billions of times a day, yet most of us have no idea what actually happens between typing SELECT and seeing results.
I wanted to figure out how all of that worked — the parsing, the query planning, the storage engines, the whole stack — and decided to document what I learned on this site.
It's been a way to deepen my own understanding and hopefully make it easier for others to appreciate the quiet engineering behind something we all depend on.
Let's go deep. 🗄️

Tone Principles

  1. First-person, conversational — "I wanted to figure out", "Let's explore"
  2. Invitational, not lecturing — "Let's go deep" not "This guide will teach you"
  3. Technical precision with plain language — Define jargon on first use
  4. Genuine curiosity — Share your "aha" moments
  5. Progressive confidence — Start accessible, get technical
  6. Practical grounding — Connect abstractions to real-world effects

Sentence Style

  • Short sentences for impact
  • Longer sentences for explanation, then short for punch
  • Use em-dashes for asides (in this style, they work)
  • Parenthetical examples: "(e.g., Cherry MX Red)"
  • Questions to transition: "But how does the controller know which key?"

Content Structure

1. The Pipeline Overview

Every complex system is a pipeline — a chain of transformations from input to output. Start by showing the full journey, then zoom into each stage.

Pattern:

## The [TOPIC] Pipeline
From [INPUT] to [OUTPUT] — the journey of a [UNIT]

When you [ACTION], it feels instantaneous. But between [START STATE] and [END STATE],
an intricate chain of events unfolds in [TIMEFRAME].

This guide walks you through every step of that journey. We'll explore [COMPONENT 1],
[COMPONENT 2], [COMPONENT 3], and finally [COMPONENT N].

Understanding this pipeline helps you appreciate why [INSIGHT 1], why [INSIGHT 2],
and how [INSIGHT 3].

[OPTIONAL: Interactive visualization description]
The entire journey typically takes [TIME RANGE].

2. Section Template

Each section follows a consistent pattern:

## [Component Name]
[One-line evocative description]

[Opening paragraph: What is this component? Why does it exist? Hook the reader.]

## [Subsection: Core Concept]
[Detailed explanation of the main idea]

## [Subsection: Variations/Types]
[Different implementations or categories]
- **Type A**: [Description] (e.g., [Example])
- **Type B**: [Description] (e.g., [Example])
- **Type C**: [Description] (e.g., [Example])

## [Subsection: The Problem This Solves]
[What would go wrong without this? Real consequences.]

## [Subsection: Real-World Considerations]
[How does this play out in practice? Trade-offs, tuning, edge cases.]

[OPTIONAL: Callout box for important aside]
[OPTIONAL: Source attribution for images/data]

3. Section Ordering

Sections should follow the pipeline flow — the natural order of data/events through the system:

  1. Physical/Input Layer — Where the journey begins
  2. Conversion/Translation — How raw input becomes structured
  3. Processing/Logic — The core transformation
  4. Communication/Protocol — How information moves between components
  5. Output/Delivery — How results reach the end user
  6. Meta Concerns — Latency, measurement, optimization

4. Practical Commands Section (Optional)

For systems/tools that users can configure, add a "Configuring the System" section with:

  1. File structure — Show the workspace layout in a code block
  2. Commands table — Natural language triggers and what they do
  3. Configuration examples — Real config file snippets
  4. Quick reference table — Summary of files/commands for scanning
<div class="not-prose my-4">
  <table class="w-full text-sm border border-slate-200 rounded">
    <thead class="bg-slate-50">
      <tr>
        <th class="text-left p-3 border-b font-medium">Command</th>
        <th class="text-left p-3 border-b font-medium">What it does</th>
      </tr>
    </thead>
    <tbody>
      <tr class="border-b border-slate-100">
        <td class="p-3 font-mono text-xs">"Remember that..."</td>
        <td class="p-3">Writes to daily notes</td>
      </tr>
    </tbody>
  </table>
</div>

This section shifts from "how it works" to "how to use it" while maintaining the same voice.

5. The Closing

End with satisfaction and a soft call-to-action (if relevant):

## And That's How [TOPIC] Work[s]!

From [START] through [MIDDLE COMPONENTS] to [END] — every [UNIT] is a small engineering marvel.

[OPTIONAL: Soft CTA to related product/project]
Now that you know the journey each [UNIT] takes, you might start wondering — [RELATED QUESTION]?

[Product/Tool Name] [DOES SOMETHING RELATED], turning [INVISIBLE THING] into [VISIBLE BENEFIT].
It's a [POSITIVE FRAMING] way to [BENEFIT].

[CTA Button Text]

Technical Implementation

Tech Stack

The reference implementation uses:

  • Nuxt 3 (Vue.js framework)
  • TailwindCSS with @tailwindcss/typography
  • @nuxt/content for markdown content
  • Static generation (Cloudflare Pages/Workers)

Project Structure

├── assets/css/           # Global styles (tailwind.css)
├── components/
│   ├── base/             # Reusable UI (Button, Card, etc.)
│   ├── content/          # Markdown components (Callout, etc.)
│   └── toys/             # Interactive demos/visualizations
├── content/guide/        # Markdown content files
│   ├── 00-intro.md
│   ├── 01-pipeline.md
│   ├── 02-component-a.md
│   ├── 03-component-b.md
│   └── ...
├── layouts/              # App layouts
├── pages/                # Route pages
│   └── index.vue         # Single-page that renders all sections
├── public/               # Static assets (images, og-image.jpg)
├── nuxt.config.ts        # Nuxt configuration
├── tailwind.config.ts    # Tailwind configuration
└── package.json

Markdown Frontmatter

Each section is a markdown file with frontmatter:

---
title: Section Title
description: Brief evocative description (shown as subtitle)
order: 2
slug: section-slug
---

Sections are automatically sorted by order and rendered sequentially on the homepage.

Tailwind Typography Config

Use @tailwindcss/typography for beautiful prose styling:

// tailwind.config.ts
export default {
  theme: {
    extend: {
      colors: {
        primary: {
          500: '#0ea5e9',  // Main accent
          600: '#0284c7',  // Links
          700: '#0369a1',  // Hover
        }
      },
      typography: {
        DEFAULT: {
          css: {
            maxWidth: 'none',
            color: '#374151',
            a: {
              color: '#0284c7',
              textDecoration: 'none',
              '&:hover': { textDecoration: 'underline' }
            },
            code: {
              backgroundColor: '#f3f4f6',
              padding: '0.25rem 0.375rem',
              borderRadius: '0.25rem',
              fontWeight: '400'
            }
          }
        }
      }
    }
  },
  plugins: [require('@tailwindcss/typography')]
}

Custom Components

Create reusable content components for markdown:

Callout Component (components/content/Callout.vue):

<template>
  <div :class="['callout', `callout-${type}`]">
    <div class="callout-title">{{ title }}</div>
    <div class="callout-content">
      <slot />
    </div>
  </div>
</template>

<script setup>
defineProps({
  title: String,
  type: { type: String, default: 'info' }  // info, warning, tip
})
</script>

Usage in markdown:

::Callout{title="Important Note" type="info"}
The actuation point is usually higher than the bottom-out point.
::

Header Design (The Frosted Glass Pattern)

The header should be minimal, functional, and elegant. Study howkeyboardswork.com's header — it's a masterclass in restraint.

The Complete Pattern

<header class="sticky top-0 z-50 bg-white/80 backdrop-blur-sm border-b border-gray-200">
  <div class="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
    <!-- Logo + Title (left) -->
    <a href="/" class="flex items-center gap-2 font-semibold text-lg text-gray-900 hover:text-sky-600 transition-colors">
      <img src="/favicon.svg" alt="" class="w-auto h-8">
      Site Title
    </a>

    <!-- Utility Link (right) -->
    <a href="https://github.com/..."
       target="_blank"
       rel="noopener noreferrer"
       class="text-sm text-gray-600 hover:text-gray-900 transition-colors">
      View Source
    </a>
  </div>
</header>

Key Techniques

ElementClassesPurpose
Frosted glassbg-white/80 backdrop-blur-sm80% white + blur = content visible but unreadable
Sticky behaviorsticky top-0 z-50Stays on top during scroll
Subtle borderborder-b border-gray-200Definition without heaviness
Logo sizeh-8 (32px)Visible but not dominating
Logo gapgap-2 (8px)Breathing room between icon and text
Layoutflex items-center justify-betweenLogo left, utility right

Vue Component

<template>
  <header class="sticky top-0 z-50 bg-white/80 backdrop-blur-sm border-b border-gray-200">
    <div class="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
      <NuxtLink to="/" class="flex items-center gap-2 font-semibold text-lg text-gray-900 hover:text-sky-600 transition-colors">
        <img src="/favicon.svg" alt="" class="w-auto h-8">
        {{ title }}
      </NuxtLink>

      <a
        v-if="sourceUrl"
        :href="sourceUrl"
        target="_blank"
        rel="noopener noreferrer"
        class="text-sm text-gray-600 hover:text-gray-900 transition-colors"
      >
        View Source
      </a>
    </div>
  </header>
</template>

<script setup>
defineProps({
  title: { type: String, required: true },
  sourceUrl: { type: String, default: null }
})
</script>

What NOT to Put in the Header

  • No navigation dropdowns — Single-page explainer uses sidebar TOC
  • No social icons — Footer, if anywhere
  • No search bar — Cmd+F works for single-page sites
  • No heavy shadows — Frosted glass + border is enough
  • No large logosh-8 (32px) is plenty

Dark Mode Variant

<header class="sticky top-0 z-50 bg-slate-900/80 backdrop-blur-sm border-b border-slate-700">
  <!-- Same structure, different colors -->
</header>

Beautiful Mermaid Diagrams (Critical!)

Diagrams are not optional. The reference sites use extensive visualizations to explain concepts. Use beautiful-mermaid (not plain mermaid) for professional, themed SVG output.

Why beautiful-mermaid?

  • 15 built-in themes (tokyo-night, nord, dracula, github-light, etc.)
  • Simple two-color theming system
  • Clean SVG output
  • Works in browser via CDN

Setup (CDN - Recommended for Nuxt/Vue)

Dynamic imports don't work reliably client-side. Use the CDN approach:

// In your component's script setup
useHead({
  script: [
    {
      src: 'https://unpkg.com/beautiful-mermaid/dist/beautiful-mermaid.browser.global.js',
      defer: true
    }
  ]
})

Rendering Diagrams

// Define your diagrams
const diagrams = {
  pipeline: `graph LR
    A[Input] --> B[Process]
    B --> C[Output]`,
  // ... more diagrams
}

// Theme that matches your page design
const theme = {
  bg: '#f8fafc',      // Match page background
  fg: '#1e293b',      // Match text color
  accent: '#3b82f6',  // Your primary color
  muted: '#64748b',   // Secondary text
  surface: '#e2e8f0', // Node fills
  border: '#cbd5e1'   // Node borders
}

onMounted(() => {
  // Wait for CDN script to load
  const checkAndRender = () => {
    if (typeof window.beautifulMermaid !== 'undefined') {
      const { renderMermaid } = window.beautifulMermaid

      const renderDiagram = async (id, code) => {
        try {
          const svg = await renderMermaid(code, theme)
          const el = document.getElementById(id)
          if (el) el.innerHTML = svg
        } catch (e) {
          console.error(`Error rendering ${id}:`, e)
        }
      }

      // Render all diagrams
      renderDiagram('diagram-pipeline', diagrams.pipeline)
      // ... render others
    } else {
      setTimeout(checkAndRender, 100)  // Retry until loaded
    }
  }

  checkAndRender()
})

HTML Structure

<div class="not-prose my-10">
  <div id="diagram-pipeline"
       class="diagram-container bg-slate-50 rounded-2xl p-8 border border-slate-200 flex justify-center min-h-[200px]">
  </div>
  <p class="text-center text-sm text-slate-500 mt-3">
    Fig 1: Description of diagram
  </p>
</div>

Critical: Match Theme to Page Design!

Don't use dark themes on light pages. Create a custom theme that matches:

Page StyleTheme Colors
Light pagebg: '#f8fafc', fg: '#1e293b'
Dark pagebg: '#1a1b26', fg: '#a9b1d6'

Or use built-in themes:

import { THEMES } from 'beautiful-mermaid'
const theme = THEMES['github-light']  // For light pages
const theme = THEMES['tokyo-night']   // For dark pages

### Supported Diagram Types

| Type | Use Case | beautiful-mermaid Support |
|------|----------|---------------------------|
| `graph LR/TB` | Pipeline flows, architecture | ✅ Full |
| `sequenceDiagram` | Interactions, API flows | ✅ Full |
| `stateDiagram-v2` | State machines, lifecycle | ✅ Full |
| `classDiagram` | Object relationships | ✅ Full |
| `erDiagram` | Entity relationships | ✅ Full |
| `mindmap` | Concept hierarchies | ⚠️ Use `graph TD` as fallback |

### Diagram Syntax Tips

**Keep it simple.** Complex syntax causes errors. Avoid:
- Emoji in node labels (use plain text)
- Special characters in subgraph names
- Overly nested structures

**Good:**

graph LR A[User Message] --> B[Context Window] B --> C[Daily Notes]


**Problematic:**

graph LR subgraph Input["💬 Input"] A[User Action] end


### Flowchart for Pipelines

```javascript
const pipeline = `graph LR
    A[Input] --> B[Process]
    B --> C[Transform]
    C --> D[Output]`

Sequence Diagram for Interactions

const sequence = `sequenceDiagram
    User->>App: Request
    App->>Server: API call
    Server-->>App: Response
    App->>User: Display`

State Diagram for Lifecycles

const state = `stateDiagram-v2
    [*] --> Idle
    Idle --> Active
    Active --> Complete
    Complete --> [*]`

Figure Captions (Substantial!)

Captions must be self-explanatory. A reader should understand the diagram from the caption alone, without needing to read the surrounding text. This is academic-style figure captioning.

Bad: Fig 1: The pipeline Good: Fig 1. User messages enter the volatile context window, then get written to persistent daily notes and long-term memory files. Semantic search retrieves relevant context back into the window for future sessions.

<div class="not-prose my-6">
  <div id="diagram-name"
       class="bg-white rounded border border-slate-200 p-4 min-h-[100px]">
  </div>
  <p class="text-center text-sm text-slate-600 mt-3 max-w-md mx-auto">
    <strong>Fig 1.</strong> Complete sentence explaining what this diagram shows,
    including the key relationships and flow. The caption should communicate
    the figure's meaning to someone who hasn't read the section text.
  </p>
</div>

Caption formula:

  1. Start with <strong>Fig N.</strong>
  2. Describe what the diagram depicts (nouns)
  3. Explain the relationships/flow (verbs)
  4. Include key insight if space allows

Common Gotchas

  1. CDN script must load before rendering — use the polling pattern shown above
  2. Theme must match page — dark themes on light pages look terrible
  3. NO HTML in labels<br>, <small> will render as literal text. Use simple labels only.
  4. Use not-prose class — prevents Tailwind Typography from breaking diagram styles
  5. Avoid dynamic imports — they don't work reliably in browser; use CDN
  6. Test iteratively with browser — use the browser tool to see actual rendering
  7. Reduce paddingp-4 not p-10; fat padding draws focus away from diagram
  8. Scale SVGs properly — add CSS for width: 100% and appropriate min-height

CSS for Proper Scaling

/* Make diagrams fill container */
#diagram-pipeline :deep(svg) {
  width: 100%;
  height: auto;
  min-height: 80px;
}

#diagram-arch :deep(svg) {
  width: 100%;
  height: auto;
  min-height: 280px;
}

Monochrome Diagrams (Default)

Keep diagrams black and white. Let shapes communicate meaning:

graph LR
    A([Input]) --> B[Process]
    B --> C[(Storage)]
    C --> D{{Tool}}

Semantic shapes (no color needed):

  • ([text]) Stadium — terminals, start/end points
  • [text] Rectangle — processes, steps
  • [(text)] Cylinder — storage, databases
  • {{text}} Hexagon — tools, utilities
  • >text] Asymmetric — documents, outputs

Color-Coded Nodes (Use Sparingly)

Only add color when it communicates specific meaning (e.g., error states, before/after comparison):

graph LR
    A[Normal]:::default --> B[Warning]:::warn --> C[Error]:::error

    classDef default fill:#f8fafc,stroke:#1e293b,color:#1e293b
    classDef warn fill:#fef3c7,stroke:#92400e,color:#92400e
    classDef error fill:#fee2e2,stroke:#991b1b,color:#991b1b

Writing Each Section

Opening Paragraph Formula

Every section needs a compelling opener that:

  1. States what this component IS
  2. Explains WHY it exists
  3. Hints at what you'll learn

Template:

[COMPONENT] is [SIMPLE DEFINITION] — [FUNCTION/PURPOSE].
[WHY IT MATTERS or WHAT WOULD GO WRONG WITHOUT IT].

Example:

Every key on your keyboard sits atop a switch — a mechanism that converts
your physical press into an electrical signal. The type of switch determines
how your keyboard feels and sounds.

Subsection Formula

For each subsection:

  1. Hook line — What is this variant/aspect?
  2. How it works — Technical explanation
  3. Trade-offs — Pros/cons, when to use
  4. Example — Concrete instance

Technical Depth Ladder

Progress from accessible to advanced within each section:

  1. Level 1: Analogy/Overview — "Think of it like..."
  2. Level 2: How it works — The mechanism
  3. Level 3: Implementation details — Specifics, numbers, protocols
  4. Level 4: Edge cases — What can go wrong, advanced considerations

Quantify Where Possible

Numbers make explanations concrete:

  • "bounces for 1-5 milliseconds"
  • "6 bytes per report"
  • "125Hz polling rate (8ms intervals)"
  • "The entire journey typically takes 5-25 milliseconds"

Lists & Inline Elements

Prose isn't always the answer. Sometimes a list communicates faster — and sometimes inline styling makes the difference between scannable and sloggable.

Lists vs Prose: When to Use Which

Use bulleted lists when:

  • Items are parallel (same structure, comparable weight)
  • Readers need to scan quickly
  • Each item is short (one line, maybe two)
  • You're showing options, features, or trade-offs

Use prose when:

  • You're building an argument or narrative
  • Items need context to make sense together
  • The explanation requires transitions between ideas
  • One item naturally leads to the next

The 3-line rule: If each bullet would need 3+ lines of explanation, consider prose with bold lead-ins instead. Lists with fat bullets feel like failed paragraphs.

Bold Lead-In Pattern

The most useful list pattern for explainers. Each item starts with a bolded term or phrase, followed by an em-dash and the explanation:

- **Facts** — Concrete information about the user (location, job, preferences they've stated)
- **Preferences** — Things they like, dislike, or have strong opinions about
- **Context** — Situational awareness (current project, recent events, mood)
- **Patterns** — Behaviors you've noticed over time

This pattern works because:

  1. Scannable — Readers can skim bold terms to find what they need
  2. Self-labeling — Each item names itself before explaining
  3. Consistent — Parallel structure makes comparison easy
  4. Dense — Packs information tightly without walls of text

When to use: Feature lists, component breakdowns, trade-off comparisons, glossary-style definitions, configuration options.

Inline Code Styling

Use inline code for:

  • File names and paths (nuxt.config.ts, /content/guide/)
  • Commands and flags (npm run dev, --host)
  • Variable names, function names, properties (isRunning, onClick)
  • Specific values (125Hz, 8ms, #0ea5e9)
  • Technical terms on first use when precision matters

Tailwind Typography styles inline code with a subtle gray background (#f3f4f6), rounded corners, and slightly reduced font weight. This works well for most cases — no custom styling needed.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
88
Forks
17
Last commit
Jul 2026
Advanced
Catalog kind
skill
Gateway key
explainer-site
Source
github.com/drpedapati/sciclaw