v0.9 · npm i @getnarro/core

Ship the story,
not the slides.

Narro is a React library for narrative, built for you and your coding agent. A deck is source: your agent writes it, narro check tells it what is wrong, and the same file renders as an animated presentation, a static deck, a PDF, or a video.

Build your first deck
npm create narro@latest my-story

Working through an agent? Point it at getnarro.com/llms.txt — the dialect, every valid name, and the command that checks its work.

story.md01 / 04
# We shipped the
  wrong thing.

<!-- notes: Six weeks in… -->

---
Markdown → deck

We shipped the wrong thing.

Six weeks in, the roadmap was fiction. Here is what it cost us.

live render

AI-first

Written for the thing writing your deck.

A deck is source, so an agent can write one — and then, unlike a slide editor, actually check its work. Narro publishes the documentation, the closed sets of valid names and the component types as machine-readable files, and ships the loop that turns a wrong deck into an error message.

The whole setup
Read https://getnarro.com/llms.txt, then write the Q3 review to deck.md and run `npx @getnarro/cli check deck.md --fit` until it passes.

No plugin, no configuration. The docs are tested this way too: an eval hands a model llms.txt and nothing else, then puts the deck it writes through narro check and narro build.

Rules to paste into your AGENTS.md →
/llms.txt
The index an assistant fetches first. Every page is markdown at its own URL with .md appended, and /llms-full.txt is all of them in one request.
/catalog.json
Every layout, theme, colour scheme, template, frontmatter key and CLI command that exists. A model choosing from it cannot invent a name that reads plausible and renders wrong.
/components.json
Every component's props, read out of the TypeScript types by the compiler rather than transcribed. The frontmatter has JSON Schema, at /schema.
narro check --fit
The loop an agent can run itself: names validated without a build, and --fit measures whether the content actually fits the canvas.
docspack ask "…"
Install the docs as a docspack and the agent asks instead of reading: at most three chunks and 3,000 tokens, answered from a local index with no network call.
@getnarro/mcp-server
Thirteen MCP tools for an assistant that has no shell — scaffold a deck, rewrite one slide, apply a theme, build, export.

One source. Six destinations.

Write it once. Send it anywhere it needs to land.

narro dev

Animated deck

Timed reveals, transitions and stage direction. Runs in the browser at 60fps.

narro build

Static deck

Same story, built to files you can host anywhere or hand over.

narro dev deck.md

Markdown → deck

Point it at a markdown deck. Headings become slides, frontmatter becomes props.

@getnarro/core

Full React deck

Slides are components. Hooks, state, effects, your own charts and canvases.

narro-video render

Video

Frame-accurate capture to MP4. Ship the same story as a launch film.

narro export --pdf

PDF

One page per slide, every fragment revealed. The version that gets forwarded.

The primitives

A deck has slides. A story has a shape.

Narro ships the beats a story is made of, so pacing is something you write down instead of something you hope for on the day.

  1. 01

    Tension

    A slide that holds keeps the room on the problem.

  2. 02

    Reveal

    <MotionStep> lands the answer on your cue.

  3. 03

    Pause

    Silence you can schedule, in milliseconds.

  4. 04

    Surprise

    Break your own grid on purpose, once.

  5. 05

    Resolution

    The ask, and where it leaves them.

Examples

Decks you can open, fork, present.

Browse all examples →
Docs

Quickstart

01 — install
npm i @getnarro/core @getnarro/cli

Adds @getnarro/core and the CLI. React 18+ and Node 20+.

02 — write a story
import { Motion, Notes, Presentation, Slide }
  from '@getnarro/core';
import { Heading, Text } from '@getnarro/shared-ui';

export default function Story() {
  return (
    <Presentation aspectRatio="16:9">
      <Slide id="intro">
        <Heading>We shipped the wrong thing.</Heading>
        <Notes>Slow down here.</Notes>
      </Slide>
      <Slide id="fix">
        <Motion effect="slide-up" delay={0.8}>
          <Text>Here is what we learned.</Text>
        </Motion>
      </Slide>
    </Presentation>
  );
}
03 — present it
narro dev story.tsx

Opens the stage with hot reload, speaker notes and a presenter clock.

04 — ship it
narro build
narro export --pdf
narro export --to pptx

Same source, every artefact. Nothing to re-lay-out by hand.

Docs

API reference

Full reference →

<Presentation>

The root of a story. Owns navigation, routing and the viewport scaling that keeps a deck legible from a laptop to a projector.

aspectRatio
"16:9" | "4:3" | "1:1"
Stage shape. Defaults to 16:9; slides letterbox rather than reflow.
theme
PresentationTheme
Fonts, palette and slide defaults for the whole deck.
autoPlay
boolean | number | number[]
Advance unattended. A number sets the dwell in ms, an array sets it per slide.
onSlideChange
(index: number) => void
Fires on every transition. Useful for analytics or captions.
maxDuration
number
Talk length in minutes, counted down in the presenter panel.
routing
boolean
Reflect the current slide in the URL so any frame is deep-linkable. On by default.

<Slide>

One frame of the story. Any React tree inside, including your own components.

id
string
Stable anchor. Deep-linkable, and the key used in exports and comments.
layout
LayoutType
Built-in composition — title, split, quote and the rest — or bring your own.
background
string
Any CSS colour or image value, applied to the slide root.
transition
"none" | "fade" | "slide" | "zoom"
How this slide arrives. Overrides the deck default.
subSlides
SubSlide[]
Steps within one frame, for content that builds rather than cuts.

Beats

Timing components. They read the slide's activation state, so a beat behaves the same on stage, in a static export and under a video render.

<Motion>
effect, delay, duration
Animate children in when the slide becomes active.
<MotionSteps>
totalSteps, loop
A sequence advanced by your keypress, not by a timer.
<MotionStep>
step: number
Shows once the sequence reaches its step. The deliberate reveal.
<MotionText>
MotionTextProps
Per-word or per-character entrance for a line that needs to land.
<Notes>
children
Speaker notes. Presenter view only, stripped from every export.

Hooks

Read and drive the story from inside your own components.

useNavigation()
NavigationState & Actions
Current slide plus next, previous, goToSlideById and fullscreen.
useSlideIndex()
number
The active slide index, for progress bars and chapter marks.
useSlideActive()
boolean
True while this slide is on stage. Gate your own animations on it.
useFragmentStep()
number
The current step inside a slide, for custom step-aware components.
useSlideSync()
SlideSyncControls
Drive a second screen, or follow one, over a sync channel.

CLI

One binary for the whole loop: author, check, present, export.

narro new
Scaffold a starter markdown deck.
narro dev <entry>
Stage with hot reload and presenter view.
narro check --fit
Validate a deck, and measure whether content actually fits.
narro build
Build for production. Pass a .md file for markdown mode.
narro export --pdf
PDF, one page per slide, every fragment revealed.
narro export --to pptx
PowerPoint, for the room that needs a .pptx.
narro bundle
One self-contained HTML file, nothing to serve.

Markdown

Front matter maps onto deck and slide props, so a markdown deck can grow into a React one without a rewrite.

title
string
Deck title. Window title and export metadata.
theme
string
A marketplace theme name, or a path to a local one.
template
string
The slide master this deck inherits from.
id
string
Per-slide. The same stable anchor `<Slide id>` takes.
layout
string
Per-slide. Resolved against your dir, then the theme, then built-ins.
notes
string
Per-slide speaker notes, without the HTML comment.
---
title: Q4 roadmap
theme: default
aspectRatio: "16:9"
---

# We shipped the wrong thing. {.text-7xl}

- Six weeks
- Two rewrites
- One good lesson

<!-- notes: Lead with the cost, then the lesson. -->

Your next deck is already a repo.