GeminiVRM is a polished fork of pixiv/ChatVRM that replaces the old OpenAI + Koeiromap response path with Gemini Live native audio while keeping the browser-first VRM experience intact.
The current build focuses on:
- browser-first single-avatar chat with streamed Gemini Live transcript and audio
- capped dual-host podcast mode where
YukitoandKiyokaalternate short native-audio turns from one topic - bundled
public/Kiyoka.vrmandpublic/Yukito.vrmavatars, per-mode voice controls, and Mixamo-backed motion presets - a local-first workflow with optional YouTube relay and browser automation hooks
- Stream Gemini Live transcript and audio in the browser for character chat
- Send microphone audio directly into Gemini Live for character chat push-to-talk turns
- Switch the chat microphone between push-to-talk and hands-free automatic reply mode
- Switch between
Character chatandPodcast modefromSettings - Start with bundled
Kiyoka.vrmandYukito.vrm, or load your own local.vrm - Tune the live model, single-chat voice, system prompt, podcast turn cap, and per-host podcast voices from the UI
- Reuse the VRM lip-sync pipeline with bundled Mixamo idle and talking motion rotation
- Configure an optional YouTube Live relay from
Settings->Streamingand receive inbound live chat comments inside GeminiVRM - Drive the app from
window.geminiVrmControlorpostMessagefor local automation and orchestration - Run a lightweight smoke E2E check with Playwright
- Publish the static app and docs to GitHub Pages
- Next.js 15
- React 18
@google/genai@pixiv/three-vrm- TypeScript
- Tailwind CSS
- Playwright
npm install
npm run dev -- --hostname 127.0.0.1 --port 3100Open http://127.0.0.1:3100, paste a Gemini API key from Google AI Studio, and press Start.
To run the app and docs together, use:
npm run dev:allThis starts the app at http://127.0.0.1:3100 and the docs at http://127.0.0.1:4173.
See .env.example.
NEXT_PUBLIC_GEMINI_API_KEY- Optional local default key for browser use
NEXT_PUBLIC_GOOGLE_CLIENT_ID- Optional Google OAuth web client ID for the YouTube Live relay settings
BASE_PATH- Optional prefix for GitHub Pages or subpath deployments
NEXT_PUBLIC_GEMINI_LIVE_MODEL- Optional default model shown in the UI
NEXT_PUBLIC_GEMINI_LIVE_VOICE- Optional default Gemini prebuilt voice name
This app is tuned for gemini-3.1-flash-live-preview and no longer auto-falls
back to older Gemini Live preview models.
- Launch the app and enter a Gemini API key.
- Open
Settingsand chooseCharacter chatorPodcast mode. - In character chat, keep the default
Kiyoka.vrmavatar or load another VRM, then send a text prompt or use the microphone button. - Open
Settingsif you want to switch the microphone betweenPush to talkandHands-free. In hands-free mode, Gemini replies automatically after you pause. - In podcast mode, enter one topic and let Yukito and Kiyoka alternate short audio turns until the configured turn cap is reached.
- Open
Settings->Podcast settingsif you want to change the max loop count or podcast-only voice routing. - Use
Settingsto tune the live model, chat voice, microphone mode, system prompt, idle motion, and other core runtime settings. - If you want live streaming support, open
Settings->Streaming->YouTube relay, useNEXT_PUBLIC_GOOGLE_CLIENT_IDor paste a Google OAuth client ID into the page, sign in with Google, pick an active or upcoming broadcast, turn relay on, and toggle auto-reply separately if you want Gemini to answer incoming comments automatically while streaming this app window through YouTube Live Control Room or OBS.
public/ Static VRM, images, and social assets
scripts/ Release, Pages, and smoke-test helpers
src/components/ UI components
src/features/chat/ Gemini Live transport and config
src/features/externalControl/ Browser automation and postMessage control hooks
src/features/lipSync/ Audio playback and analysis
src/features/podcast/ Dual-host podcast orchestration
src/features/vrmViewer/ Viewer and model runtime
src/lib/fbxAnimation/ Mixamo retargeting helpers for bundled motions
docs/ Architecture, deployment, release, and QA notes
- Live docs (English): https://sunwood-ai-labs.github.io/GeminiVRM/docs/
- Live docs (Japanese): https://sunwood-ai-labs.github.io/GeminiVRM/docs/ja/
- Getting Started
- Usage Guide
- Podcast Benchmark Report
- YouTube Relay Guide
- Release Notes
- Release Articles
- Latest v0.3.0 Release Notes
- Latest v0.3.0 Runtime And Benchmark Guide
- Architecture notes
- Deployment guide
- Troubleshooting
- Repository QA inventory
Local docs commands:
npm run docs:build
npm run docs:previewnpm run verifyor run each step manually:
npm run lint
npm run build
npm run docs:build
npm run build:pages
npm run e2e:smokeThe smoke test checks that the app boots, the send flow works, and known chunk/icon/runtime request failures stay absent. When no Gemini API key is present, the missing-key error path is treated as a valid smoke outcome.
When you benchmark podcast relay with Playwright, keep the run isolated from the watched Next.js workspace.
- Use
npm run bench:podcast:topic -- .tmp-topic-files/agi.txtornode scripts/run-podcast-topic-benchmark.mjs <topic-file>when the topic contains Japanese text or other non-ASCII content. - Keep
E2E_BENCH_OUTPUT_DIRoutside the repository. The benchmark runner now defaults to the system temp directory so artifact writes do not triggernext devFast Refresh. - Use
E2E_BENCH_MODES=streamingorE2E_BENCH_MODES=batchwhen you want isolated retries per mode. - If you are collecting many repeated runs under
next dev, restart the dev server between isolated runs to keep Playwright stable.
For the bilingual latency chart and the text-overflow verifier:
- Run
npm run report:podcast-benchmarkto rebuild the English and Japanese report images plus the shared JSON summary. - The same command also updates
docs/public/benchmarks/podcast-benchmark-history.jsonand.csvfor longitudinal tracking. - The tracked history fields are
generatedAt,benchmarkKey,gitSha,sourceKind,topics,firstAudio*, andhandoff*. - Run
npm run verify:podcast-benchmark-layoutto check missingdata-fit-boundaryannotations, text overflow, and text-on-text overlaps in both SVG files. - See Podcast Benchmark Report for the latest captured numbers, caveats, and output paths.
The repository is prepared for GitHub Pages deployment through GitHub Actions.
- Static export uses
BASE_PATHfor subpath hosting NEXT_EXPORT=trueenables a Pages-ready static build- Pages artifacts are produced from
.next-pages - CI validates lint, build, and smoke E2E on every push and pull request
For step-by-step instructions, see docs/deployment.md.
- This project still sends the Gemini API key from the browser, matching the original local-first ChatVRM setup style.
- The YouTube relay stores the Google OAuth client ID and short-lived YouTube access token in browser local storage until sign-out or token expiry so the session can be restored after reload.
- The external-control
postMessagesurface is enabled by default in development. In production it is gated by local storage and allowed-origin checks, so do not assume it is globally active on public deployments. - For public production deployments, prefer a token relay or another server-side key handling strategy.
