Pinecall

@pinecall/web

Drop-in React voice widget with animated orb UI, live transcript, themes, and multi-language support.

npm install @pinecall/web react react-dom

Built on top of @pinecall/web/core. React ≥18 is a peer dependency.

Quick start#

import { VoiceWidget } from "@pinecall/web";

export default function App() {
  return <VoiceWidget agent="mara" name="Mara" />;
}

That's it. The widget renders a floating orb in the bottom-right corner. Click to start a voice call, click again to end it. The orb animates through phases (idle → connecting → listening → speaking → thinking) and shows a live transcript bubble above.

What you get out of the box#

  • Animated orb with breathing rings, pulse states, and per-phase colors
  • Live transcript rendered as chat bubbles next to the orb
  • 5 theme presets (dark, midnight, aurora, sunset, light) — plus full CSS variable overrides
  • Multi-language pill selector with hot-swap mid-call
  • Token security via tokenProvider — API keys never leave your server
  • Idle warning state when the user goes silent too long
  • Interactive Tools API for rendering UI in response to LLM tool calls
  • useVoiceSession() hook for building completely custom UIs

Standalone components#

The package also exports standalone components for building custom multi-channel experiences:

ExportPurpose
ContactHubMulti-channel contact menu (voice, chat, WhatsApp, Call Me)
ChatViewEmbedded LLM text chat with streaming markdown
useVoiceSession()Headless hook — build your own UI from scratch
useAgentInfo()Fetch agent channel info for auto-discovery

These are not wired into <VoiceWidget> — you compose them yourself in your app's UI.

When to use what#

You want to...Use
Drop a voice button on your site<VoiceWidget />
Build a fully custom UI in ReactuseVoiceSession() hook
Build a fully custom UI in Vue/Svelte/vanilla@pinecall/web/core directly
Render interactive UI from agent tool calls<VoiceWidget> + tools prop or useVoice() + trackedTools
Add multi-channel contact menuImport ContactHub and compose it in your layout

What's next#