Concierge: We Gave the Site Chatbot a Face
Every website has the same widget in the corner: a colored circle, a text box, a logo pretending to be a person. The AI behind those boxes got dramatically better in the last two years. The boxes did not.
So we shipped Concierge: a support chat where a rigged 3D avatar blinks, idles, turns to face the conversation, and lipsyncs the answer while it speaks it aloud. Answers stream token by token, are grounded in whatever your page actually says, and the whole thing installs with one tag:
<script type="module"
src="https://three.ws/concierge/concierge.global.js"
data-concierge
data-site-name="Acme"
data-accent="#f97316"></script>
It is free, the widget is on npm as @three-ws/concierge, the wire format is open, and the landing page runs it live, where the widget's job is answering questions about itself.
Built by remixing our own stack
We did not start from zero, and that is the story worth telling. three.ws already had a walking corner companion (@three-ws/walk), a narrating page guide (@three-ws/page-agent), and a battle-tested free-first LLM chain behind /api/chat. Concierge is those three things recombined and pointed at support:
- The face comes from the page-agent lineage: a transparent WebGL stage that loads a rigged GLB, frames it as a bust, plays a real idle clip when the model ships one and a procedural breathing-and-blink loop when it does not. The avatar catalog is the same diverse, rigged-only, viseme-capable roster.
- The mouth is text-to-viseme lipsync, not audio analysis: the sentence is tokenized into a timed phoneme sequence and the matching morph targets are lerped every frame, synced to the browser's own speech engine. No audio backend, no API key, works offline.
- The brain is the platform's free-first provider chain with automatic failover: if one free lane is throttled, the next takes over mid-conversation, and a billing-dead lane gets cooled down instead of re-probed on every request.
No crawler, no index, no onboarding call
Products in this category ask you to connect a knowledge base, wait for a crawl, and keep it synced. We inverted the whole thing: the visitor is already on your page, so the widget reads it at the moment of the question. Title, meta description, headings, nav labels, the main content, all capped to a strict budget, plus an optional knowledge attribute where you paste the facts that matter (pricing, policies, contact).
The server folds that snapshot into a grounded system prompt with one non-negotiable rule: if the answer is not in the site information, say so and point at the closest real link. Never invent a price. Edit your pricing page and the very next answer reflects it. Nothing to re-index, ever.
It speaks while it streams
The detail we are proudest of: answers arrive over SSE, and the widget splits the stream into sentences as they complete, handing each one to the speech engine while the rest is still generating. The avatar starts talking about your refund policy before the model has finished writing about it. Muted, or on a browser without speech synthesis? The captions and the lipsync timeline still play, so the experience never silently stalls.
The boring parts, done properly
- A closed widget costs your page zero GPU and no GLB download; the 3D stage initializes on first open.
- Every state is designed: empty state with suggestion chips, skeleton shimmer while the rig loads, typing dots, a streaming caret, and an error bubble with a retry that rewinds the failed turn.
- Model output renders through a strict markdown-lite renderer: escaped first, markup second,
javascript:links never survive. - Light and dark themes follow the visitor's system, one accent color restyles everything, and
prefers-reduced-motionis respected throughout. - The backend is anonymous, CORS-open by design, rate-limited per IP and globally, and pre-moderated fail-open.
Bring your own backend
The hosted endpoint is free, but nothing locks you to it. The wire format is three SSE event types (chunk, done, error) over one POST; point the endpoint attribute at any server that speaks it. The production reference implementation, failover and all, is open in the repo.
Try it on the landing page, read the docs, or go deep with the build tutorial that walks through every module. And if you ship it on your site, tell @trythreews, we collect screenshots of our avatars working other people's front desks.