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

@avatar-engine/react

v1.3.0

Published

React components and hooks for Avatar Engine — chat UI, avatar bust, provider selector

Readme

@avatar-engine/react

npm TypeScript License

React components and hooks for Avatar Engine — a complete AI chat UI with provider switching, session management, avatar animations, and theming.

This package re-exports everything from @avatar-engine/core, so you only need to install this one.

Installation

npm install @avatar-engine/react

Peer dependencies: React 18+ or 19+, ReactDOM

Quick Start

Minimal setup (3 files)

1. Configure Tailwind (tailwind.config.js):

import avatarPreset from '@avatar-engine/react/tailwind-preset'

export default {
  presets: [avatarPreset],
  content: [
    './src/**/*.{tsx,ts}',
    './node_modules/@avatar-engine/react/dist/**/*.js',
  ],
}

2. Import styles (in your entry point):

import '@avatar-engine/react/styles.css'

3. Use the widget (App.tsx):

import { useAvatarChat, AvatarWidget } from '@avatar-engine/react'

function App() {
  const chat = useAvatarChat('ws://localhost:8420/api/avatar/ws')

  return (
    <div>
      <h1>My App</h1>
      <AvatarWidget {...chat} />
    </div>
  )
}

That's it — you get a floating action button (FAB) that expands into a compact chat drawer or fullscreen chat panel.

With initial configuration

import { useAvatarChat, AvatarWidget, PermissionDialog } from '@avatar-engine/react'

function App() {
  const chat = useAvatarChat('ws://localhost:8420/api/avatar/ws', {
    apiBase: '/api/avatar',
    initialProvider: 'gemini',
    initialModel: 'gemini-2.5-flash',
    initialOptions: { thinking_level: 'low' },
    onResponse(message) {
      console.log('AI responded:', message.content.slice(0, 100))
    },
  })

  return (
    <>
      <AvatarWidget {...chat} />
      <PermissionDialog
        request={chat.permissionRequest}
        onRespond={chat.sendPermissionResponse}
      />
    </>
  )
}

Headless mode (custom UI)

Use useAvatarChat without any pre-built components:

import { useAvatarChat } from '@avatar-engine/react'

function CustomChat() {
  const { messages, sendMessage, isStreaming, connected } = useAvatarChat(
    'ws://localhost:8420/api/avatar/ws'
  )

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id} className={msg.role}>
          {msg.content}
          {msg.isStreaming && <span className="cursor" />}
        </div>
      ))}
      <form onSubmit={(e) => {
        e.preventDefault()
        const input = e.currentTarget.elements.namedItem('msg') as HTMLInputElement
        sendMessage(input.value)
        input.value = ''
      }}>
        <input name="msg" disabled={!connected || isStreaming} />
      </form>
    </div>
  )
}

Hooks

useAvatarChat(wsUrl, options?)

Main orchestration hook — manages WebSocket connection, message state, file uploads, and provider switching.

const chat = useAvatarChat('ws://localhost:8420/api/avatar/ws', {
  apiBase: '/api/avatar',           // REST API base (default: '/api/avatar')
  initialProvider: 'gemini',        // Auto-switch provider on connect
  initialModel: 'gemini-2.5-flash', // Auto-switch model on connect
  initialOptions: { ... },          // Provider options to apply
  onResponse: (msg) => { ... },     // Called when response completes
})

Returns (UseAvatarChatReturn):

| Property | Type | Description | |----------|------|-------------| | messages | ChatMessage[] | All messages (user + assistant) | | sendMessage | (text, attachments?) => void | Send a user message | | stopResponse | () => void | Cancel current AI response | | clearHistory | () => void | Clear all messages | | switchProvider | (provider, model?, options?) => void | Switch AI provider/model | | resumeSession | (sessionId) => void | Resume a previous session | | newSession | () => void | Start a new session | | isStreaming | boolean | Whether AI is currently responding | | connected | boolean | WebSocket connected | | provider | string | Current provider ID | | model | string \| null | Current model name | | sessionId | string \| null | Current session ID | | sessionTitle | string \| null | Current session title | | thinking | { active, phase, subject } | Thinking state | | cost | { totalCostUsd, totalInputTokens, totalOutputTokens } | Accumulated cost | | capabilities | ProviderCapabilities \| null | Provider feature flags | | safetyMode | SafetyMode | Current safety mode | | permissionRequest | PermissionRequest \| null | Pending permission request | | sendPermissionResponse | (requestId, optionId, cancelled) => void | Respond to permission | | pendingFiles | UploadedFile[] | Files queued for upload | | uploading | boolean | File upload in progress | | uploadFile | (file: File) => Promise | Upload a file | | removeFile | (fileId) => void | Remove a pending file | | error | string \| null | Error message | | diagnostic | string \| null | Diagnostic message |

useAvatarWebSocket(wsUrl)

Low-level WebSocket hook — manages connection, state machine, and raw message dispatch. Used internally by useAvatarChat.

useWidgetMode(options?)

Widget display mode state machine (FAB → compact → fullscreen).

useAvatarBust(engineState, isStreaming)

Avatar bust animation state derived from engine activity.

useFileUpload(apiBase)

File upload queue with progress tracking.

useDynamicModels(apiBase)

Fetch dynamic model lists from the backend with three-tier fallback:

  1. Static provider config (instant)
  2. localStorage cache (24h TTL)
  3. Backend scraping (live documentation fetch)

Returns provider configurations with up-to-date model lists.

useModelDiscoveryErrors()

Listen for model discovery errors emitted during dynamic model fetching. Returns array of errors for UI display (toasts, banners).

useAvailableProviders(apiBase)

Fetch available providers from the REST API.

Components

Layout

| Component | Description | |-----------|-------------| | AvatarWidget | Master layout — FAB button, compact drawer, and fullscreen panel | | ChatPanel | Fullscreen chat UI with messages, input, and status bar | | CompactChat | Compact mode chat drawer | | StatusBar | Header bar with provider badge, model name, session info |

Chat

| Component | Description | |-----------|-------------| | MessageBubble | Single message (user or assistant) with markdown rendering | | MarkdownContent | Markdown renderer with syntax highlighting | | ThinkingIndicator | AI thinking phase display | | ToolActivity | Tool execution status (started/completed/failed) | | BreathingOrb | Animated orb for empty state | | CostTracker | API cost display |

Provider & Session

| Component | Description | |-----------|-------------| | ProviderModelSelector | Provider/model dropdown with options | | SessionPanel | Session list, resume, new session | | OptionControl | Dynamic option inputs (select, slider, number) |

Safety & Permissions

| Component | Description | |-----------|-------------| | PermissionDialog | ACP tool permission request modal | | SafetyModeSelector | Safe / Ask / Unrestricted toggle | | SafetyModal | Confirmation dialog for unrestricted mode |

Avatar

| Component | Description | |-----------|-------------| | AvatarBust | Animated avatar bust with state-driven animations | | AvatarFab | Floating action button | | AvatarPicker | Avatar selection | | AvatarLogo | Avatar Engine logo |

Theming

Tailwind Preset

The preset provides the Avatar Engine design system — dark glassmorphism theme with accent colors:

// tailwind.config.js
import avatarPreset from '@avatar-engine/react/tailwind-preset'

export default {
  presets: [avatarPreset],
  content: [
    './src/**/*.{tsx,ts}',
    './node_modules/@avatar-engine/react/dist/**/*.js',
  ],
  theme: {
    extend: {
      colors: {
        // Override accent colors for your brand
        synapse: '#ff6b6b',  // Primary accent (default: indigo)
        pulse: '#ff8e53',    // Secondary accent (default: violet)
        neural: '#ffd93d',   // Tertiary accent (default: cyan)
      },
    },
  },
}

CSS Custom Properties

For runtime theming without Tailwind rebuilds:

:root {
  --avatar-accent: #6366f1;
  --avatar-accent-secondary: #8b5cf6;
  --avatar-bg-primary: #0a0a0f;
  --avatar-bg-panel: #13131b;
  --avatar-text-primary: #f8fafc;
  --avatar-text-secondary: #94a3b8;
  --avatar-border-radius: 0.75rem;
}

Custom Providers

Override the built-in provider list with your own:

import { AvatarWidget, useAvatarChat, type ProviderConfig } from '@avatar-engine/react'

const myProviders: ProviderConfig[] = [
  {
    id: 'gemini',
    label: 'Gemini',
    defaultModel: 'gemini-2.5-flash',
    models: ['gemini-2.5-flash', 'gemini-2.5-pro'],
    gradient: 'from-blue-500/20 to-cyan-500/20 border-blue-400/40',
    dotColor: 'bg-blue-400',
  },
]

function App() {
  const chat = useAvatarChat('ws://localhost:8420/api/avatar/ws')
  return <AvatarWidget {...chat} customProviders={myProviders} />
}

Vite Proxy

When developing with Vite, proxy the Avatar Engine backend:

// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/api/avatar': {
        target: 'http://localhost:8420',
        ws: true,
      },
    },
  },
})

Backend

This package is the React frontend for Avatar Engine — a Python backend that wraps Gemini CLI, Claude Code, and Codex CLI into a unified WebSocket API. See the main README for backend setup.

License

Apache-2.0