Annotated code walkthrough pages with a live comment system, hosted on Val Town.
Meander turns /* … */ comments in your source files into a
narrated, navigable walkthrough. Each comment becomes a prose
card; the code that follows becomes the paired, highlighted code
block. Readers can leave threaded comments on any line range.
The generator emits static HTML. Comments are stored server-side in a Val Town val (SQLite + blob storage, encrypted at rest) — you only need that piece if you want the commenting layer.
- Side-by-side prose + code — each block comment pairs with the code that follows it.
- Multi-part walkthroughs — split a codebase into ordered parts; the top nav moves readers between them.
- Go-to-definition — exported symbols are indexed so readers can jump to any definition across parts.
- Line-range commenting — shift-click to select lines, type a comment, reply, resolve, delete.
- Documents tab — optional Markdown pages with syntax highlighting, a floating table of contents, block-level comments, and cross-doc links.
- Reader UX — resizable prose/code splitter, jump-to-file menus, theme toggle, Cmd/Ctrl-click hotlinks, JSDoc annotation, opt-in Mermaid pre-rendering.
- Val Town hosting — one Hono val serves every walkthrough out of blob storage, with encryption at rest.
See docs/features.md for the full feature list and configuration knobs.
pnpm install -g @divmain/meanderOr run without installing:
npx @divmain/meander generate meander.config.jsonRequirements: Node >= 20.
Add block comments anywhere in your source files. The comment becomes the prose; the code that follows (up to the next comment or end-of-file) becomes the paired code block.
/*
* Load the application configuration from environment variables,
* falling back to sensible defaults when a variable is absent.
*/
export function loadConfig(): Config {
return {
port: Number(process.env['PORT'] ?? 3000),
version: process.env['API_VERSION'] ?? 'v1',
}
}Prose inside the comment supports full Markdown.
Create meander.config.json at the root of your project:
{
"slug": "my-project",
"title": "My Project Walkthrough",
"parts": [
{
"id": 1,
"title": "Configuration",
"objective": "Understand how the app is configured at startup.",
"keywords": ["config", "env"],
"files": ["src/config.ts", "src/defaults.ts"]
},
{
"id": 2,
"title": "Request Handling",
"objective": "See how incoming requests are routed and processed.",
"keywords": ["router", "handler", "middleware"],
"files": ["src/router.ts", "src/handlers/index.ts"]
}
]
}meander generate meander.config.json # emit HTML
meander serve meander.config.json # local preview at http://127.0.0.1:8080generate writes into pages/ next to your config:
pages/
index.html part listing
part-1.html one file per part
part-2.html
meander.css shared styles
manifest.json build summary
| Field | Type | Required | Description |
|---|---|---|---|
slug |
string |
Yes | URL-safe identifier, [a-z0-9][a-z0-9-]*. Used in URLs and storage keys. |
title |
string |
Yes | Title shown on the index page. |
parts |
Part[] |
Yes | Ordered list of walkthrough parts (at least one). |
documents |
string[] |
No | Markdown files to render as a Documents tab, relative to the config file. |
outDir |
string |
No | Directory to emit into, default pages. Also the Val Town blob prefix. |
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer |
Yes | Unique part number (starts at 1). |
title |
string |
Yes | Short title shown in the nav. |
objective |
string |
Yes | One sentence describing what the reader will learn. |
keywords |
string[] |
Yes | Words used to resolve ownership when a file appears in multiple parts. |
files |
string[] |
Yes | Source files in this part, relative to the config file. |
filename |
string |
No | URL-friendly slug for clean part URLs (/:slug/parts/<filename>.html). |
When the same file appears in multiple parts, meander picks an
owner per comment block using keyword scoring. Each keywords
list is checked against the block's cleaned text and its file
path; the part with the most matches wins, ties broken by
config order. Pick keywords that distinguish parts, not generic
terms.
The full schema — comments / theme / styles opt-outs, favicon
overrides, CSP, SRI, mermaid, minify, service worker — lives in
docs/features.md.
The commenting layer runs in a Val Town val. If you only want
static pages, you can skip this — meander serve previews the
HTML standalone.
To deploy the val + publish encrypted pages:
meander deploy-val # first-time val setup
meander publish meander.config.json # upload encrypted HTMLSee docs/deploying.md for the full setup (env vars, CI integration, graceful skip for fork PRs).
example/minimal/— the smallest runnable meander project. Start here.example/consumer-build/— integrating meander as a step in your own build pipeline (CLI, programmatic, GH Pages workflow).
- Features + configuration — every opt-in and opt-out knob, with examples.
- Deploying — Val Town setup, token scopes, first-time deploy, CI integration.
- Comment API — the REST endpoints the browser client hits.
- Encryption — envelope scheme, threat model, Shamir custody, recovery scenarios.
- Operating — day-2 ops runbook: rotation, restoration drills, custodian responsibilities.
- Contributing — working on meander itself: tests, CI, style, architecture tour.
MIT