← commslink.netView on GitHub

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

  1. Quickstart
  2. The component API
  3. Brains and voices — bring your own
  4. Affordances — surface-aware behavior
  5. Imperative control
  6. Relationship to CommsLink Chat
  7. 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:

PropWhat it does
modelURL to a .vrm / .glb avatar model (VRoid-compatible; any gender or style).
systemPromptThe persona — who this character is.
nameDisplay name.
brainLLM config or a custom Brain implementation (see below).
voiceTTS config or a custom Voice implementation.
affordancesSurface-scanning behavior (see below).
anchorsNamed world positions the NPC can be sent to.
onSpeakingChangeFires when the NPC starts/stops speaking (drive your UI).
onReadyFires after the model loads — add your world geometry to the exposed scene, then call rescanAffordances().
className / styleStandard 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. openai with your key) or your own object implementing respond({ 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-in webspeech (free, in-browser) or your own speak(text) => Speech, where Speech is 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.

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.respond through 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.