npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mermaid-flow-player

v2.0.0

Published

Animate Mermaid-rendered diagrams with semantic node/edge steps and scenarios

Readme

mermaid-flow-player

Step through your Mermaid diagrams. Add one script tag and every diagram on the page gets play, pause and step controls, narration, and a URL that links to a single step.

<script src="https://cdn.jsdelivr.net/npm/mermaid-flow-player/auto.global.js"></script>

<div class="mermaid">
  flowchart TD
    A[Validate token] --> B[Fetch user] --> C[Render page]
</div>

Save that as a file, open it in a browser, and it plays. Your markup does not change. Mermaid loads itself if it is not already on the page, and the CSS is bundled and injected.

Docs and live demos

Where your diagrams already live

Auto mode upgrades three shapes of markup with no configuration:

| Your markup | Emitted by | |---|---| | <div class="mermaid"> / <pre class="mermaid"> | hand-authored, Mermaid's own docs | | <pre><code class="language-mermaid"> | markdown-it, marked, Prism, Jekyll, Hugo, Eleventy | | <pre class="language-mermaid"> | Shiki, Astro, Starlight, VitePress, Docusaurus |

Each one is replaced in place by a <mermaid-flow-player>, keeping its id and your own classes. Point it somewhere else with ?selector=.

The upgrade needs the diagram source, so let the player render: don't run Mermaid with startOnLoad: true first. If a block is already rendered its SVG is adopted rather than discarded, but narration falls back to node labels because the source text is gone.

Authoring new diagrams

Write the diagram inside the element and set options per diagram:

<script src="https://cdn.jsdelivr.net/npm/mermaid-flow-player/mermaid-flow-player.element.js"></script>

<mermaid-flow-player controls captions>
  flowchart TD
    A[Validate token] --> B[Fetch user]
    %% narrate A: First we check the caller's token hasn't expired.
</mermaid-flow-player>

There is one player implementation, so both routes get the same features: the element is what the upgrade produces. Configure a block with the same attribute names the element uses (speed, captions, speak...), with or without a data-flow- prefix.

Install

The CDN needs no install. For a bundler:

npm install mermaid-flow-player
import 'mermaid-flow-player/auto';

CDN URL builder: docs site -> CDN Builder. Pick options and copy script tags or query params.

Usage (programmatic)

import { createFlowPlayer } from 'https://cdn.jsdelivr.net/npm/mermaid-flow-player';

// Read the source before Mermaid renders: afterwards the element holds the drawing.
const root = document.getElementById("diagram");
const source = root.textContent;
const player = createFlowPlayer({
  root,
  source,
  visited: true,
  dim: "others",
});

await player.ready();
await player.play(player.path("A", "B", "C", "E", "F", "G", "J"), { speed: 1.1 });

The player reads the diagram through window.mermaid, the same Mermaid that drew it. A bundler that imports Mermaid as a module sets it with window.mermaid = mermaid before creating a player.

Use stable, simple node IDs in your Mermaid diagram (e.g. A, B, X1) so path() and steps line up.

Animated SVG, for where JavaScript cannot run

A README, a pull request comment, an issue, an email: none of them run scripts, so none of them can run a player. toAnimatedSvg draws a scenario as one self-contained file that animates on its own.

const svg = player.toAnimatedSvg(
  [
    { type: 'node', id: 'A' },
    { type: 'edge', from: 'A', to: 'B' },
    { type: 'node', id: 'B' },
  ],
  { title: 'How a request is served' },
);

No script, no external references, nothing to fetch. Options: stepMs (default 1200), loop (default true), title, accent, restOpacity. A reader whose system asks for less motion gets the finished diagram, still.

Features

Multi-Diagram Support

Auto-detects and animates 7 diagram types:

  • Flowcharts, Sequence Diagrams, State Diagrams, Gantt Charts, User Journey, Class Diagrams, ER Diagrams

All diagram types use the same animation API; just change your Mermaid diagram type and the player adapts automatically.

Narration

Automatically update narration text as animation progresses:

createFlowPlayer({
  root: diagram,
  source,
  narrationTarget: '#narration',
});

await player.play([
  { type: 'node', id: 'A', note: 'Starting...' },
  { type: 'node', id: 'B', note: 'Processing...' },
]);

Narrated walkthroughs — captions, voice, transcript, deep-links

Every step (auto-play and manual Next/Previous) emits a single mfp:step event, and the per-step text is auto-derived from the Mermaid markup — a sequence message's label or a node's label — so authors get narration for free just by writing normal diagrams. Sequence diagrams step through their messages in order.

Sequence Note over/of … lines are picked up automatically as the richer commentary for the message they follow; otherwise the message label is used.

Write a script with %% narrate. Node labels are terse ("Validate token") but spoken narration wants a sentence. Put the script in the diagram itself and it travels with the fenced code block — copy-paste safe, Markdown-native, and a coding agent can emit a diagram that explains its own flow in one shot:

<mermaid-flow-player controls captions speak>
  flowchart TD
    A[Validate token] --> B[Fetch user]
    %% narrate A: First we check the caller's token hasn't expired.
    %%   Expired tokens stop here.
    %% narrate B: Then we load their profile from cache.
</mermaid-flow-player>

A %% line indented by two or more spaces continues the previous directive, so long narration can wrap. Scripts override the derived label everywhere at once — captions, voice, chapters, transcript and VTT. Parse them yourself with parseNarration(source).

On a sequence diagram, an id-less %% narrate: attaches to the message above it — the same way Note over already does. Put %% voice <participant>: name in the source too, so each speaker keeps their voice when the fenced block is copied:

<mermaid-flow-player controls captions chapters speak karaoke>
  sequenceDiagram
    %% voice Req: daniel
    %% voice W: samantha
    Req->>W: POST /access-requests
    %% narrate: A worker validates the caller and opens a request.
    W->>WF: create instance
    WF->>Req: signed approval link
</mermaid-flow-player>

parseVoices(source) returns the participant → voice map. Host JavaScript el.voices still wins when set.

Opt-in attributes:

| Attribute | Effect | | --- | --- | | captions | Live caption bar showing the current step's text (ARIA-announced). | | speak | Reads each step aloud via the browser's SpeechSynthesis — zero audio files. | | chapters | Clickable chapter rail (one entry per step); click to jump. | | karaoke | Auto-advances when each step's narration (audio clip or voice) ends. | | scroll-steps | Drives the step index from page scroll (scrollytelling). | | progress | A "Step 3 of 9" position indicator. | | step="N" / ?step=N | Deep-link straight to a step. |

Keyboard

Playback keys work on the element whether or not you render controls, and are ignored while the reader is typing in an input, textarea or contenteditable:

| Key | Action | | --- | --- | | Space / k | Play, pause, resume. | | / | Previous / next step. | | Shift+/, / | Pan the viewport. | | + / - / 0 | Zoom in / out / fit. | | f / Escape | Open / close the focused view. |

Loading and error states

The element shows a .mfp-loading placeholder while Mermaid loads and renders, then replaces it with the diagram. If rendering fails it shows a .mfp-error box (role="alert") instead of leaving an empty element that looks like it is still loading. mfp:error still fires either way; add silent-errors to suppress the visible box and handle the event yourself.

Shape the voice (all read live — no re-render, safe to change mid-playback):

| Attribute | Effect | | --- | --- | | rate="0.9" | Speaking rate, 0.110. The default is brisk for a walkthrough; 0.9 reads better. | | pitch="1.2" | Voice pitch, 02. | | volume="0.5" | Narration volume, 01. | | lang="en-GB" | BCP-47 language for the utterance. | | voice="samantha" | Voice name, matched case-insensitively as a substring — voice names differ per platform, so a fragment beats hard-coding Samantha (Enhanced). Unmatched names keep the platform default. | | pause-between="400" | Milliseconds of silence before karaoke advances. Without it steps advance the instant the voice stops, which reads like a queue draining rather than someone talking. |

While speaking, the caption highlights the current word (.mfp-word, styleable via --mf-word-bg / --mf-word-color) in time with the voice.

Give each participant its own voice and a sequence diagram reads like a conversation instead of one narrator — %% voice in the source (above), or from JavaScript:

el.voices = (index) => (index % 2 === 0 ? 'daniel' : 'samantha');

Browsers refuse speech until the page has had a user gesture, and they fail silently. The element shows a Tap to enable voice control (.mfp-tap-to-speak) and fires mfp:speech-blocked once, so a host can hide the default button and prompt itself:

el.addEventListener('mfp:speech-blocked', () => showTapToStartButton());

Hook mfp:step to drive your own audio commentary, analytics, or scroll-sync — it fires on auto-play and manual stepping with { index, node, text }:

const el = document.querySelector('mermaid-flow-player');
// Option A: bind clips and let the player manage playback (+ karaoke timing)
el.audioTracks = { 0: 'audio/01.mp3', 1: 'audio/02.mp3' };
// Option B: react to the event yourself
el.addEventListener('mfp:step', (e) => {
  const { index, node, text } = e.detail;   // text = markup-derived narration
  analytics.track('diagram_step', { index, text });
});

Browser autoplay rules apply: bound audio plays after a user gesture (clicking Play/Next), so karaoke runs once the reader interacts.

Build a transcript, captions file, or chapter list from the steps:

import { toTranscript, toVtt } from 'mermaid-flow-player';
const steps = el.player.getSteps();   // [{ index, node, text, speaker }, ...]
toTranscript(steps);                   // "1. ...\n2. ..." (Markdown/plain text)
toVtt(steps, { secondsPerCue: 5 });    // WebVTT subtitle track

Playback Speed & Progress

Change speed live (even mid-run) and track progress for scrubbers/progress bars:

player.setSpeed(2);            // applies immediately; emits mfp:speedchange
player.getSpeed();             // 2
player.getProgress();          // { current: 3, total: 8 } or null before first run
el.addEventListener('mfp:progress', (e) => {
  const { current, total } = e.detail;
  progressBar.style.width = `${(current / total) * 100}%`;
});

Export

Copy or download the current diagram state — including mid-animation:

await player.copySvg();                    // SVG markup to clipboard
player.downloadSvg('flow.svg');
await player.downloadPng('flow.png', { scale: 2 }); // rasterized at 2x

Animation Easing

Control animation timing with 30+ easing functions: standard CSS, back, elastic, bounce, power curves, and custom cubic-bezier().

createFlowPlayer({
  root: diagram,
  source,
  easing: {
    default: 'ease-out-back',
    states: {
      active: 'ease-out-elastic',
      success: 'ease-out-bounce',
    }
  }
});

Web Component

Drop-in <mermaid-flow-player> custom element. Diagram from inner text (or diagram attribute):

<script src="https://cdn.jsdelivr.net/npm/mermaid-flow-player@latest/mermaid-flow-player.element.js"></script>

<mermaid-flow-player autoplay controls>
  graph LR; A-->B-->C
</mermaid-flow-player>

Narration is opt-in: add the narration attribute (or narration-text="…") to show the narration area; otherwise it isn't rendered. Playback exposes a single lifecycle status — "idle" | "playing" | "paused" — via el.player.getStatus(), and every transition fires a bubbling mfp:statechange event (detail.status), which the play/pause control reflects automatically.

Interactive Mode

Step-through with user-controlled path selection:

const player = createFlowPlayer({ root: diagram, source, mode: 'interactive' });
await player.nextStep();

Viewport & readable fit

Zoom, pan, and fitView() keep large diagrams legible: fit never shrinks below a readable floor, so when a diagram is too big to show whole it stays readable and the viewport scrolls/pans (pinned to the start) instead of becoming a postage stamp. Tune the floor with viewport.minReadableScale (default 0.6):

createFlowPlayer({ root: diagram, viewport: { minReadableScale: 0.6 } });

Validation and user feedback

Diagram validity comes from Mermaid (they run in the browser). We propagate their errors; listen for mfp:error or use normalizeMermaidError(e) when you call mermaid.run() / mermaid.render(). For scenario-vs-index (after render), use player.validateScenario(steps) and show result.availableNodeIds for suggestions.

import { normalizeMermaidError } from '…';
try {
  await mermaid.run({ nodes: [el] });
} catch (e) {
  const payload = normalizeMermaidError(e);
  showInUI(payload.message, payload.detail);
}

Scenario-vs-index (after the diagram has rendered): use player.validateScenario(steps) to check that step IDs exist and get availableNodeIds for "Did you mean: A, B, C?". assertIds(ids) throws with available node IDs in the message.

Upgrading .mermaid blocks yourself

Auto mode runs this for you on load and re-runs it when an SPA swaps the DOM. Call it directly to control when, or to point it at a different selector:

import { autoInit } from 'https://cdn.jsdelivr.net/npm/mermaid-flow-player@latest/auto-init.js';

autoInit({ selector: '.diagram', controls: 'play-pause next fit' });

controls takes true (transport plus zoom), false, a preset ("viewer", "full"), or an explicit space-separated token list. The same values work in the element's controls attribute. destroyAll() puts the original blocks back.

Web font

The player asks for JetBrains Mono only if you opt in — otherwise it uses the system monospace stack and makes no third-party request:

<script data-mfp-font src="…/mermaid-flow-player.element.js"></script>

URL Query Parameter Configuration

Configure via URL without JavaScript: page.html?theme=dark&speed=1.5

| Parameter | Values | Default | | --- | --- | --- | | theme | light, dark, auto | auto | | speed | 0.1 to 10 | 1.2 | | stepMs | milliseconds per step | derived from speed | | visited | true, false | true | | mode | sequential, interactive | sequential | | selector | CSS selector (e.g. .my-diagram) | .mermaid (auto mode only) | | step | step index to deep-link to | none | | autoplay | (presence) | false | | trigger | load, scroll | load | | debug | (presence) | false |

License

MIT