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

@liyalabs/liya-3d-avatar-widget-vanilla-js

v0.1.1

Published

3D Talking Avatar Widget - AI Assistant with real-time lip-sync (Vanilla JS / PHP / any non-framework environment)

Readme

@liyalabs/liya-3d-avatar-widget-vanilla-js

3D Talking Avatar Widget — AI Assistant with real-time lip-sync animation for Vanilla JS, PHP and any non-framework environment.

npm version License: MIT

Live Demo →  |  Website →  |  API Docs →

Origin

This package is a framework-agnostic port of @liyalabs/liya-3d-avatar-widget-vuejs.

| | Vue JS (upstream) | Vanilla JS (this package) | |---|---|---| | Runtime | Vue 3 + Vite | Plain JS / UMD / ESM | | Usage | <LiyaAvatarWidget /> component | new LiyaAvatarWidget(el, opts) | | PHP | ❌ | ✅ | | CDN ready | ❌ | ✅ | | No build step | ❌ | ✅ | | Three.js | bundled | bundled |

Screenshots

Widget & Avatar Modal

| Widget (Chat Panel) | Avatar Modal (Lip-sync) | |---------------------|------------------------| | Widget Desktop | Avatar Modal |

Mobile

| Mobile Widget | Mobile Avatar | |---------------|---------------| | Widget Mobile | Avatar Mobile |

Avatar Lip-sync in Action

| Idle | Speaking | |------|----------| | Avatar Idle | Avatar Speaking |

Features

  • 🎭 3D Avatar — Three.js powered 3D avatar with customizable models (GLB/GLTF)
  • 👄 Lip-Sync — Real-time lip synchronization using viseme data (AudioContext clock)
  • 🎤 Voice Input — Web Speech API push-to-talk & continuous mode
  • 🔊 Voice Output — Text-to-speech with avatar animation
  • 💬 Full Chat — Message history, suggestion chips, typing indicator
  • 📎 File Upload — Attach files to conversations
  • 🖼️ Media Display — Inline image and video rendering in chat messages
  • 🖥️ Kiosk / Modal-Kiosk — Full-screen presentation layouts
  • 📱 iOS safe areaenv(safe-area-inset-*) support across all breakpoints
  • 🌗 Dark / Light themes — CSS variable driven
  • 📐 Responsive — Mobile → 4K/UHD breakpoints
  • 🌐 i18n — Turkish, English and Chinese support

Installation

npm install @liyalabs/liya-3d-avatar-widget-vanilla-js
# or
yarn add @liyalabs/liya-3d-avatar-widget-vanilla-js
# or
pnpm add @liyalabs/liya-3d-avatar-widget-vanilla-js

Or via CDN (no build step):

<link rel="stylesheet" href="https://unpkg.com/@liyalabs/liya-3d-avatar-widget-vanilla-js/dist/liya-3d-avatar-widget-vanilla-js.css" />
<script src="https://unpkg.com/@liyalabs/liya-3d-avatar-widget-vanilla-js/dist/liya-3d-avatar-widget-vanilla-js.iife.js"></script>

Quick Start

1. HTML + CDN (simplest)

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet"
    href="https://unpkg.com/@liyalabs/liya-3d-avatar-widget-vanilla-js/dist/liya-3d-avatar-widget-vanilla-js.css" />
</head>
<body>
  <div id="liya-widget"></div>

  <script src="https://unpkg.com/@liyalabs/liya-3d-avatar-widget-vanilla-js/dist/liya-3d-avatar-widget-vanilla-js.iife.js"></script>
  <script>
    const widget = new LiyaAvatarWidget(document.getElementById('liya-widget'), {
      apiKey: 'your-api-key',
      baseUrl: 'https://app-1-ai.liyalabs.com', // Your assigned backend URL (see GAR section)
      assistantId: 'your-assistant-id',
      assistantName: 'AI Assistant',
      mode: 'widget',   // 'widget' | 'kiosk' | 'modal_kiosk'
      locale: 'tr',     // 'tr' | 'en' | 'zh'
    });
  </script>
</body>
</html>

2. ES Module (bundler / Vite / Webpack)

import LiyaAvatarWidget from '@liyalabs/liya-3d-avatar-widget-vanilla-js'
import '@liyalabs/liya-3d-avatar-widget-vanilla-js/style.css'

const widget = new LiyaAvatarWidget(document.getElementById('liya-widget'), {
  apiKey: 'your-api-key',
  baseUrl: 'https://app-1-ai.liyalabs.com',
  assistantId: 'your-assistant-id',
  assistantName: 'AI Assistant',
  mode: 'widget',
  locale: 'tr',
})

3. PHP / Laravel Blade

<!-- resources/views/layouts/app.blade.php -->
<link rel="stylesheet"
  href="{{ asset('vendor/liya/liya-3d-avatar-widget-vanilla-js.css') }}">

<div id="liya-widget"></div>

<script src="{{ asset('vendor/liya/liya-3d-avatar-widget-vanilla-js.iife.js') }}"></script>
<script>
  const widget = new LiyaAvatarWidget(document.getElementById('liya-widget'), {
    apiKey: '{{ config("liya.api_key") }}',
    baseUrl: '{{ config("liya.base_url") }}',
    assistantId: '{{ config("liya.assistant_id") }}',
    mode: 'widget',
    locale: 'tr',
  });
</script>

Options

All options are passed as the second argument to the constructor.

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | required | LiyaLabs API key | | baseUrl | string | required | Your backend URL (see GAR section) | | assistantId | string | '' | Target assistant ID | | assistantName | string | '' | Display name for the AI assistant | | mode | string | 'widget' | 'widget' | 'kiosk' | 'modal_kiosk' | | locale | string | browser default | 'tr' | 'en' | 'zh' | | theme | string | 'dark' | 'dark' | 'light' | | position | string | 'bottom-right' | 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | | avatarModelUrl | string | '' | URL to GLB/GLTF avatar model (auto-fetched from backend if omitted) | | welcomeMessage | string | '' | Welcome message shown on load | | welcomeSuggestions | string[] | [] | Quick reply suggestion chips | | placeholder | string | '' | Chat input placeholder text | | showBranding | boolean | true | Show Liya branding footer | | showVoice | boolean | true | Show voice input button | | voiceEnabled | boolean | true | Enable voice (false = disabled mic for STANDARD accounts) | | showFileUpload | boolean | true | Show file upload button | | showAvatarButton | boolean | true | Show "Talk with Avatar" button | | autoSpeak | boolean | true | Auto-speak assistant responses | | animateButton | boolean | true | Attention animation on the toggle button | | viewOnPageStart | boolean | false | Auto-open widget on page load | | closeButtonEnabled | boolean | true | Show close button | | offsetX | number | 20 | Horizontal offset in pixels | | offsetY | number | 20 | Vertical offset in pixels | | lipSyncIntensity | number | 0.5 | Mouth opening intensity (0–1) |

Events

Listen to widget lifecycle events via the on method:

const widget = new LiyaAvatarWidget(el, opts)

widget.on('opened',          ()       => console.log('Chat panel opened'))
widget.on('closed',          ()       => console.log('Chat panel closed'))
widget.on('avatarOpened',    ()       => console.log('Avatar modal opened'))
widget.on('avatarClosed',    ()       => console.log('Avatar modal closed'))
widget.on('messageSent',     (text)   => console.log('User sent:', text))
widget.on('messageReceived', (text)   => console.log('Assistant replied:', text))
widget.on('speaking-changed',(active) => console.log('Speaking:', active))

| Event | Payload | Description | |-------|---------|-------------| | opened | — | Chat panel opened | | closed | — | Chat panel closed | | avatarOpened | — | Avatar modal opened | | avatarClosed | — | Avatar modal closed | | messageSent | string | User sent a message | | messageReceived | string | Assistant responded | | speaking-changed | boolean | Avatar speaking state changed |

API Methods

// Programmatically open / close
widget.open()
widget.close()

// Send a message from code
widget.sendMessage('Merhaba!')

// Destroy and clean up
widget.destroy()

Avatar Models

The widget supports GLB/GLTF models with ARKit-compatible blend shapes for lip-sync:

  • Ready Player Me avatars (recommended — full ARKit blend shape support)
  • Custom models with viseme morph targets

Supported Viseme Morph Targets

viseme_PP, viseme_FF, viseme_TH, viseme_DD, viseme_kk,
viseme_CH, viseme_SS, viseme_nn, viseme_RR, viseme_aa,
viseme_E, viseme_I, viseme_O, viseme_U

Media Display

When the AI assistant returns images or videos (e.g. from image generation), the widget automatically renders them as inline thumbnails in the chat bubble.

Chat messages include a media field:

interface MessageMediaItem {
  type: 'image' | 'video'
  url: string
  alt?: string
  source?: string
}

Backend Requirements

This widget requires the Liya AI backend. The complete OpenAPI specification (LiyaAi-Api-External-V0, v0.1.0) is available on the developer page:

Developer Docs & API Reference →

Download the spec directly (Endpoints tab → OpenAPI Specification):

| Language | View / Download | |----------|----------------| | 🇬🇧 English | LiyaAi-Api-External-V0-en.yaml | | 🇹🇷 Türkçe | LiyaAi-Api-External-V0-tr.yaml |

The spec follows Semantic Versioning. While on 0.x, breaking changes may occur without prior notice — subscribe to liyalabs.com/changelog.

Core Endpoints Used

| Method | Endpoint | Description | |--------|----------|-------------| | POST | /api/v1/external/chat/ | Send message, get response | | POST | /api/v1/external/chat/with-files/ | Send message with file attachments | | GET | /api/v1/external/sessions/ | List sessions | | POST | /api/v1/external/sessions/ | Create session | | DELETE | /api/v1/external/sessions/{id}/ | Delete session | | GET | /api/v1/external/sessions/{id}/history/ | Get chat history | | POST | /api/v1/external/files/ | Upload file | | GET | /api/v1/external/assistants/ | List assistants | | POST | /api/v1/external/tts/ | Text-to-speech (audio blob) | | POST | /api/v1/external/avatar/speech/ | TTS with viseme data (PREMIUM+) | | GET | /api/v1/external/avatar/model/ | Get avatar model URL (PREMIUM+) | | GET | /api/v1/external/user/access/ | Check feature access | | GET | /api/v1/external/tasks/{id}/status/ | Async task status (image/video gen) |

Authentication

All requests require the X-API-Key header:

X-API-Key: your-api-key

Get your API key from your Liya AI Dashboard under Projects → API Keys.

GAR (Global Application Router)

Liya AI uses a distributed backend architecture. Each project is routed to a specific backend instance via GAR.

Your backend URL is shown in your dashboard under Settings → API Configuration:

https://app-{X}-ai.liyalabs.com

Where {X} is your assigned instance number.

| Instance | Backend URL | |----------|-------------| | 1 | https://app-1-ai.liyalabs.com | | 2 | https://app-2-ai.liyalabs.com | | 3 | https://app-3-ai.liyalabs.com |

Use this URL as the baseUrl in your widget options.

Theme Customization

Pass a theme object to customize colors:

const widget = new LiyaAvatarWidget(el, {
  apiKey: 'your-api-key',
  baseUrl: 'https://app-1-ai.liyalabs.com',
  theme: {
    primaryColor: '#6366f1',
    backgroundColor: '#ffffff',
    textColor: '#374151',
    borderRadius: '16px',
    fontFamily: 'Inter, sans-serif',
    widgetSize: 'medium',   // 'small' | 'medium' | 'large'
    zIndex: 9999
  }
})

Kiosk Mode

Kiosk mode renders a full-screen avatar experience — ideal for interactive displays, reception kiosks and digital signage:

const widget = new LiyaAvatarWidget(el, {
  apiKey: 'your-api-key',
  baseUrl: 'https://app-1-ai.liyalabs.com',
  assistantId: 'your-assistant-id',
  mode: 'kiosk',            // or 'modal_kiosk' for overlay mode
  avatarModelUrl: 'https://your-cdn.com/avatar.glb',
  locale: 'tr',
  autoSpeak: true,
})

Account Types & Feature Access

| Feature | STANDARD | PREMIUM | PREMIUM PLUS | |---------|----------|---------|--------------| | Chat | ✅ | ✅ | ✅ | | File Upload | ❌ | ✅ | ✅ | | Voice Input (STT) | ✅ | ✅ | ✅ | | Voice Output (TTS) | ❌ | ✅ | ✅ | | 3D Avatar | ❌ | ✅ | ✅ | | Custom Avatar Model | ❌ | ❌ | ✅ | | Kiosk Mode | ❌ | ❌ | ✅ |

Browser Support

| Browser | Chat | Voice Input | 3D Avatar | Audio | |---------|------|-------------|-----------|-------| | Chrome 90+ | ✅ | ✅ | ✅ | Opus | | Firefox 90+ | ✅ | ✅ | ✅ | Opus | | Safari 15+ | ✅ | ✅ (iPadOS 16+) | ✅ | MP3 | | Edge 90+ | ✅ | ✅ | ✅ | Opus | | iOS Safari | ✅ | ✅ (iOS 16+) | ✅ | MP3 |

Minimum requirements: ES6+, WebGL 1.0, AudioContext

Development

# Install dependencies
npm install

# Watch build (development)
npm run dev

# Production build
npm run build

Changelog

0.1.0 (2025-07-10)

Features

  • feat: Lip-sync overhaul — AudioContext.currentTime clock instead of performance.now() for precise audio/viseme synchronisation (matches Vue upstream)
  • feat: Smooth exponential mouth morphing — exponential smoothing formula min(speed × (0.5 + |diff| × 0.5), 0.08) eliminates jitter (matches Vue upstream)
  • feat: startVisemeSequence now fires before audio.start() for zero-latency sync
  • feat: Kiosk topbar — Settings and Close buttons moved to top-right actions group
  • feat: Chinese (ZH) language support added to i18n
  • feat: Media display — inline image and video rendering in chat messages
  • feat: MessageMediaItem type support (backend media[] array + markdown fallback)
  • fix: ARKit blendshape: inactive mouth morphs now smoothly lerp to 0 (no stuck shapes)
  • fix: Removed random intensity (0.6 + Math.random() × 0.4) — replaced with stable lipSyncIntensity
  • chore: All debug console.log / console.warn calls removed from source; drop_console enforced at build level

0.0.2

  • Kiosk / modal_kiosk layout fixes
  • Message bubbles no longer clipped at the bottom (flex-start + auto-scroll)
  • Avatar canvas height calculated from actual rendered controls height
  • Large-screen / 4K canvas overflow fixed
  • New @media (min-width: 1920px) and @media (min-width: 2560px) breakpoints

0.0.1

  • Initial public release
  • 3D avatar with real-time lip-sync
  • Voice input / output
  • File upload support
  • Session history
  • Multi-language support (TR / EN)
  • Standard, modal_kiosk and kiosk modes

Live Demo

License

MIT © Liya Labs

Support


💡 For Vue 3 projects, use the upstream package: @liyalabs/liya-3d-avatar-widget-vuejs