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

@bubblio/widget

v0.4.0

Published

Embeddable real-time AI customer-service character widget — drop into any React app in 5 lines of code.

Readme

@bubblio/widget

Embeddable real-time AI character widget for React apps. Floating bubble that opens into a live video character — connects directly to Runway, talks to your backend via @bubblio/server.

npm install @bubblio/widget @runwayml/avatars-react react react-dom

Peer dependencies: react >= 18, react-dom >= 18, @runwayml/avatars-react >= 0.14.


Quickstart

import { BubblioWidget } from '@bubblio/widget'

export default function App() {
  return (
    <BubblioWidget
      config={{
        name: 'Aria',
        character: '/aria.png',
        serverUrl: '/api/bubblio/session',
      }}
    />
  )
}

serverUrl is your own backend route that returns { sessionId, sessionKey }. Pair it with @bubblio/server:

// app/api/bubblio/session/route.ts
import { createBubblioSession } from '@bubblio/server'

export async function POST() {
  const session = await createBubblioSession({
    bubblioApiKey: process.env.BUBBLIO_API_KEY!,
    characterId: process.env.BUBBLIO_CHARACTER_ID!,
  })
  return Response.json(session)
}

That's it. The widget renders a floating bubble; clicking it opens the live character panel and starts a WebRTC connection. Closing the panel ends the session.


No React? One script tag.

Plain HTML, Webflow, Wix — drop this anywhere (Webflow/Wix users: paste it into a custom-code block):

<script defer
  src="https://cdn.jsdelivr.net/npm/@bubblio/[email protected]/dist/embed.global.js"
  data-server-url="https://yoursite.com/api/bubblio/session"></script>

The bubble auto-mounts on DOM ready. Configure it with data-* attributes:

| Attribute | Maps to | | --- | --- | | data-server-url | serverUrl (required for auto-mount) | | data-name | name | | data-character | character | | data-primary-color | theme.primaryColor | | data-accent-color | theme.accentColor | | data-dot-color | theme.dotColor |

Prefer to configure from JavaScript? Set window.bubblioConfig before the embed script tag (inline scripts run before defer scripts, so this ordering is always safe — including in Webflow/Wix custom-code blocks) and omit data-server-url:

<script>
  window.bubblioConfig = { serverUrl: 'https://yoursite.com/api/bubblio/session' }
</script>
<script defer src="https://cdn.jsdelivr.net/npm/@bubblio/[email protected]/dist/embed.global.js"></script>

For full runtime control there's also a global API — note it only exists once the embed script has loaded (call it from the script tag's load event or a later user interaction, never from an inline script above it):

window.Bubblio.init({ serverUrl: 'https://yoursite.com/api/bubblio/session' })
// later:
Bubblio.destroy()

The embed is a single self-contained file (~290 KB gzipped) that loads deferred. React is not required on the page — and if the page already has React, nothing clashes: everything is bundled and scoped inside the script.


Persistence across navigation

Mount <BubblioWidget /> once in your root layout so the session survives page transitions. Mounting inside a page component will tear down and restart the session every time the user navigates.

// app/layout.tsx (Next.js App Router)
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <BubblioWidget config={{ name: 'Aria', character: '/aria.png', serverUrl: '/api/bubblio/session' }} />
      </body>
    </html>
  )
}

Theming

<BubblioWidget
  config={{
    name: 'Aria',
    character: '/aria.png',
    serverUrl: '/api/bubblio/session',
    theme: {
      primaryColor: '#0066ff',
      dotColor: '#0066ff',
    },
  }}
/>

| Field | What it styles | | --- | --- | | primaryColor | Retry button, default bubble color | | dotColor | Floating trigger bubble color (defaults to primaryColor) | | accentColor | Reserved for future use |


Client events

The character can fire two built-in client events to drive your UI:

set_animation_state — Switch a visual state in the widget. The character should call this just before any tool call, then idle once the result is back. States: idle, searching, creating, found, analyzing, linking, closing.

show_link_card — Render a clickable link card inside the panel. Useful for directing the user to a specific page.

{ name: 'show_link_card', args: { title: 'Your dashboard', url: '/dashboard' } }

Both events are registered automatically by the platform — you just need to mention them in the character's personality prompt so it knows when to use them.


API

<BubblioWidget config={config} />

interface BubblioConfig {
  name: string         // shown in panel header
  character: string    // portrait image URL or path
  serverUrl: string    // your backend endpoint that returns { sessionId, sessionKey }
  theme?: {
    primaryColor?: string
    accentColor?: string
    dotColor?: string
  }
}

type AnimationState =
  | 'idle' | 'searching' | 'creating' | 'found'
  | 'analyzing' | 'linking' | 'closing'

interface LinkCard {
  title: string
  url: string
  description: string
}

License

MIT. See LICENSE.