Michael profile

Deck-as-code: the slide registry pattern

The whole architecture of a deck-as-code framework lives in one type:

interface SlideDefinition {
  id: string
  title: string
  component: ComponentType
  controls?: ComponentType
  context: SlideContext
}

A deck is SlideDefinition[]. A viewer is <DeckViewer slides={SLIDES} />. That's the thesis.

One viewer, many decks

In nopoint, the same DeckViewer renders the YC pitch deck, the information memorandum, a conference talk and a demo-day 2-minute pitch. The component does not know which deck it's showing. It knows how to render slides, navigate between them, manage state, and export them. The deck identity lives in the registry.

// slides/index.ts (pitch deck)
export const SLIDES: SlideDefinition[] = [
  TitleSlide,
  ProblemSlide,
  SolutionSlide,
  WhyNowSlide,
  ProductSlide,
  MarketSlide,
  TractionSlide,
  WhyWeWinSlide,
  BusinessModelSlide,
  TeamSlide,
  AskSlide,
]
// app/pitchdeck/page.tsx
import { DeckViewer } from "@/components/deck-viewer"
import { SLIDES } from "@/components/pitchdeck/slides"
 
export default () => <DeckViewer slides={SLIDES} storagePrefix="pitchdeck" />

That's the entire page. To make a second deck, copy the file, point at a different registry, change the storage prefix.

Adding a slide is import + push

The reason this matters is the iteration loop. In PowerPoint, "add a slide" is "drag a thumbnail and rebuild it." In a registry, it's:

  1. slides/new-slide.tsx — write the JSX.
  2. slides/index.ts — import it, push into the array.
  3. Done. It appears in the viewer, the manager, the grid view, the scroll view, and the PDF export.

Reordering is array reordering. Disabling is array.filter. Audience-specific decks are slicing the array. Versioning the deck is committing the file.

Why the type has four fields

Each one earns its place.

That's it. No heavyweight slide engine. No layout DSL. No bullet-point schema. The component is whatever you write.

What the viewer gives you

Because the registry shape is uniform, the viewer can do work on top of it:

You write zero of that infrastructure. You write slides.

Deck-type templates

The "deck type" maps to: a registry + a chrome config. Pitch deck has a CONFIDENTIAL watermark and a contact card. Conference talk doesn't. Demo Day strips out the Why-Now and Business Model slides. A customer-facing product narrative hides Ask and financials.

In nopoint these are templates: --type=pitch, --type=im, --type=demo-day, --type=narrative. Each scaffolds a registry and a config. Same viewer underneath.

The line that matters

The registry is the deck. Everything else — view modes, exports, navigation, persistence — is shared infrastructure that doesn't change between decks. If you've spent ten years building slides, you've spent ten years also rebuilding that infrastructure inside whichever slide tool you used. You can stop now.

nopoint gives you the infrastructure. You bring the registry.