narratify
v2.2.0
Published
Narratify - Transform your web content into captivating audio experiences. A React TTS narration system for Next.js applications.
Maintainers
Readme
🎙️ Narratify
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 narratifyPrerequisites
- 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 objectautoStart?: boolean- Whether to start playing automaticallystartFromCue?: string- Cue ID to start fromshowVoiceSelector?: boolean- Whether to show voice selectiondefaultVoice?: VoiceConfig- Default voice configurationcontinuous?: boolean- Whether to play continuouslylocale?: string- Locale for voice selectiononClose?: () => 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 buttontoggleIcon?: 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
- Clone the repository:
git clone https://github.com/ebcont/narratify.git
cd narratify- Install dependencies:
pnpm install- Start development:
pnpm dev- Build the package:
pnpm build📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
🙏 Acknowledgments
- Built with React
- UI components powered by Radix UI
- Styled with Tailwind CSS
- Icons by Lucide React
Narratify - Where websites become podcasts 🎙️
Made with ❤️ by EBCONT Studio
