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

@buzztrail-ai/presentation

v1.4.1

Published

AI-powered slide presentations with voice interaction for any website platform.

Readme

@buzztrail-ai/presentation

AI-powered slide presentations with voice interaction for any website platform.

npm version

Overview

@buzztrail-ai/presentation enables AI-powered slide presentations with voice interaction on any website platform. Add an interactive AI-guided slide deck to your site in minutes - no complex setup required.

⚠️ Account Required: You need an active BuzzTrail account to use this package. Sign up at buzztrail.ai to get your customer ID and configure your presentations.

Features

  • Interactive AI Presentations: Engage website visitors with AI-guided slide presentations
  • Voice Interaction: Natural voice conversations about slide content
  • Manual Controls: Optional manual slide navigation controls
  • Works Everywhere: Wix, Webflow, WordPress, Shopify, or any custom website
  • Simple Integration: Just call createPresentation()
  • Fast Loading: Ultra-lightweight package that won't slow down your site
  • Mobile-Friendly: Automatically adapts to desktop, tablet, and mobile screens
  • Customizable: Match your brand with custom colors and theming
  • Lead Capture: Optional forms to collect visitor information before presentations
  • Real-time Sync: Slide changes sync across all viewers in real-time
  • No Technical Skills: Works without coding knowledge (perfect for Wix users)

Getting Started

Prerequisites

  1. BuzzTrail Account: Sign up at buzztrail.ai
  2. Customer ID: You'll receive this after account setup
  3. Deck ID: Create a presentation deck in the BuzzTrail dashboard
  4. Supabase Credentials: You'll receive these from BuzzTrail support

Installation

NPM (for developers)

npm install @buzztrail-ai/presentation
yarn add @buzztrail-ai/presentation
pnpm add @buzztrail-ai/presentation

CDN (for Wix, Webflow, no-code platforms)

<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>

Fallback CDN (unpkg):

<script src="https://unpkg.com/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>

Quick Start

CDN Usage (Wix, Webflow, etc.)

<!-- 1. Add a container element to your page -->
<div id="presentation-container"></div>

<!-- 2. Add the BuzzTrail Presentation script -->
<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>

<!-- 3. Initialize the presentation -->
<script>
  const presentation = createPresentation('presentation-container', {
    customerId: 'your-customer-id',
    deckId: 'your-deck-id',
    supabaseUrl: 'https://your-project.supabase.co',
    supabaseKey: 'your-anon-key'
  });

  // Start the presentation
  presentation.start();
</script>

That's it! The interactive presentation will appear in your container.

With Callbacks

For more control, add callback functions:

<div id="my-presentation"></div>

<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>
<script>
  const presentation = createPresentation('my-presentation', {
    customerId: 'your-customer-id',
    deckId: 'your-deck-id',
    supabaseUrl: 'https://your-project.supabase.co',
    supabaseKey: 'your-anon-key',

    onStart: () => console.log('Presentation started'),
    onEnd: () => console.log('Presentation ended'),
    onError: (error) => console.error('Error:', error),
    onStateChange: (state) => console.log('State:', state)
  });

  presentation.start();
</script>

NPM Usage (TypeScript/JavaScript)

import { createPresentation } from '@buzztrail-ai/presentation';
import type { PresentationConfig } from '@buzztrail-ai/presentation';

const config: PresentationConfig = {
  customerId: 'acme-corp',
  deckId: 'product-demo-2024',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',

  // Optional: Viewer configuration
  viewer: {
    position: 'center',
    showControls: true,
    controlsPosition: 'bottom',
    aspectRatio: '16:9',
    showLoading: true,
    loadingMessage: 'Loading presentation...'
  },

  // Optional: Theme
  theme: 'auto', // 'light', 'dark', or 'auto'

  // Optional: Lead capture
  gating: {
    enabled: true,
    fields: ['email', 'name']
  },

  // Lifecycle callbacks
  onStart: () => {
    console.log('Presentation started');
  },
  onEnd: () => {
    console.log('Presentation ended');
  },
  onError: (error) => {
    console.error('Error:', error);
  },
  onStateChange: (state) => {
    console.log('State changed:', state);
  }
};

const presentation = createPresentation('my-container', config);

// Start the presentation
await presentation.start();

// Later: End the presentation
await presentation.end();

// Get current state
const state = presentation.getState(); // 'idle' | 'connecting' | 'connected' | 'disconnected'

// Cleanup
presentation.destroy();

Demo Experience

The createDemoExperience() function provides an automated investor demo experience with greeter agent warmup and seamless handoff to presentation.

Features:

  • Automatic greeter agent (50-second warmup by default)
  • Natural conversation before presentation
  • Seamless transition to slide presentation
  • Configurable timeline (50s or 20s for testing)
  • System defaults for quick setup

Basic Usage:

import { createDemoExperience } from '@buzztrail-ai/presentation';

const demo = createDemoExperience('container', {
  // Required
  customerName: 'Jane Investor',
  customerEmail: '[email protected]',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',
});

await demo.start();

With Custom Options:

const demo = createDemoExperience('container', {
  // Required
  customerName: 'Jane Investor',
  customerEmail: '[email protected]',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',

  // Optional
  customerCompany: 'Acme Corp',
  deckUrl: 'https://example.com/custom-deck',
  timelineConfig: 'investor_demo_quick', // 20s handoff for testing

  // Callbacks
  onHandoff: () => console.log('Transitioning to presentation!'),
  onStart: () => console.log('Demo started'),
  onEnd: () => console.log('Demo ended'),
});

await demo.start();

Timeline Configurations:

  • investor_demo (default): 50-second greeter warmup
  • investor_demo_quick: 20-second warmup for testing

System Defaults:

  • Falls back to default investor deck if no deckUrl provided
  • Timeline defaults to investor_demo (50s)

CDN Usage:

<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/[email protected]/index.umd.js"></script>
<script>
  const demo = BuzztrailPresentation.createDemoExperience('container', {
    customerName: 'Jane Investor',
    customerEmail: '[email protected]',
    supabaseUrl: 'https://your-project.supabase.co',
    supabaseKey: 'your-anon-key',
  });

  demo.start();
</script>

Wix Integration Guide

Wix requires special handling due to iframe permission restrictions. Follow these steps:

Step 1: Add a Container Element

  1. Open Wix Editor for your site
  2. Click "Add Elements" (+) → Select "Strip" or "Box"
  3. Position and size the element where you want the presentation (recommended: 900x600px or larger)
  4. Right-click the element → "View Properties" → Note the Element ID (e.g., comp-mfy88b7h)

Step 2: Add BuzzTrail via Custom Code

  1. Open SettingsAdvancedCustom Code
  2. Click "+ Add Custom Code"
  3. Paste the following code (replace credentials and element ID):
<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>
<script>
  const presentation = createPresentation('comp-mfy88b7h', {
    customerId: 'your-customer-id',
    deckId: 'your-deck-id',
    supabaseUrl: 'https://your-project.supabase.co',
    supabaseKey: 'your-anon-key'
  });

  presentation.start();
</script>
  1. Configure the snippet:
    • Name: BuzzTrail Presentation
    • Add to Pages: Choose "All pages" or specific pages
    • Place Code in: Select "Body - end" (recommended)
  2. Click "Apply"
  3. Publish your site

Finding the Correct Container ID

Each Wix page element has a unique ID. To find the correct container ID for your page:

  1. Open your published Wix page in a browser
  2. Open the browser's Developer Tools (F12 or right-click → Inspect)
  3. In the Console tab, paste this code and press Enter:
document.querySelectorAll('[id^="comp-"]').forEach(el => {
  console.log(`ID: ${el.id}, Size: ${el.offsetWidth}x${el.offsetHeight}px`);
});
  1. Look for a container with dimensions around 900x600px or larger - this is ideal for presentation display
  2. Copy that container's ID (e.g., comp-abc123xyz) and use it in createPresentation()

Why Custom Code (Not Embed HTML)?

  • Wix Embed HTML wraps code in an iframe, which blocks camera/microphone permissions
  • Custom Code runs directly on the page, allowing proper permissions for voice interaction
  • This is the only way to enable voice-interactive presentations on Wix

TypeScript Support

This package includes full TypeScript type definitions. No need to install @types packages.

Type Imports

import type {
  // Main API
  Presentation,
  PresentationConfig,
  PresentationState,

  // Configuration types
  ViewerConfig,
  GatingConfig,
  ThemeMode,
  PresentationThemeConfig,

  // Session types
  Session,
  SessionState,

  // Error types
  PresentationError,
  SessionError,
  NetworkError,
  BotError,
  ConfigError,
  ErrorSeverity,
  ErrorCategory,
  RecoveryStrategy,
} from '@buzztrail-ai/presentation';

Example: Type-Safe Configuration

import { createPresentation } from '@buzztrail-ai/presentation';
import type { PresentationConfig, PresentationState } from '@buzztrail-ai/presentation';

const config: PresentationConfig = {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',

  // TypeScript will autocomplete and validate these properties
  viewer: {
    position: 'center',  // Type-checked: 'left' | 'center' | 'right'
    showControls: true,
    aspectRatio: '16:9' // Type-checked: '16:9' | '4:3' | '21:9'
  },

  theme: 'auto', // Type-checked: 'light' | 'dark' | 'auto'

  // TypeScript will autocomplete and validate callbacks
  onStateChange: (state: PresentationState) => {
    console.log('State:', state); // Type: 'idle' | 'connecting' | 'connected' | 'disconnected'
  }
};

const presentation = createPresentation('my-container', config);

Configuration

createPresentation Options

interface PresentationConfig {
  // Required: Your BuzzTrail customer ID
  customerId: string;

  // Required: Deck ID to present
  deckId: string;

  // Required: Supabase project URL
  supabaseUrl: string;

  // Required: Supabase anonymous key
  supabaseKey: string;

  // Optional: Backend API base URL (defaults to production)
  apiUrl?: string;

  // Optional: Viewer configuration
  viewer?: ViewerConfig;

  // Optional: Theme mode
  theme?: ThemeMode; // 'light' | 'dark' | 'auto'

  // Optional: Custom theme configuration
  themeConfig?: PresentationThemeConfig;

  // Optional: Lead capture configuration
  gating?: GatingConfig;

  // Optional: Customer metadata for session tracking
  customerInfo?: {
    name?: string;
    email?: string;
    [key: string]: unknown;
  };

  // Optional: Enable debug logging
  debug?: boolean;

  // Optional: Lifecycle callbacks
  onStart?: () => void;
  onEnd?: () => void;
  onError?: (error: Error) => void;
  onStateChange?: (state: PresentationState) => void;
}

Viewer Configuration

interface ViewerConfig {
  // Viewer position in container
  position?: 'left' | 'center' | 'right'; // default: 'center'

  // Show manual slide controls
  showControls?: boolean; // default: false

  // Controls position
  controlsPosition?: 'top' | 'bottom'; // default: 'bottom'

  // Video aspect ratio
  aspectRatio?: '16:9' | '4:3' | '21:9'; // default: '16:9'

  // Show loading state
  showLoading?: boolean; // default: true

  // Custom loading message
  loadingMessage?: string; // default: 'Loading presentation...'
}

Gating Configuration

interface GatingConfig {
  // Enable lead capture form
  enabled: boolean;

  // Fields to collect
  fields: Array<'name' | 'email' | 'phone' | 'company'>;

  // Form title (optional)
  title?: string;

  // Form description (optional)
  description?: string;
}

Theme Configuration

interface PresentationThemeConfig {
  // Theme mode
  mode: 'light' | 'dark' | 'auto';

  // Custom colors (optional)
  colors?: {
    background?: string;
    text?: string;
    accent?: string;
    border?: string;
  };
}

API Reference

createPresentation(containerOrId, config)

Create a presentation instance in the specified container.

Parameters:

  • containerOrId (string | HTMLElement): DOM element or element ID to inject the presentation into
  • config (PresentationConfig): Configuration options

Returns: Presentation instance

const presentation = createPresentation('my-container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key'
});

endPresentation(sessionId)

End a presentation by session ID.

Parameters:

  • sessionId (string): The session ID to end

Returns: Promise<void>

await endPresentation('session-abc123');

Presentation Instance

The object returned by createPresentation() has the following methods:

presentation.start()

Start the presentation session. Connects to LiveKit room, spawns bots, and begins the interactive presentation.

Returns: Promise<void>

await presentation.start();

presentation.end()

End the presentation session. Disconnects from room, cleans up resources.

Returns: Promise<void>

await presentation.end();

presentation.getState()

Get the current presentation state.

Returns: PresentationState - 'idle' | 'connecting' | 'connected' | 'disconnected'

const state = presentation.getState();
console.log(state); // 'connected'

presentation.destroy()

Destroy the presentation instance and clean up all resources. Call this when removing the presentation from the page.

Returns: void

presentation.destroy();

presentation.sessionId

Read-only property containing the unique session ID.

console.log(presentation.sessionId); // 'session-abc123'

Configuration Scenarios

Scenario 1: Basic Presentation (Minimal Config)

const presentation = createPresentation('container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key'
});

await presentation.start();

Scenario 2: With Manual Controls

const presentation = createPresentation('container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',

  viewer: {
    showControls: true,
    controlsPosition: 'bottom'
  }
});

await presentation.start();

Scenario 3: With Lead Capture

const presentation = createPresentation('container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',

  gating: {
    enabled: true,
    fields: ['name', 'email', 'company'],
    title: 'Get Access to Our Product Demo',
    description: 'Please provide your information to continue'
  }
});

await presentation.start();

Scenario 4: Full Configuration with Callbacks

const presentation = createPresentation('container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',
  apiUrl: 'https://api.buzztrail.ai',

  viewer: {
    position: 'center',
    showControls: true,
    controlsPosition: 'bottom',
    aspectRatio: '16:9',
    showLoading: true,
    loadingMessage: 'Preparing your personalized demo...'
  },

  theme: 'auto',

  gating: {
    enabled: true,
    fields: ['name', 'email']
  },

  customerInfo: {
    name: 'Jane Smith',
    email: '[email protected]',
    company: 'Acme Inc'
  },

  debug: true,

  onStart: () => {
    console.log('Presentation started');
    // Track analytics, show UI elements, etc.
  },

  onEnd: () => {
    console.log('Presentation ended');
    // Hide UI elements, show follow-up actions, etc.
  },

  onError: (error) => {
    console.error('Presentation error:', error);
    // Show user-friendly error message
  },

  onStateChange: (state) => {
    console.log('State changed to:', state);
    // Update UI based on state
    if (state === 'connected') {
      // Show "presentation is live" indicator
    }
  }
});

await presentation.start();

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • Mobile browsers: iOS Safari 14+, Chrome Android

Note: Voice interaction requires browser support for WebRTC and getUserMedia API.

Troubleshooting

"Domain not authorized" Error

Solution: Contact BuzzTrail support to authorize your domain. Domain authorization is managed by BuzzTrail admins for security purposes.

Camera/Microphone Not Working

  • HTTPS Required: Voice interaction only works on secure (HTTPS) websites
  • Wix Users: Use Custom Code (Settings → Advanced), NOT the Embed HTML element
  • Browser Permissions: Users must allow microphone access when prompted
  • Check Container: Ensure the container element exists before calling createPresentation()

Presentation Not Appearing

  • Check Account: Verify your BuzzTrail account is active
  • Check Customer ID: Ensure you're using the correct customer ID from your dashboard
  • Check Deck ID: Verify the deck ID exists and is published
  • Check Supabase Credentials: Ensure your Supabase URL and key are correct
  • Check Container: The HTML element with your container ID must exist on the page
  • Check Console: Open browser DevTools (F12) to see any error messages

Slides Not Advancing

  • Voice Commands: The AI voice agent controls slides based on conversation flow
  • Manual Controls: Enable manual controls with viewer.showControls: true if you want user control
  • Database Connection: Ensure Supabase credentials are correct - slides sync via database
  • Network Issues: Check browser console for network errors

Bot Spawn Failures

If you see "Bot spawn failed" errors:

  1. Check API URL: Verify apiUrl is correct (or omit to use default)
  2. Check Session Creation: Ensure the session was created successfully
  3. Check Logs: Enable debug: true to see detailed bot spawn logs
  4. Retry: Bot spawning includes automatic retry logic, wait a few seconds

Debugging Slide Control Issues

Enable debug mode to see detailed logs:

const presentation = createPresentation('container', {
  customerId: 'acme-corp',
  deckId: 'product-demo',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseKey: 'your-anon-key',
  debug: true // Enable debug logging
});

Debug logs will show:

  • Session creation
  • Bot spawn attempts
  • LiveKit room connection
  • Slide control commands
  • Error details with recovery strategies

Examples

Wix Example (Copy-Paste Ready)

<!-- Add via Wix Settings → Advanced → Custom Code → Body - end -->
<script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>
<script>
  // Replace these values with your credentials
  const CUSTOMER_ID = 'your-customer-id';
  const DECK_ID = 'your-deck-id';
  const SUPABASE_URL = 'https://your-project.supabase.co';
  const SUPABASE_KEY = 'your-anon-key';
  const CONTAINER_ID = 'comp-mfy88b7h'; // Your Wix element ID

  const presentation = createPresentation(CONTAINER_ID, {
    customerId: CUSTOMER_ID,
    deckId: DECK_ID,
    supabaseUrl: SUPABASE_URL,
    supabaseKey: SUPABASE_KEY,

    viewer: {
      showControls: true,
      aspectRatio: '16:9'
    },

    onStart: () => console.log('Presentation started!'),
    onEnd: () => console.log('Presentation ended!'),
    onError: (error) => console.error('Error:', error.message)
  });

  presentation.start().catch(error => {
    console.error('Failed to start presentation:', error);
  });
</script>

Generic HTML Example (Copy-Paste Ready)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>BuzzTrail Presentation Demo</title>
  <style>
    body {
      margin: 0;
      padding: 20px;
      font-family: Arial, sans-serif;
      background: #f5f5f5;
    }

    h1 {
      text-align: center;
      color: #333;
    }

    #presentation-container {
      max-width: 1200px;
      margin: 0 auto;
      background: white;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
      min-height: 600px;
      padding: 20px;
    }

    .status {
      text-align: center;
      padding: 10px;
      margin: 20px auto;
      max-width: 400px;
      border-radius: 4px;
      background: #e3f2fd;
      color: #1976d2;
    }
  </style>
</head>
<body>
  <h1>Product Demo Presentation</h1>

  <div id="status" class="status">
    Initializing presentation...
  </div>

  <div id="presentation-container"></div>

  <!-- Load BuzzTrail Presentation SDK -->
  <script src="https://cdn.jsdelivr.net/npm/@buzztrail-ai/presentation@1/buzztrail-presentation.min.js"></script>

  <script>
    // Configuration
    const config = {
      customerId: 'your-customer-id',
      deckId: 'your-deck-id',
      supabaseUrl: 'https://your-project.supabase.co',
      supabaseKey: 'your-anon-key',

      viewer: {
        position: 'center',
        showControls: true,
        controlsPosition: 'bottom',
        aspectRatio: '16:9'
      },

      theme: 'auto',

      debug: true,

      onStart: () => {
        updateStatus('Presentation is live!', 'success');
      },

      onEnd: () => {
        updateStatus('Presentation ended. Thank you!', 'info');
      },

      onError: (error) => {
        updateStatus('Error: ' + error.message, 'error');
        console.error('Presentation error:', error);
      },

      onStateChange: (state) => {
        console.log('State:', state);
        if (state === 'connecting') {
          updateStatus('Connecting...', 'info');
        } else if (state === 'connected') {
          updateStatus('Connected!', 'success');
        } else if (state === 'disconnected') {
          updateStatus('Disconnected', 'info');
        }
      }
    };

    // Helper function to update status
    function updateStatus(message, type = 'info') {
      const statusEl = document.getElementById('status');
      statusEl.textContent = message;
      statusEl.style.background = {
        success: '#e8f5e9',
        error: '#ffebee',
        info: '#e3f2fd'
      }[type];
      statusEl.style.color = {
        success: '#2e7d32',
        error: '#c62828',
        info: '#1976d2'
      }[type];
    }

    // Create and start presentation
    const presentation = createPresentation('presentation-container', config);

    presentation.start()
      .then(() => {
        console.log('Presentation started successfully');
      })
      .catch(error => {
        updateStatus('Failed to start: ' + error.message, 'error');
        console.error('Failed to start presentation:', error);
      });

    // Cleanup on page unload
    window.addEventListener('beforeunload', () => {
      presentation.destroy();
    });
  </script>
</body>
</html>

Changelog

See CHANGELOG.md for version history.

License

Proprietary - BuzzTrail AI


Built with TypeScriptAI-Powered PresentationsMade for modern web platforms