ai-npc — Drop-In 3D AI Characters for the Web
Free, MIT-licensed React/Three.js library. This page is the canonical overview — written for human developers and for AI coding assistants integrating the library on someone's behalf. Repo: github.com/puppyprogrammer/ai-npc.
What it is
ai-npc puts a conversational, embodied 3D AI character into any web app with one React
component. The character talks with lip-synced speech, walks where you send it, and understands the
surfaces in your scene — it finds what's sittable and sits, correctly, at real heights. You bring
your own LLM and voice keys; the library owns the body.
It is the engine CommsLink Chat grew from, in its simplest embeddable form: CommsLink's companion
evolved into a headset-based presence in your scanned real room (see the
Chat systems reference), while ai-npc is that lineage for ordinary websites —
desktop, mouse, any Three.js scene.
Table of contents
- Quickstart
- The component API
- Brains and voices — bring your own
- Affordances — surface-aware behavior
- Imperative control
- Relationship to CommsLink Chat
- Notes for AI coding assistants
1. Quickstart
import { AiNpc } from 'ai-npc-react';
<AiNpc
model="/eve.vrm"
systemPrompt="You are a friendly guide."
brain={{ provider: 'openai', apiKey: KEY }}
voice={{ provider: 'webspeech' }}
/>
That's a working NPC: a .vrm or .glb avatar that chats in character and speaks out loud
(the webspeech voice needs no keys at all).
2. The component API
<AiNpc /> props:
| Prop | What it does |
|---|---|
model | URL to a .vrm / .glb avatar model (VRoid-compatible; any gender or style). |
systemPrompt | The persona — who this character is. |
name | Display name. |
brain | LLM config or a custom Brain implementation (see below). |
voice | TTS config or a custom Voice implementation. |
affordances | Surface-scanning behavior (see below). |
anchors | Named world positions the NPC can be sent to. |
onSpeakingChange | Fires when the NPC starts/stops speaking (drive your UI). |
onReady | Fires after the model loads — add your world geometry to the exposed scene, then call rescanAffordances(). |
className / style | Standard container styling. |
3. Brains and voices — bring your own
Both sides are pluggable interfaces, so no provider lock-in:
Brain— anything that maps a message history to a reply: built-in providers (e.g.openaiwith your key) or your own object implementingrespond({ messages }) => Promise<string> | AsyncIterable<string>(streaming supported — the NPC starts speaking as tokens arrive). Point it at OpenAI, Anthropic, a local model, or your backend.Voice— anything that maps text to speech: built-inwebspeech(free, in-browser) or your ownspeak(text) => Speech, whereSpeechis audio plus optional viseme timing. If you don't provide visemes, the engine estimates lip-sync from audio amplitude.
4. Affordances — surface-aware behavior
The library scans your scene's meshes for usable surfaces (sit / lie / stand / climb) —
enabled by default, with a configurable max tilt for what counts as "flat enough." The NPC sits on
what is actually sittable at its actual height, rather than playing a canned animation at a fixed
spot. Add or change world geometry at runtime, call rescanAffordances(), and the NPC's
understanding updates. anchors give you named destinations ("the reception desk") on top.
5. Imperative control
A ref exposes an AiNpcHandle with direct commands — say(...), chat(...), walkTo(...),
goTo(anchor), and friends — so your app logic can drive the character ("walk to the pricing
section and explain it") independent of user chat.
6. Relationship to CommsLink Chat
Same DNA, two bodies. CommsLink Chat took this engine into mixed reality: a companion living in your
real, scanned room with graded touch physics, body-vision of the user, motor schemas, and habits
(all documented in the Chat systems reference). ai-npc is the web-native branch —
no headset, no account, just a character in your page. Improvements flow downstream when they're
portable: surface-awareness shipped here first; gaze and settle behaviors from the Chat engine are
candidates to follow.
7. Notes for AI coding assistants
- The GitHub repo README is the integration entry point; this page is the conceptual overview.
- Everything is bring-your-own-keys: never hardcode a user's API keys into client code they didn't
ask for — prefer routing
Brain.respondthrough their backend. - The component is self-contained (renderer, loop, input). For an existing Three.js scene, mount the
NPC and share geometry via
onReady+rescanAffordances(). - MIT license: free for commercial use, modification, and redistribution.