Build Keynote-style single-file HTML slide decks with brand-ready templates, minimal navigation, and Gemini nano banana media generation...
assets/keynote-slides.html holds the single-file slide deck template.references/brand-guidelines.md captures brand tokens, typography, and image style guidance.references/gemini-media.md documents the Gemini nano banana and Veo media settings.Resolve entity + detect content-db. Read deck.json โ entity field; fall back to <section data-entity="..."> on the active slide; then to brands.js default entity (the entity whose export key is "default", or the single entity in the file). Check whether content-db/<entity>/ exists alongside brands.js. If it does and is well-formed, content-db mode is active โ load relevant atoms before generating any content. If it does not exist or is malformed, proceed normally with no message. See the Content Database section for the full protocol.
Run the deck bootstrap to create a deck folder:
scripts/new-deck.sh example-pitch --entity northwind --title "Example Pitch" --type pitch
decks/brands.js when brand tokens change.decks/<deck-id>/index.html and duplicate slides inside <main id="deck">, keeping each data-title unique.layout-title, layout-split, layout-grid, layout-metrics, layout-quote) to keep spacing consistent.reveal plus --reveal-index to stagger key elements.data-entity="entity-id" on a slide to override the global profile for that slide.?entity=entity-id to the URL for a quick switch.mediaPromptPrefix in brandProfiles to keep Gemini media outputs on brand.decks/<deck-id>/index.html is the editable deck file.decks/<deck-id>/deck-config.js stores deck metadata (entity, title, resources).decks/<deck-id>/deck.json stores the same metadata in JSON form.decks/<deck-id>/slides.md is for draft copy and notes.decks/<deck-id>/resources/assets/ holds logos, images, and media inputs.decks/<deck-id>/resources/materials/ holds briefs, pricing docs, P&L inputs, and outlines.Export PMF Panel findings as deck input materials:
# From pmf-panel directory
.claude/export-deck-brief.sh <scenario-id>
# Copy to deck materials
cp scenarios/<scenario-id>/deck-brief.md \
../keynote-slides-skill/decks/<deck-id>/resources/materials/pmf-brief.md
The brief includes diagnosis, scenarios, 30/60/90 plan, and specialist perspectives ready for narrative engine ingestion.
deckType and entity preferences.resources/materials/brief.md and capture evolving preferences in deck.json or decks/brands.js.content-db/<entity>/ for any claims (cl###), copy strings (cp###), or assets (as###) introduced during the build. Run node content-db/validate.js (or equivalent). The output package is not complete until validation exits 0. Do not modify existing atoms โ add a vl### validation record and mark the original status: disputed if wording conflicts.<template> blocks at the bottom of the file.data-gen and data-prompt to <img> or <video> elements.g or the Gen button.Use the /acquire-images skill (see skills/acquire-images.md) to populate slides with visuals.
Claude decides whether to generate (Gemini) or search (stock photos) for each slide:
| Content Type | Decision | Why |
|---|---|---|
| Diagrams, flowcharts | GENERATE | Custom layouts, brand colors |
| Data visualizations | GENERATE | Precise data representation |
| Real-world photos | SEARCH | Authentic people, places |
| Team/people shots | SEARCH | Realistic human photos |
| Abstract concepts | GENERATE | Metaphorical, brand-styled |
| Branded hero images | HYBRID | Search base + AI overlay |
Search sources: Unsplash, Pexels, Google Custom Search.
Attribution: Downloaded images tracked in resources/materials/image-credits.json.
See skills/acquire-images.md for the full workflow.
scripts/serve-decks.sh
Then open http://<tailscale-ip>:8921/decks/<deck-id>/index.html.
<aside class="slide-notes">Speaker notes here.</aside>
n.?notes=1 to open notes by default.data-anim for lightweight entrance animations (fade, slide-up, slide-left, slide-right, scale-in).--anim-delay to stagger; avoid mixing with reveal on the same element.?motion=off or rely on prefers-reduced-motion..diagram and data-media="svg":<svg class="diagram" data-media="svg" viewBox="0 0 800 450" role="img" aria-label="Diagram"></svg>
data-gen = Gemini only (optional data-media="gemini").data-gen.data-gen.Micro animations are small decorative accent elements that add subtle motion to slides without distracting from content.
What micro animations ARE:
What micro animations are NOT:
Implementation:
<!-- Accent line after a headline -->
<h1 class="title">Your headline here</h1>
<span class="accent-line"></span>
Available classes:
.accent-line โ 80px amber line that expands from left, then pulses.accent-line.long โ 120px version for major headlinesBehavior:
prefers-reduced-motion and ?motion=offWhen to use:
decks/<deck-id>/editor.html in a second window to edit copy without touching HTML.cp skills/keynote-slides/assets/keynote-editor.html decks/<deck-id>/editor.html
e, or add ?edit=1 to enter Edit mode.data-editable, data-edit-id, data-copy-id, or data-copy-role.KEYNOTE_EDIT_PATCH_<deck-id>.edit-patch-<deck-id>.json for agent handoff. The deck HTML remains the source of truth until an agent/script applies the patch.status: "published" to both deck.json and window.KEYNOTE_DECK in deck-config.js when a deck is final.?edit=1, and do not apply local edit patches.draft.node scripts/export-pdf.js decks/<deck-id> --out /tmp/<deck-id>.pdf
e.#slide-title hash navigation for direct jumps.Enable reviewers to leave comments on deck elements for collaborative feedback.
r key to toggle review mode?review=1 to the URL to start in review modec or click the sidebar toggle to open the comment sidebarFrom the comment sidebar:
comments-<deck-id>.json for backup or importUse assets/feedback-viewer.html to review all feedback outside the deck:
feedback-viewer.html in a browsercomments.json file or enter a URLAdd ?url=<path-to-json> to auto-load comments.
Comments are stored in localStorage keyed by deck ID. Export structure:
{
"deckId": "example-pitch",
"nextNumber": 4,
"comments": [
{
"id": "c_1706123456789_abc123",
"number": 1,
"slideIndex": 2,
"slideTitle": "Our Solution",
"elementSelector": "[data-comment-target='headline']",
"elementText": "First 50 chars of element...",
"selectedText": "specific phrase",
"comment": "This needs more specificity",
"author": {
"name": "Sarah Chen",
"email": "sarah@example.com"
},
"createdAt": "2024-01-24T10:30:00Z",
"resolved": false
}
]
}
number: Sequential comment number (โ โกโข) for easy reference in feedbackselectedText: If reviewer selected specific text, captures that selection (null otherwise)For precise comment targeting, add data-comment-target attributes:
<h2 data-comment-target="solution-headline">Our Solution</h2>
<p data-comment-target="value-prop-1">We reduce costs by 40%...</p>
Elements without explicit targets use a generated CSS selector path.
For content-driven deck creation, use the Narrative Engine workflow that matches your material to proven storytelling frameworks.
references/narrative-engine/narrative-arcs.md โ Beat-by-beat structures for 10 narrative arcsreferences/narrative-engine/framework-selection.md โ Selection matrix by audience/purpose/contentreferences/narrative-engine/framework_selection_guide.md โ Deep pairing guidance for arcs + frameworksreferences/narrative-engine/communication-frameworks.md โ 7 efficiency-optimized frameworksreferences/narrative-engine/checklists.md โ Quality gates for narrative + copy reviewreferences/narrative-engine/agent-reference-*.md โ Agent-specific frameworks for reviewnode scripts/ingest-resources.js decks/<deck-id> to read all materialsnode scripts/narrative-build.js decks/<deck-id> to prepare model-mediated prompts
1a. Load content-db atoms (if active). If content-db mode is active, pull copy.md and claims.md atoms for the resolved entity. Filter atoms by audience tag if present. Surface any atom with a non-null gate value before proceeding โ do not include gated content without user confirmation. If content-db is not active, skip this step.content-db/<entity>/claims.md โ want me to register it as unverified, or use the closest approved atom?" Do not silently include or skip unapproved content.| Question | Options |
|---|---|
| Audience | Executive, Technical, Investors, Skeptics, General, Mixed |
| Purpose | Persuade, Inform, Inspire, Align, Report, Defend, Entertain |
| Content type | Research, Strategy, Origin story, Post-mortem, Pattern insight, etc. |
| Tone | Authoritative, Provocative, Warm, Urgent, Balanced, Visionary |
| Reveal potential | Yes (has surprise), No (straightforward), Help me find one |
| If your content has... | Consider... |
|---|---|
| A genuine surprise | The Prestige or Mystery Box |
| Multiple stakeholder views | Rashomon |
| A transformation story | Hero's Journey |
| Future vision | Time Machine |
| Root cause analysis | Columbo |
| Strategy/roadmap | The Heist |
| Paradigm shift | Trojan Horse |
| Agent | Lens | Key Question |
|---|---|---|
| Audience Advocate | Target audience persona | "Does this land for [audience]?" |
| Comms Specialist | Messaging, emotion, PR risk | "Is this tight and bulletproof?" |
| Visual Designer | Metaphor coherence, S.T.A.R. moments | "What visual makes this unforgettable?" |
| Critic | Pacing, weak links, efficacy | "What's the weakest link?" |
| Content Expert | Accuracy, logic, sources | "Can every claim be defended?" |
After the 5-agent review, optionally stress-test with stakeholder personas auto-selected by content type:
| Persona | Questions | Best For |
|---|---|---|
| Engineer | "How does this actually work?" | Technical proposals, product launches |
| Skeptic | "Why should I believe this?" | Bold claims, paradigm shifts |
| Risk Officer | "What could go wrong?" | Strategy, transformation, investment |
| CFO | "What are the numbers?" | Pitches, business cases, ROI claims |
| Lawyer | "What's the exposure?" | Policy, compliance, external-facing |
| Conservative | "Why change what's working?" | Change management |
| COO | "Would this actually work?" | Execution plans, go-to-market |
The Director triages findings into Must Fix, Should Fix, and Could Fix categories.
| Tag | Meaning |
|---|---|
[DIRECT] |
Verbatim from source material |
[PARAPHRASE] |
Restated ideas |
[ELABORATED] |
Expanded concept |
[SYNTHESIZED] |
Combined multiple sources |
[GENERATED] |
New content for flow |
See /docs/integrated-architecture.md for full technical details.
A modular, approved-content management layer for any project using keynote-slides. When a content-db/<entity>/ directory exists alongside brands.js, agents automatically load and enforce approved atoms. When it does not exist, the skill runs exactly as before โ no config, no warnings.
<deck-repo>/
โโโ brands.js โ entity source of truth (unchanged)
โโโ content-db/
โ โโโ <entity>/ โ one directory per entity
โ โโโ README.md โ schema reference + agent protocol
โ โโโ claims.md โ cl### atoms โ stats, benchmarks, data points
โ โโโ validation.md โ vl### atoms โ experimental evidence blocks
โ โโโ assets.md โ as### atoms โ images, video, SVG with provenance
โ โโโ copy.md โ cp### atoms โ approved text passages
โ โโโ brand.md โ br### atoms โ color tokens, typography
โ โโโ layouts.md โ ly### atoms โ approved slide structures
โโโ <deck-id>/ โ decks alongside (unchanged)
content-db/ always lives next to brands.js. Multi-entity repos have one subdirectory per entity.
Resolve the active entity in this order:
deck.json โ entity field<section data-entity="..."> on the active slidebrands.js โ the entity whose export key is "default", or the single entity in the file. If multiple entities exist without a "default" key, surface the ambiguity โ do not guess.resolve entity
โ content-db/<entity>/ exists and is well-formed?
โ YES: load relevant atom files, activate compliance
โ MALFORMED: log warning, proceed without compliance
โ NO: proceed as normal, no message
| Operation | Atom files loaded |
|---|---|
| Narrative planning | copy.md, claims.md |
| Full build | all six files |
| Targeted edit | only types relevant to the change |
content-db/<entity>/claims.md โ want me to register it as unverified, or use the closest approved atom?"cl###), copy strings (cp###), and assets (as###) introduced. Run node content-db/validate.js. Output is not complete until exit 0.vl### validation record and update status: disputed in the original. Surface the conflict to the user.All new atoms use a two-letter prefix + zero-padded three-digit number. Existing atoms with single-letter prefixes are grandfathered.
| File | Prefix | Contents |
|---|---|---|
claims.md |
cl### |
Stats, benchmarks โ status: validated | disputed | unverified |
validation.md |
vl### |
Experimental evidence โ experiment_type, result, institution |
assets.md |
as### |
Images, video, SVG โ file, deck, type, used_in |
copy.md |
cp### |
Approved text passages โ concept, audience_level, tone, variants |
brand.md |
br### |
Color tokens, typography โ element, css_var, value, usage_rules |
layouts.md |
ly### |
Slide structures โ slide_type, css_classes, js_required, data_density |
Each atom is a ## <id> heading with bullet-field body. Full schema in content-db/<entity>/README.md.
The skill does not scaffold a content-db unprompted. If a user asks why content-db is not active, explain the directory is absent and offer to create it. Only scaffold if the user says yes.
Bootstrap steps (when approved):
content-db/<entity>/ directoryREADME.md with schema reference and compliance rulesIf the user declines, proceed in no-compliance mode and do not raise the topic again in the same session.