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 🙏

© 2025 – Pkg Stats / Ryan Hefner

narratify

v2.2.0

Published

Narratify - Transform your web content into captivating audio experiences. A React TTS narration system for Next.js applications.

Readme

🎙️ Narratify

npm version License: MIT TypeScript

Transform your web content into captivating audio experiences

Narratify is a powerful React TTS (Text-to-Speech) narration system for Next.js applications. Turn any website into an engaging podcast-like experience with support for multiple voice providers, customizable controls, and seamless integration.

✨ Features

  • 🎙️ Multiple Voice Providers: Support for browser TTS and ElevenLabs API
  • 🌍 Multi-language Support: Automatic voice selection based on locale
  • 🎛️ Standard Audio Player Controls: Play, pause, skip, restart, and voice selection
  • 📱 Responsive Design: Works seamlessly on desktop and mobile devices
  • Accessibility: Built with accessibility in mind, keyboard navigation support
  • 🎨 Customizable UI: Uses Tailwind CSS with fully customizable components
  • 🔄 Continuous Playback: Automatic progression through content sections
  • 🎯 Visual Highlighting: Highlights current content during narration
  • ⏯️ Smart Pause/Resume: Position tracking for seamless pause and resume experience
  • ⌨️ Keyboard Shortcuts: Space for play/pause, arrow keys for navigation

📦 Installation

# Using pnpm (recommended)
pnpm add narratify

# Using npm
npm install narratify

# Using yarn
yarn add narratify

Prerequisites

  • React 18.0.0 or higher
  • Next.js 13.0.0 or higher (for full functionality)
  • Tailwind CSS (for styling)

CSS Variables

Narratify uses CSS custom properties for theming and dark mode support. See CSS_VARIABLES.md for the complete list of required variables and theming examples.

🚀 Quick Start

1. Basic Usage

import { Narratify } from 'narratify';

function MyComponent() {
  const narrationScript = {
    'intro': 'Welcome to Narratify - where websites become podcasts',
    'main-content': 'Transform any content into an engaging audio experience',
    'conclusion': 'Thank you for using Narratify!'
  };

  return (
    <Narratify 
      narrationScript={narrationScript}
      autoStart={false}
      showVoiceSelector={true}
    />
  );
}

2. With Toggle Button

import { NarratifyWithToggle, DEFAULT_VOICE_CONFIGS } from 'narratify';

function MyComponent() {
  const narrationScript = {
    'intro': 'Welcome to our application',
    'main-content': 'This is the main content area'
  };

  return (
    <NarratifyWithToggle 
      narrationScript={narrationScript}
      defaultVoice={DEFAULT_VOICE_CONFIGS["browser-google-us"]}
      continuous={true}
    />
  );
}

3. Flexible Integration (New in v2.1.0)

For maximum layout flexibility, you can now separate the toggle button and controls:

import { 
  NarratifyProvider, 
  NarratifyToggleButtonWithProvider, 
  NarratifyControlsWithProvider 
} from 'narratify';

function MyApp() {
  const narrationScript = {
    'intro': 'Welcome to our flexible integration example',
    'content': 'Toggle button in header, controls at bottom'
  };

  return (
    <NarratifyProvider>
      {/* Header with Toggle Button */}
      <header>
        <h1>My App</h1>
        <NarratifyToggleButtonWithProvider />
      </header>

      {/* Main Content */}
      <main>
        <h2 data-cue="intro">Flexible Integration</h2>
        <p data-cue="content">Content here...</p>
      </main>

      {/* Sticky Controls at Bottom */}
      <NarratifyControlsWithProvider 
        position="bottom"
        sticky={true}
        showVoiceSelector={true}
      />
    </NarratifyProvider>
  );
}

4. Manual Integration with Context

For complete control, use the context directly:

import { 
  NarratifyProvider, 
  useNarratifyContext 
} from 'narratify';

function CustomToggleButton() {
  const { isActive, isPlaying, isPaused, toggleActive } = useNarratifyContext();
  
  return (
    <button onClick={toggleActive}>
      {!isActive ? 'Start' : isPaused ? 'Resume' : 'Pause'}
    </button>
  );
}

function MyApp() {
  return (
    <NarratifyProvider>
      <header>
        <CustomToggleButton />
      </header>
      {/* Your custom controls and content */}
    </NarratifyProvider>
  );
}

3. Using the Hook Directly

import { useNarratify, DEFAULT_VOICE_CONFIGS } from 'narratify';

function MyCustomComponent() {
  const {
    isPlaying,
    currentCue,
    play,
    pause,
    restart
  } = useNarratify({
    narrationScript: myScript,
    voiceConfig: DEFAULT_VOICE_CONFIGS.browser.en
  });

  return (
    <div>
      <button onClick={play}>Play</button>
      <button onClick={pause}>Pause</button>
      <button onClick={restart}>Restart</button>
      {currentCue && <p>Current: {currentCue.text}</p>}
    </div>
  );
}

4. Content Markup

Mark your content with data-cue attributes:

<div>
  <h1 data-cue="intro">Welcome to Our App</h1>
  <section data-cue="main-content">
    <p>This content will be highlighted during narration.</p>
  </section>
  <footer data-cue="conclusion">
    <p>Thank you for visiting!</p>
  </footer>
</div>

📖 Components

Narratify

The main narrator component with built-in controls.

Props:

  • narrationScript?: NarrationScript - The narration script object
  • autoStart?: boolean - Whether to start playing automatically
  • startFromCue?: string - Cue ID to start from
  • showVoiceSelector?: boolean - Whether to show voice selection
  • defaultVoice?: VoiceConfig - Default voice configuration
  • continuous?: boolean - Whether to play continuously
  • locale?: string - Locale for voice selection
  • onClose?: () => void - Callback when narrator is closed

NarratifyWithToggle

A narrator with a toggle button for easy activation.

Props:

  • Same as Narratify plus:
  • toggleText?: string - Text for the toggle button
  • toggleIcon?: ReactNode - Icon for the toggle button

SimpleNarratify

A simplified version with minimal UI.

NarratifyControls

Standalone controls component for custom implementations.

VoiceSelector

Voice selection component with support for multiple providers.

🎣 Hooks

useNarratify

The main hook for TTS functionality.

Parameters:

interface UseNarratifyProps {
  narrationScript?: NarrationScript;
  voiceConfig?: VoiceConfig;
  autoStart?: boolean;
  continuous?: boolean;
}

Returns:

interface UseNarratifyReturn {
  isPlaying: boolean;
  isPaused: boolean;
  currentCueIndex: number;
  totalCues: number;
  currentCue: NarrationCue | null;
  error: string | null;
  play: () => void;
  pause: () => void;
  restart: () => void;
  playNext: () => void;
  playPrevious: () => void;
}

🎵 Voice Providers

Browser TTS

Uses the browser's built-in text-to-speech API.

import { DEFAULT_VOICE_CONFIGS } from 'narratify';

const voiceConfig = DEFAULT_VOICE_CONFIGS.browser.en;
// or
const voiceConfig = DEFAULT_VOICE_CONFIGS.browser.es;
const voiceConfig = DEFAULT_VOICE_CONFIGS.browser.fr;

ElevenLabs API

Uses ElevenLabs API for high-quality voices (requires API key).

const voiceConfig = {
  provider: 'elevenlabs' as const,
  voiceId: 'your-voice-id',
  apiKey: 'your-api-key'
};

For ElevenLabs integration, set up an API route in your Next.js app:

// app/api/tts/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { text, voiceId, apiKey } = await request.json();
  
  const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
    method: 'POST',
    headers: {
      'Accept': 'audio/mpeg',
      'Content-Type': 'application/json',
      'xi-api-key': apiKey,
    },
    body: JSON.stringify({
      text,
      model_id: 'eleven_monolingual_v1',
      voice_settings: {
        stability: 0.5,
        similarity_boost: 0.5,
      },
    }),
  });

  if (!response.ok) {
    return NextResponse.json({ error: 'Failed to generate speech' }, { status: 500 });
  }

  const audioBuffer = await response.arrayBuffer();
  const base64Audio = Buffer.from(audioBuffer).toString('base64');
  const audioUrl = `data:audio/mpeg;base64,${base64Audio}`;

  return NextResponse.json({ audioUrl });
}

📝 Narration Scripts

Narration scripts are objects that map cue IDs to text:

const narrationScript = {
  'intro': 'Welcome to our application',
  'main-content': 'This is the main content area',
  'features': 'Here are our amazing features',
  'conclusion': 'Thank you for using our application'
};

Dynamic Script Loading

import { loadNarrationScript } from 'narratify';

// Load from JSON file
const script = await loadNarrationScript('/path/to/script.json');

// Load from URL
const script = await loadNarrationScript('https://api.example.com/narration-script');

🎨 Styling

The package uses Tailwind CSS for styling. You can customize the appearance by:

1. CSS Custom Properties

:root {
  --tts-primary-color: #3b82f6;
  --tts-secondary-color: #6b7280;
  --tts-background-color: #ffffff;
  --tts-text-color: #1f2937;
}

2. Component Class Overrides

<Narratify 
  className="custom-narrator-styles"
  narrationScript={script}
/>

3. Custom UI Components

You can replace the built-in UI components:

import { Button, Card } from './custom-ui-components';

⌨️ Keyboard Shortcuts

  • Space: Play/Pause
  • Arrow Left: Previous cue
  • Arrow Right: Next cue
  • R: Restart
  • Escape: Close narrator

🔧 Advanced Configuration

Custom Voice Configuration

const customVoice: VoiceConfig = {
  provider: 'browser',
  lang: 'en-US',
  voice: 'Google US English',
  rate: 1.0,
  pitch: 1.0,
  volume: 1.0
};

Event Callbacks

<Narratify
  narrationScript={script}
  onPlay={() => console.log('Started playing')}
  onPause={() => console.log('Paused')}
  onEnd={() => console.log('Finished')}
  onCueChange={(cue) => console.log('Current cue:', cue)}
/>

📱 Mobile Considerations

The package is fully responsive and includes:

  • Touch-friendly controls
  • Optimized for mobile browsers
  • Automatic audio context handling
  • Battery-efficient playback

🧪 Examples

Check out the /examples directory for complete implementation examples:

  • Simple Example: Basic usage with minimal setup
  • Next.js Example: Full integration with Next.js app
  • Custom Implementation: Advanced customization examples

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

  1. Clone the repository:
git clone https://github.com/ebcont/narratify.git
cd narratify
  1. Install dependencies:
pnpm install
  1. Start development:
pnpm dev
  1. Build the package:
pnpm build

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

🙏 Acknowledgments


Narratify - Where websites become podcasts 🎙️
Made with ❤️ by EBCONT Studio