ring:deck
ring:deck — Lerian Editorial Deck Scaffolder
Scaffold a self-contained Node project for a Lerian-branded HTML presentation. Every deck ships with a live-reload dev server, a presenter view designed for a second screen, a phone-as-remote over WebSocket, and Puppeteer-driven PDF export. The output is a working local project the user runs themselves — not a single HTML file, not a hosted site.
When to use this skill
Use whenever the user asks for a branded slide deliverable: board deck, investor update, conference talk, all-hands, customer pitch, internal review. The trigger is "deck-shaped output" — sequenced sections, speaker notes, something a human will present live.
- "Make me a board deck for Q2"
- "Build an investor deck for the Series A conversation"
- "I need a conference talk deck"
- "Scaffold a new presentation for next week's all-hands"
- "New slide deck for the product review"
When NOT to use this skill
- Editing an already-scaffolded deck — edit
deck.htmlinside that project directly. The scaffold is a one-shot bootstrap, not an editor. - Non-presentational documents — memos, one-pagers, exec emails, PR descriptions. These are written content, not sequenced slides.
- Single static HTML visualization — a diagram, dashboard, or comparison table is
ring:visualize. That skill produces one.htmlfile; this skill produces a Node project.
Inviolable vs Creative
Inviolable (engineering + brand). Canvas dimensions, flex layout, pagination, overflow, export pipeline — see engineering.md. Brand colors, typography, logo — see brand.md. These MUST NOT bend.
Creative (the canvas itself). Slide composition, narrative arc, headline voice, content rhythm, layout imagination. Use the primitives; the composition is yours.
Two Lerian Design Systems Side by Side
HARD GATE (brand). ring:deck uses editorial tokens (Amarelo #FEED02, Poppins + IBM Plex Serif, JetBrains Mono) intentionally separate from ring:visualize's product-console tokens (#FDCB28 sunglow, Inter). Both systems are canonical Lerian. MUST NOT cross-mix tokens. A deck with ring:visualize's Inter + sunglow is wrong; a diagram with ring:deck's Poppins + Amarelo is wrong. Keep the systems pure.
Mandatory Reading — HARD GATE
Before writing any slide content, MUST read:
references/brand.md— colors, typography, logo (inviolable)references/engineering.md— canvas, flex, pagination, 24px text floor, overflow (inviolable)references/primitives.md— the CSS atoms available: eyebrow, pill, kpi, ticks, numbered, table.grid, dashed-hairline, narrative-arc, transition-column, org-node-flag, dual-sided-argument, inline-mini-legendreferences/chart-primitives.md— stacked-horizontal-bar, vertical-bar-chart, 2x2-matrix, funnel (+ monetary overlay), inline-micro-chartreferences/speaker-notes.md— JSON schema + presenter voice
Server + export references (read when tooling questions come up):
references/server.md— dev server, WebSocket protocol, port override, trust modelreferences/export.md— Puppeteer PDF export flow
Skipping the engineering and brand files is the #1 failure mode — they encode the canvas physics and brand rigor that every deck must obey.
Skill Workflow
Phase 1: Gather minimum-viable requirements
MUST ask the user (skip questions already answered):
- Deck title — e.g., "Lerian Board Meeting Q2 2026"
- Audience — board, investors, conference, team, external partner
- Rough slide count — e.g., around 15
- Directory name — defaults to kebab-cased title
MUST NOT ask about: tokens, fonts, layout, runtime, export. Those are fixed by the skill — asking is validation theater.
Phase 2: Read mandatory references
See Mandatory Reading above. HARD GATE — MUST NOT write slides without reading refs 1-5.
Phase 3: Scaffold project
Sanitize substitution variables first. Before copying any template, compute:
DECK_TITLE= the user-supplied title verbatim (e.g.,"Q2 2026 Board Deck"). Used inside HTML text nodes — HTML-escape<,>,&if the title contains them.DECK_NAME=DECK_TITLE.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''). MUST be kebab-case — it's the project directory name AND the"name"field inpackage.json, which rejects spaces, quotes, and most punctuation. Example:"Q2 2026 Board Deck" → "q2-2026-board-deck".YEAR= current 4-digit year.COPYRIGHT_HOLDER="Lerian Studio"unless the user specifies otherwise.
Naive str.replace on an unsanitized title breaks package.json (quotes, newlines) and fails filesystem validation. Sanitize first, substitute second.
Then create <DECK_NAME>/ directory with these files (copy from the skill's templates/, assets/, and scripts/ directories):
| Source (skill) | Destination (scaffolded deck) |
|---|---|
templates/deck.html |
deck.html (substitute {{DECK_TITLE}}) |
templates/presenter.html |
presenter.html |
templates/remote.html |
remote.html |
templates/package.json.tmpl |
package.json (substitute {{DECK_NAME}}) |
assets/* |
assets/* |
scripts/* |
scripts/* |
templates/LICENSE.tmpl |
LICENSE (substitute {{YEAR}}, {{COPYRIGHT_HOLDER}} — default Lerian Studio) |
templates/README.md.tmpl |
README.md (substitute {{DECK_TITLE}}, {{DECK_NAME}}) |
templates/.gitignore.tmpl |
.gitignore (no substitution) |
Phase 4: Compose slides in deck.html
Compose slides from the brand tokens and primitives to serve the deck's narrative. There is no required slide menu — use a cover when it serves the moment, a full-bleed accent slide when the message demands it, invent a layout when the content calls for something the primitives don't anticipate. The engineering and brand constraints are hard; the composition is yours.
For each slide:
- Compose using primitives from
references/primitives.md(and charts fromreferences/chart-primitives.mdwhere they fit) - Borrow from the example slide templates in
templates/slide-*.htmlwhen a composition there already fits — those are examples, not a required menu - Replace any placeholder content with actual content
- Obey
references/engineering.md(flex: 1,min-height: 0, no fixed-height cards, 24px text floor, overflow hidden) - Obey
references/brand.md(tokens, typography, logo)
Phase 5: Write speaker notes
- Flat JSON array of strings
- One entry per
<section>, zero-indexed matching<section>order \n\nfor paragraph breaks- Speaking voice (not written voice) — concrete data first, then context
- See
references/speaker-notes.mdfor full guidance
Phase 6: Hand off to user
Print the Handoff Message Template (below). Do NOT run pnpm install or pnpm dev for the user — the deck is theirs to run.
Anti-Rationalization Table
| Rationalization | Why It's WRONG | Required Action |
|---|---|---|
"Content is simple, I can skip engineering.md" |
Simple content still breaks with fixed-height cards. Skipping the canvas rules is the #1 failure mode. | MUST read engineering.md |
| "I'll pick colors that look nicer than Amarelo" | #FEED02 Amarelo is Lerian brand primary, not a style choice. Swapping is a rebrand, not a tweak. |
MUST use tokens from brand.md |
| "I can skip speaker notes" | Notes surface in presenter view — presenters rely on them. Empty notes = unusable presenter view. | MUST write notes for every slide |
| "Deck already has fonts — I'll skip the Google Fonts block" | Every scaffolded deck is self-contained. The fonts block in deck.html is mandatory. |
MUST preserve the Google Fonts import block |
| "I'll use Chart.js for richer charts" | v1 is pure CSS/HTML. Chart.js is v2 work. | MUST use only the 4 chart primitives |
| "I'll mix deck tokens and visualize tokens" | Editorial and product-console design systems are deliberately separate. | MUST keep deck tokens pure |
| "I'll hardcode the slide count in pagination" | <section> count is dynamic. deck-stage.js fills pagination at runtime. |
MUST use <span class="page-num"> + <span class="page-total"> pattern |
| "Puppeteer install is slow — I'll skip it" | Export is a first-class feature. Install is a one-time cost. | MUST include puppeteer in package.json |
| "Reading the reference summary in this SKILL.md is enough" | Summaries are lossy. Token values, exact class names, and pattern structure live in the reference files. | MUST use the Read tool to open each reference file |
Pressure Resistance
| User Says | Your Response |
|---|---|
| "Just make a simple HTML file, no Node project" | "Cannot: dev server + presenter + remote + export require Node. If you want a single static HTML without tooling, use ring:visualize instead — different skill, different purpose." |
| "Skip the presenter view, I don't need it" | "Generated anyway — costs nothing, adds value if needed later. Zero-config removal: just don't open the /presenter URL." |
| "Use Inter instead of Poppins" | "Cannot: #FEED02 Amarelo + Poppins + IBM Plex Serif is Lerian editorial brand. For Inter/sunglow tokens, use ring:visualize." |
| "Skip the license file" | "Cannot: Lerian open-source commitment is a third rail. Apache 2.0 license ships with every scaffold." |
| "Don't watch files, just write the deck once" | "Cannot: dev server + chokidar is the scaffold default. For a static export, run pnpm export and distribute the PDF." |
| "Host the deck online" | "Out of scope. Scaffolded deck is local-network. Hosting is the user's choice — any static host (Vercel, Cloudflare Pages) serves deck.html + assets/ + scripts/ (minus dev-server.mjs). Document if the user asks." |
| "Build me a timeline/quote/org-chart slide" | "Compose one from the primitives in primitives.md — eyebrow, pill, kpi, ticks, narrative-arc, transition-column, and friends are enough for most shapes. If a specific shape (e.g., image-hero, photo-grid) needs primitives that don't exist yet, flag as v2 and proceed with the closest composition." |
Blocker Criteria — STOP and Report
STOP and report to the user if:
| Decision Type | Blocker Condition | Required Action |
|---|---|---|
| Missing Runtime | Node not installed, or Node version < 18.0.0 | STOP — user must install Node 18+ before proceeding |
| Directory Collision | Target directory exists and is non-empty | STOP and ask: overwrite, rename, or cancel |
| Unsupported Export | User asks for editable-PowerPoint PPTX (text + shapes, not screenshots) | STOP — report v1 PPTX is screenshots mode only (PNG per slide + speaker notes via addNotes()); editable PPTX is deferred because CSS layout doesn't map cleanly to PowerPoint shapes. Offer: PDF + re-author manually, or accept screenshots-mode PPTX. |
| Theme Customization | User asks for accent override, density toggle, font swap | STOP — report v1 is locked to Lerian editorial tokens; customization is v2 |
| Auth on Remote | User asks for PIN or auth on the remote control | STOP — report v1 is local-network trust model; PIN auth is v2 |
HARD BLOCK — cannot proceed:
- If the skill's
references/directory is missing any mandatory file (any of the 7 refs) → report which is missing; instruct user to re-clone the plugin repo. - If the skill's
templates/is missingdeck.htmlor the example slide templates → same remediation.
Severity Calibration
| Severity | Examples | Action |
|---|---|---|
| CRITICAL | Fixed-height cards used; hardcoded pagination NN/17; wrong color tokens; wrong fonts |
MUST fix before completing |
| HIGH | Text smaller than 24px floor; chart without aria-label; speaker notes missing |
SHOULD fix; warn user if shipping as-is |
| MEDIUM | Placeholder content not replaced; content-accent slides used so often they lose impact |
Warn user; user decides |
| LOW | Minor typography drift (e.g., 80px hero where 96px would fit) | Mention; user decides |
Cannot Be Overridden (Non-Negotiable)
- Lerian brand tokens — Amarelo
#FEED02, Poppins + IBM Plex Serif, JetBrains Mono - Apache 2.0 license on scaffolded deck
- Dynamic pagination via
<span class="page-num">+<span class="page-total">(two documented exceptions: appendix letter paginationA1 / 8and main-deck companion letter-suffix09b / 14— both hardcoded without the.page-numclass so the runtime leaves them alone) flex: 1; min-height: 0on main content grids (engineering.mdHARD GATE)- Speaker-notes JSON structure — flat array of strings
- WebSocket protocol — 5 message types (
nav,blank,state,hello,reload) in v1.stateandnavcarry atotalfield so the remote can renderN / Monce the main deck has announced totals. Seereferences/server.mdfor the full protocol. - Self-contained scaffold — every deck is an independent Node project; no shared workspace dependency
Known Limitations (v1)
- Remote shows
N / ?for slide-total until the first nav event fires. Server doesn't know total until main deck broadcasts. Fine for most flows; users rarely notice. - No auth on remote — local network trust model. Document in handoff.
- Puppeteer bundled Chromium weighs ~200MB per scaffolded deck.
pnpm export:chromeuses system Chrome instead. - Google Fonts online dependency — scaffolded deck fetches fonts from Google CDN. Offline presentations need a pre-cached browser.
Handoff Message Template
After scaffolding, print this to the user:
Deck scaffolded at: ./<deck-name>/
Next steps:
cd <deck-name>
npm start # one command: installs deps if needed, boots
# dev server on http://localhost:7007, and
# auto-opens the deck in your default browser.
# (Suppress the auto-open with AUTO_OPEN=false.)
During the presentation:
- Main deck: http://localhost:7007
- Presenter: http://localhost:7007/presenter (open on second screen)
- Remote: http://<LAN-IP>:7007/remote (open on phone, same Wi-Fi)
In-browser toolbar (floating, bottom-center):
Tweak capture feedback on the active slide — appended to
feedback.jsonl. Tell Claude "check tweaks" to review.
Presenter opens /presenter in a new window
PDF triggers Puppeteer export, streams deck.pdf for download
PPTX same flow for deck.pptx (screenshots + speaker notes)
Remote shows the LAN URL for the phone remote
Keyboard controls (main deck):
→/Space next slide
← previous slide
F fullscreen
S toggle speaker notes overlay
G go to slide number
B blank screen
T toggle tweak panel
H toggle toolbar visibility
Export from the terminal (optional — the toolbar buttons are easier):
npm run export # PDF via bundled Chromium (~200MB first time)
npm run export:chrome # PDF via system Chrome (~50MB, faster)
npm run export:pptx # PPTX (screenshots + notes, not editable)
Local network only — no auth. Don't expose port 7007 publicly.
Future Work (v2 Candidates)
- Editable PPTX export (text + shapes mapped from CSS layout, not screenshots) — v1 ships screenshots mode only
- Data-driven mode: YAML/JSON content files + template binding
- Theme customization: accent override, density toggle
- Additional primitives: timeline, quote block, org-chart, image-hero, photo-grid
- Remote auth: short-lived rotating PIN displayed on main screen
- Chart.js opt-in for richer analytics
- Self-contained HTML bundle export (no-CDN offline package)
- Multi-deck workspace (shared deps)