Model or dataset
semperai/amica avatar
semperai/amica

Amica: a 3D character on your desktop that listens back

Amica is an open source interface for interactive communication with 3D characters with voice synthesis and speech recognition.

1,612 stars269 forksTypeScriptMIT

At a glance

What is it?
A Next.js and three.js front end that puts a VRM avatar in the browser, wires Whisper to a local or hosted language model, and returns speech with an emotion engine attached.
Who is it for?
Amica is worth reading as a wiring diagram rather than as a finished product. The reason is that every interesting piece of the pipeline is swappable, and the repository shows you exactly where the seams are: Transformers.js and Whisper for perception, one of seven named chat backends for generation, and a comparable list of speech synthesizers.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A fork of ChatVRM that grew an emotion engine

The README states the project's origin plainly: it began as a fork of ChatVRM by Pixiv, and the History section links back to the original at pixiv.github.io/ChatVRM. That matters for reading the code, because ChatVRM was a demonstration of putting a VRM model on a web page and making it talk, and almost everything structural in this repository descends from that. The things Amica added are the parts you would not get from the upstream demo.

The short description in the repository metadata calls it an open source interface for interactive communication with 3D characters, and the README expands on the three capabilities: natural voice chat, vision, and an emotion engine that lets the character express feelings. The emotion engine is the differentiator. Response text can include emotional expressions, and the voice can be adjusted to fit the character, so the avatar reacts rather than just reciting.

The rendering side is ordinary by now. Three.js draws the scene, `@pixiv/three-vrm` loads and animates the character, and the package manifest pins three-vrm at `^3.1.2`. Character files are imported as VRM, which is the glTF based format for humanoid avatars, so anything you can find in that format will load. The README announces Amica 1.2 with VRM import, per-character voice tuning and emotional expression in the generated text, and points at a hosted demo plus separate documentation at docs.heyamica.com.

The repository reports 1599 stars, 267 forks and 19 open issues, with a default branch named master. Topics cover ai, assistant-chat-bots, computer-vision, llm, speech-recognition and tts, which is an accurate summary of the pipeline rather than a marketing claim.

Seven chat backends, and what the browser does before any of them runs

The chat layer is deliberately pluggable. The README lists Llama.cpp server, the ChatGPT API, Window.ai, Ollama, KoboldCpp, Oobabooga and OpenRouter, with the note that the OpenAI compatible API means anything shaped like LM Studio works too. Only the first and last need a key; the rest are local servers you start yourself. Nothing in the repository forces a choice at build time.

Before the model is ever called, the browser is doing real work. `Transformers.js` runs models in the browser rather than on a server, and Whisper handles speech recognition there too. Voice activity detection uses Silero VAD through `@ricky0123/vad-react`, which is what lets the character know you have finished speaking instead of waiting for a fixed duration. This is the part of the design that shapes the user experience: recognition, endpointing and rendering all happen locally, so the latency before a reply is generated is network-independent even when the model itself is remote.

Vision follows the same pattern. The README names Bakllava as the vision component, and the Ollama release notes describe trying it by running `ollama run llava` and pointing the vision setting at it, so a local multimodal model is a supported path. The topics list includes computer-vision for the same reason.

Text to speech is the widest menu in the project: Eleven Labs, SpeechT5, the OpenAI API, Coqui for local synthesis, RVC, and AllTalkTTS. Reading that list tells you what the emotion feature is actually built on. RVC is a retrieval based voice conversion service, which means the character's voice can be a conversion of another voice rather than a synthesis from scratch. That is why the README can talk about adjusting the voice to fit the character rather than only picking a voice.

Three commands to a running character on port 3000

The local path is short enough to hold in your head. Clone, install, run the development server:

bash
git clone [email protected]:semperai/amica.git
bash
npm install
bash
npm run dev

Then visit `http://localhost:3000`. There is no environment file to create first, which is worth knowing because the character will start with no chat backend wired up. Configuration is described separately, and most of it is done in `.env.local`, with `config.ts` in the source tree holding the available options.

The dev script is not a bare `next dev`. The package manifest shows `npm run dev` expanding to `npm run generate:paths && npm run build:workers && next dev`, so two build steps run first. `generate:paths` executes `npx node scripts/generate_paths.js`, and `build:workers` bundles `src/workers/bvh/generateMeshBVH.worker.js` through esbuild into `public/generateMeshBVH.worker.js`. That second one is the interesting detail: a bounding volume hierarchy worker for the character mesh, precompiled so the browser is not building it at runtime. A character with heavy geometry is the reason this exists, and it also means a first start takes longer than a plain Next.js dev boot.

Desktop builds use Tauri rather than Electron, and the same manifest exposes the `tauri` script, so development is:

bash
npm run tauri dev

The README carries a Windows specific warning that is easy to skim past and worth reading twice: create a new folder for Amica during installation, because uninstalling can otherwise delete other files. That is a Tauri installer path bug being worked around in documentation, which tells you something about how the desktop distribution is maintained.

The OpenRouter key is a public variable, so plan for a browser-side secret

Configuration for OpenRouter is three environment variables in `.env.local`: `NEXT_PUBLIC_OPENROUTER_APIKEY` as required, `NEXT_PUBLIC_OPENROUTER_URL` optional and defaulting to the public OpenRouter API, and `NEXT_PUBLIC_OPENROUTER_MODEL` optional and defaulting to `openai/gpt-3.5-turbo`.

The prefix on all three is the thing to notice. In Next.js, a variable named with a `NEXT_PUBLIC_` prefix is inlined into the client bundle at build time, which means the key is readable by anyone who opens developer tools on the running page. There is no server-side secret here. For a local installation that only ever talks to a model you are also running, the practical effect is limited, because the same person can read `.env.local`. The moment the built app is reachable by anyone else, or you use a hosted key tied to a paid account, that arrangement matters.

Two ways out exist and neither is enforced by the code. Route through a small server of your own and keep the key there, which is the ordinary Next.js answer. Or use one of the local backends, where Ollama, KoboldCpp, Oobabooga or a llama.cpp server need no credential at all and the entire pipeline from speech recognition onward stays on the machine.

The README defers the rest of the configuration surface to `config.ts` and to external documentation, so the three variables above are the only ones spelled out in the repository itself. Anything beyond them you are reading the docs site for, and the README says that documentation is still being updated after the 1.2 release, which is a fair signal about how settled that surface is.

The container path disagrees with the README in three separate ways

The tree carries a `Dockerfile` and a `docker-compose.yml`, and neither matches the documented local workflow exactly. The compose file is this:

yaml
version: "3"
services:
    amica:
        build: .
        ports:
            - "80:3000"
        container_name: amica

The first disagreement is the port. The README tells you to visit `http://localhost:3000` after `npm run dev`, and the container publishes host port 80 to container port 3000. Both are internally consistent, but they are not the same URL, and nothing in the README mentions the compose file at all.

The second is the package manager. The tree contains `package-lock.json` and no yarn.lock, and the README uses `npm install` throughout. The Dockerfile tries to be helpful about this in its dependency stage, checking for a yarn lockfile first, then npm, then pnpm. But the build stage ignores that logic:

dockerfile
FROM node:18-alpine AS base
WORKDIR /app
RUN yarn build
EXPOSE 3000
ENV PORT 3000

That is `RUN yarn build` unconditionally, in an image that does not install yarn, against a project whose committed lockfile is npm's. The commented-out `# RUN npm run build` underneath shows the author knew about the mismatch and left the yarn line active. Expect this build to need a fix before it works.

The third is the base image. Node 18 alpine is a reasonable choice for the framework in use, but the manifest pins a Next.js 14 line and a Sentry SDK at `^8.34.0`, both of which moved their supported Node floors during that period. Nothing here is broken by construction, but it is the kind of pin that ages badly, and the image is not rebuilt automatically against newer versions.

Also worth knowing: three Sentry config files sit at the repository root for client, edge and server, and Supabase is in the dependency list. Whether those are active in your build depends on environment variables you supply, not on anything in the compose file.

Four places report a version, and no two of them agree

Version information in this repository is inconsistent, and the inconsistency is informative about how the project is maintained.

The README announces Amica 1.2 as the current release and describes its features. The package manifest says `"version": "0.1.0"` with `"private": true`, so no npm version is ever published from it and the field is effectively inert. The newest tag on GitHub is Amica 0.2.1, published 2023-12-23, described as a patch release fixing macOS microphone and webcam support, improving the Ollama implementation and adding initial Docker setup. Before that came 0.2.0 on 2023-12-16 with desktop builds for Mac, Windows and Linux, and 0.1.2 on 2023-12-15 adding Ollama vision support.

So the sequence runs 0.1.2, 0.2.0, 0.2.1 by tag, then 1.2 by README, with 0.1.0 in the manifest. The Docker setup that the 0.2.1 notes call initial is the compose file still in the tree, build problems included. The gap between the newest tag and the last push, 2026-09-22, is close to three years, on a repository with 19 open issues and a non-archived state. The honest reading is that tagged releases stopped being the distribution channel once the hosted demo and the Tauri desktop builds took over, and the README version refers to the product rather than to a tag you can install.

The licence is a cleaner story and worth reading properly. The README says the majority of the project is released under the MIT licence as found in the LICENSE file, while assets such as 3D models and images are released under their respective authors' licences. Since the whole point is importing VRM characters, that second sentence is the operative one for anyone shipping this commercially: the code is permissive and the avatars are not necessarily yours to redistribute. The repository metadata reports MIT, which reflects the code and flattens the distinction the README draws.

Editorial conclusion

Amica is worth reading as a wiring diagram rather than as a finished product. The reason is that every interesting piece of the pipeline is swappable, and the repository shows you exactly where the seams are: Transformers.js and Whisper for perception, one of seven named chat backends for generation, and a comparable list of speech synthesizers. The gaps are just as instructive. Version numbering is inconsistent across four places, the Docker build runs yarn against a repository that ships a package-lock.json, and the compose file publishes on port 80 while the README tells you to visit port 3000. Secrets deserve care too, since the OpenRouter key is configured as a NEXT_PUBLIC_ variable and therefore ships to the browser. The last push was 2026-09-22 and the newest release is Amica 0.2.1 from 2023-12-23, so plan to track the branch. Before you use the character assets commercially, read the licence split in the README, which puts code under MIT and assets under their authors.

Frequently asked questions

What is Amica and how does it talk to you?

Amica is a Next.js and three.js application that displays a VRM 3D character and holds a voice conversation with it. Speech recognition runs through Whisper in the browser with Silero VAD for endpointing, generation goes to one of seven named chat backends such as Ollama or OpenRouter, and the reply is spoken by one of several text to speech engines and animated onto the character with an emotion engine.

What do I need installed to run Amica locally?

Node and npm, then three commands: `git clone [email protected]:semperai/amica.git`, `npm install`, and `npm run dev`. Open http://localhost:3000 afterwards. No backend is required to start, but you do need to point the app at a chat backend in `.env.local` before it can answer you. The dev script also precompiles a mesh worker, so the first start takes longer than a plain Next.js boot.

Can Amica run entirely offline with a local model?

Yes. The README lists Ollama, KoboldCpp, Oobabooga and a llama.cpp server as chat backends, and Coqui for local speech synthesis, so the generation and speech halves can both stay on your machine. Speech recognition and rendering are already browser side, which means a fully local pipeline is achievable once you start the model server yourself.

Is it safe to put my OpenRouter API key in the Amica configuration?

Be aware of where it goes. The documented variables are named `NEXT_PUBLIC_OPENROUTER_APIKEY`, `NEXT_PUBLIC_OPENROUTER_URL` and `NEXT_PUBLIC_OPENROUTER_MODEL`, and that prefix causes Next.js to inline the value into the client bundle, so the key is visible to anyone who opens developer tools. That is fine for a private local install with a free or local key. For a key tied to a paid hosted account, put a small server in front of it or switch to a local backend.

What is the difference between the local and Docker setups in Amica?

The local workflow from the README serves on port 3000, while the checked in docker-compose.yml publishes host port 80 to container port 3000, so the URLs differ and the README does not mention the compose file. The Dockerfile also builds with `RUN yarn build` against a repository that ships `package-lock.json` and no yarn.lock, so the container build is likely to need adjusting before it succeeds.

Can I use Amica's VRM characters in a commercial product?

Treat the code and the assets as two separate questions. The README states the majority of the project is MIT licensed, and that assets such as 3D models and images are released under their respective authors' licences. GitHub reports the repository licence as MIT, which reflects the code. Any character you import carries its own terms, so check the model before redistributing it.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. semperai/amica on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/semperai-amica.svg)](https://hysenlabs.com/projects/semperai-amica)