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

orb-ui

v0.6.1

Published

React voice agent UI components with audio-reactive adapters for Vapi, ElevenLabs, LiveKit, Pipecat, OpenAI Realtime, Gemini Live, and custom voice AI apps.

Readme

orb-ui

React voice agent UI components for Vapi, ElevenLabs, LiveKit, Pipecat, OpenAI Realtime, Gemini Live, and custom realtime voice AI apps. orb-ui gives you animated voice orbs, audio-reactive themes, accessible clickable controls, and provider adapters for building polished voice agent interfaces in React.

import Vapi from '@vapi-ai/web'
import { Orb } from 'orb-ui'
import { createVapiAdapter } from 'orb-ui/adapters'

const vapi = new Vapi('your-public-key')
const adapter = createVapiAdapter(vapi, { assistantId: 'your-assistant-id' })

export function VoiceOrb() {
  return <Orb adapter={adapter} theme="circle" aria-label="Start voice assistant" />
}

Install

Install the component package:

npm install orb-ui

Provider adapters are lightweight wrappers around provider SDKs. Install the SDK for the provider you use:

# Vapi
npm install orb-ui @vapi-ai/web

# ElevenLabs Conversational AI
npm install orb-ui @elevenlabs/client

# LiveKit Agents
npm install orb-ui livekit-client

# Pipecat (choose the transport used by your agent)
npm install orb-ui @pipecat-ai/client-js @pipecat-ai/small-webrtc-transport

# OpenAI Realtime uses browser WebRTC and has no additional client SDK
npm install orb-ui

# Gemini Live
npm install orb-ui @google/genai

Note: Orb uses React hooks internally — in Next.js App Router, use it in a 'use client' component.

How provider adapters are created

Every provider ends at the same React API:

<Orb adapter={adapter} theme="circle" aria-label="Start voice assistant" />

The only difference is how the adapter obtains a provider session:

| Provider | Required browser setup | | --------------- | ------------------------------------------------------------------------ | | Vapi | Pass a configured Vapi client plus assistantId | | ElevenLabs | Pass Conversation plus an agentId, signed URL, or conversation token | | LiveKit | Provide a token endpoint and optional agent name | | Pipecat | Pass a configured PipecatClient plus its connect callback | | OpenAI Realtime | Return a fresh short-lived client secret from getClientSecret | | Gemini Live | Open the official Google Live session in connect |

The adapter owns provider event mapping and emits one consistent OrbSignal. OpenAI and Gemini standard API keys, and LiveKit participant-token signing, stay on your server. See the adapter overview for the responsibility boundary and advanced setup shapes.

Quick Start

Use orb-ui as a React voice AI component when you need a first-party provider voice UI or a custom animated voice orb for another realtime voice agent stack.

With Vapi

import Vapi from '@vapi-ai/web'
import { Orb } from 'orb-ui'
import { createVapiAdapter } from 'orb-ui/adapters'

const vapi = new Vapi('your-public-key')
const adapter = createVapiAdapter(vapi, { assistantId: 'your-assistant-id' })

function App() {
  return <Orb adapter={adapter} theme="circle" aria-label="Start Vapi assistant" />
}

With ElevenLabs

import { Conversation } from '@elevenlabs/client'
import { Orb } from 'orb-ui'
import { createElevenLabsAdapter } from 'orb-ui/adapters'

const adapter = createElevenLabsAdapter(Conversation, { agentId: 'your-agent-id' })

function App() {
  return <Orb adapter={adapter} theme="circle" aria-label="Start ElevenLabs assistant" />
}

With LiveKit

import { Orb } from 'orb-ui'
import { createLiveKitAdapter } from 'orb-ui/adapters/livekit'

const adapter = createLiveKitAdapter({
  tokenEndpoint: '/api/livekit-token',
  agentName: 'your-agent-name',
})

function App() {
  return <Orb adapter={adapter} theme="circle" aria-label="Start LiveKit assistant" />
}

The LiveKit entrypoint creates the room and token source, assigns a fresh room name, and meters both sides of the conversation with speech-oriented analyser and smoothing defaults. Existing-room and custom-runtime modes remain available from the advanced orb-ui/adapters entrypoint.

With Pipecat

import { PipecatClient } from '@pipecat-ai/client-js'
import { SmallWebRTCTransport } from '@pipecat-ai/small-webrtc-transport'
import { Orb } from 'orb-ui'
import { createPipecatAdapter } from 'orb-ui/adapters'

const client = new PipecatClient({ transport: new SmallWebRTCTransport(), enableMic: true })
const adapter = createPipecatAdapter(client, {
  connect: () => client.connect({ webrtcUrl: 'https://agent.example.com/api/offer' }),
})

function App() {
  return <Orb adapter={adapter} theme="circle" aria-label="Start Pipecat assistant" />
}

The Pipecat adapter consumes the standard RTVI event surface and meters the client media tracks as a browser fallback, so it works with Pipecat Cloud, Daily, SmallWebRTC, and transports that emit sparse audio-level events. See the Pipecat guide.

With OpenAI Realtime

import { Orb } from 'orb-ui'
import { createOpenAIRealtimeAdapter } from 'orb-ui/adapters'

const adapter = createOpenAIRealtimeAdapter({
  getClientSecret: async () => {
    const response = await fetch('/api/openai-realtime-token', { method: 'POST' })
    return (await response.json()).value
  },
})

Create client secrets with a standard OpenAI API key on your server. See the OpenAI Realtime guide.

With Gemini Live

import { GoogleGenAI } from '@google/genai'
import { Orb } from 'orb-ui'
import { createGeminiLiveAdapter } from 'orb-ui/adapters'

const adapter = createGeminiLiveAdapter({
  connect: async (callbacks) => {
    const token = await fetch('/api/gemini-live-token', { method: 'POST' }).then((res) =>
      res.json(),
    )
    const client = new GoogleGenAI({
      apiKey: token.value,
      httpOptions: { apiVersion: 'v1alpha' },
    })
    return client.live.connect({ model: token.model, config: token.config, callbacks })
  },
})

Mint one-use Gemini Live tokens on your server. See the Gemini Live guide for the matching server config that disables automatic activity detection. The adapter handles client-side turn detection by default.

The examples above show the intended happy paths. Transport overrides, custom browser runtimes, existing-session modes, and audio calibration hooks are optional and documented in the individual adapter guides.

Controlled mode (custom integration)

import { Orb } from 'orb-ui'
import { useState } from 'react'

function App() {
  const [state, setState] = useState('idle')
  const [volume, setVolume] = useState(0)

  return <Orb state={state} volume={volume} theme="circle" />
}

Use signal when your integration has separate input and output levels:

import { Orb } from 'orb-ui'

function App() {
  return <Orb signal={{ state: 'speaking', outputVolume: 0.7 }} theme="circle" />
}

External session controls

Keep the orb as a passive visual when start and stop controls belong elsewhere in your layout. Provider adapters already expose the matching lifecycle methods.

function VoiceExperience({ adapter }) {
  return (
    <>
      <Orb adapter={adapter} theme="cloud" interactive={false} />
      <button onClick={() => void adapter.start?.()}>Start conversation</button>
      <button onClick={() => void adapter.stop?.()}>End conversation</button>
    </>
  )
}

Themes

| Theme | Description | | -------- | ----------------------------------------------------------------------------- | | cloud | Atmospheric sphere with inverse listening scale and faster speaking motion. | | debug | State + volume display with start/stop. Use to verify your integration works. | | circle | Pulsing circle that reacts to volume. | | bars | Five bars that animate with voice. |

When an adapter or onStart/onStop handler is provided, visual themes render as keyboard-accessible <button type="button"> controls. Pass interactive={false} to keep the theme passive and call adapter.start() or adapter.stop() from external controls instead.

Props

| Prop | Type | Default | Description | | ------------- | ------------------------------------------ | --------- | ------------------------------------------------------- | | theme | 'debug' \| 'circle' \| 'bars' \| 'cloud' | 'debug' | Visual theme | | signal | OrbSignal | — | Rich controlled signal with state/input/output volume | | state | OrbState | 'idle' | Conversation state (controlled mode) | | volume | number | 0 | Audio volume, 0–1. Overrides signal/adapter volume. | | adapter | OrbAdapter | — | Provider adapter (manages signal updates automatically) | | size | number | 200 | Size in pixels | | className | string | — | Optional class name for the rendered theme | | style | React.CSSProperties | — | Optional inline styles for the rendered theme | | disabled | boolean | false | Disables clickable themes and debug start/stop controls | | interactive | boolean | true | Allows the orb itself to start and stop a session | | aria-label | string | generated | Accessible label for clickable visual themes | | onStart | () => void | — | Custom start handler (overrides adapter.start()) | | onStop | () => void | — | Custom stop handler (overrides adapter.stop()) |

States

idle · connecting · listening · thinking · speaking · error

Supported Providers

| Provider | Adapter | | ------------------------------------------------------------------------- | --------------------------------------------------------------------- | | Vapi | createVapiAdapter from orb-ui/adapters | | ElevenLabs | createElevenLabsAdapter from orb-ui/adapters | | LiveKit | createLiveKitAdapter from orb-ui/adapters | | Pipecat | createPipecatAdapter from orb-ui/adapters | | OpenAI Realtime | createOpenAIRealtimeAdapter from orb-ui/adapters | | Gemini Live | createGeminiLiveAdapter from orb-ui/adapters | | Custom | Use controlled mode — pass signal, or state and volume directly |

Development

git clone https://github.com/alexanderqchen/orb-ui.git
cd orb-ui
pnpm install

# Build the library
pnpm build

# Run demo locally
pnpm dev:demo

Useful maintenance commands:

pnpm check        # format check, lint, typechecks, tests, library build, demo build
pnpm format       # format repo files
pnpm changeset    # add release notes for a user-facing package change

Releases are managed with Changesets. Merging a Changesets version PR publishes orb-ui to npm from GitHub Actions using npm trusted publishing.

License

MIT © Alexander Chen