✨ Animation

How do I reveal a list one line at a time, or move between slides with something other than a cut?

Fragments

A fragment reveals part of a slide on the next keypress instead of showing everything at once.

import { Fragment } from "@getnarro/shared-ui";

<Slide id="reveal">
  <SlideContent>
    <Heading level={2}>Progressive reveal</Heading>

    <Fragment order={1}>
      <Text>Appears first</Text>
    </Fragment>

    <Fragment order={2} effect="slide-up">
      <Text>Appears second, sliding up</Text>
    </Fragment>

    <Fragment order={3} effect="scale-in" duration={400}>
      <Text>Then this</Text>
    </Fragment>
  </SlideContent>
</Slide>;

Fragment comes from @getnarro/shared-ui, not @getnarro/core.

PropTypeDefault
ordernumbersource order
effectFragmentEffect"fade-in"
durationnumber (ms)
staggerDelaynumber (ms)
isActivebooleaninherited from the slide

FragmentEffect is “fade-in” | “fade-out” | “slide-up” | “slide-down” | “slide-left” | “slide-right” | “scale-in” | “scale-out” | “blur-in”.

Fragments consume a navigation step: on a slide with three fragments, the first three presses reveal them and the fourth advances. Every key that advances a slide advances a fragment too, including the PageDown a presenter’s clicker sends.

Without an explicit order, fragments reveal in source order. Set order when you want a different one — two fragments sharing an order reveal together.

trigger="time" opts out: those fragments reveal on slide entry, staggered by staggerDelay, and do not consume a press — a slide holding only time-triggered fragments advances on the first press, not on the nth.

Fragments without an explicit order are numbered in source order, and the numbering depends only on what is mounted — so a slide costs the same number of presses every time it is entered.

<Fragment>revealed first</Fragment>
<Fragment>then this</Fragment>
<Fragment trigger="time">already there when the slide opens</Fragment>

Used outside a Slide — a component in a storybook, a page that is not a deck — there is nothing to step, so a fragment reveals on mount.

In markdown mode the equivalent is {.step}, and it behaves the same way:

- appears first {.step}
- appears second {.step delay=200}

Slide transitions

<Slide transition="fade">…</Slide>

"none" | "fade" | "slide" | "zoom". In markdown, set transition: in slide frontmatter, or on the deck to change the default for every slide.

Motion primitives

@getnarro/core wraps Framer Motion in components that already know whether their slide is on screen — animations start when the slide appears, not when the deck mounts.

import { Motion, MotionNumber, MotionText } from "@getnarro/core";

<Motion effect="slideUp" delay={0.2}>
  <Heading level={1}>Animated in</Heading>
</Motion>

<MotionText type="wordByWord">One word at a time</MotionText>

<MotionNumber value={42} suffix="%" decimals={0} />

Units differ between the two families, and nothing warns. Durations and delays on Motion* components are in seconds (Framer Motion’s convention); everything in shared-uiFragment.duration, TypewriterText.speed, CountingNumber.duration — is in milliseconds. duration={2} is two seconds in one and two milliseconds in the other, and both are valid numbers. The rule that always holds: core is seconds, shared-ui is milliseconds.

Which of the two to reach for

Fragment and MotionSteps/MotionStep both stage a slide in pieces, and they are not interchangeable — the difference is who owns the presenter’s keypresses:

Fragment (shared-ui)MotionSteps / MotionStep (core)
NavigationConsumes a keypress per fragment. The slide takes N presses to leaveConsumes nothing. It manages its own index and needs totalSteps
UnitsMillisecondsSeconds
Built onCSS keyframesFramer Motion
Reach for it whenThe presenter should reveal the slide at their own pace — the common caseThe sequence is a self-contained animation you want to replay or drive yourself

If you want “press space, the next thing appears”, that is Fragment. Mixing both on one slide means two things claiming the same keypress, so pick one per slide.

MotionEffect is “fadeIn” | “fadeOut” | “slideUp” | “slideDown” | “slideLeft” | “slideRight” | “scaleUp” | “scaleDown” | “rotateIn” | “flip” | “bounce” | “elastic” | “blur” | “glow” | “typewriter” | “spotlight” | “parallax” | “morphPath” | “stagger” | “wave”.

See the component reference for the full set — Motion, MotionContainer, MotionList, MotionText, MotionNumber, MotionPresence, MotionSpotlight, MotionSteps, MotionStep, MotionTransform.

Gating your own animation

To drive animation yourself, ask whether the slide is active. Both packages export the hook — @getnarro/shared-ui and @getnarro/core — and both read the context Slide provides, so either import works:

import { useSlideActive } from "@getnarro/shared-ui";

function Chart() {
  const isActive = useSlideActive();
  return <svg className={isActive ? "animate-draw" : "opacity-0"} />;
}

Without this, every animation on every slide fires on load and is finished before the audience sees it.

Respecting reduced motion

Motion components honour prefers-reduced-motion. If you hand-roll animation, gate it the same way:

@media (prefers-reduced-motion: reduce) {
  .animate-draw {
    animation: none;
  }
}
IntroductionWhat is Narro, and should I be writing markdown or React?
InstallationWhat do I install, and what does the project look like afterwards?
First DeckWhat does a working React deck look like, end to end?
Markdown ModeHow do I split a slide, style one word, or reveal a line — without leaving the markdown file?
Writing AI PromptsWhat do I tell an AI so the deck it writes actually builds?
Rules for AI AgentsWhat do I paste into my repo so an agent stops writing decks that build wrong?
React APIWhich component or hook do I import, and what does it take?
CLIWhich command do I run, and what are its flags?
Markdown APIHow do I read, edit, or validate a deck file from my own code instead of by hand?
Component ReferenceWhat props does this component take, and which package do I import it from?
Verifying a deckHow do I know my deck is actually correct?
AnimationHow do I reveal a list one line at a time, or move between slides with something other than a cut?
NavigationHow does the audience move through the deck, and how do I present it?
Canvas & PositioningHow do I put something at an exact position instead of in the flow?
Images & MediaHow do I use an image as a background, tint it, or embed a video?
ArchitectureWhich package owns what, and why is the seam where it is?
Transform ModeHow do I zoom and pan across one big canvas instead of cutting between slides?
Import & ExportHow do I get this deck out as PPTX, PDF, or one file I can email?
AI IntegrationHow do I wire an AI assistant up to Narro so it can write and build decks?
ThemingHow do I change the colours, fonts, and overall look of a deck?
Deck TemplatesHow do I define one house style with named layouts my slides can reference, like a PowerPoint master?
TroubleshootingSomething is wrong with my deck. What is it, and how do I fix it?
LimitationsWhat can't Narro do, and what do I do instead?