Agora Rotary Dial Phone
Call a real-time AI character from an interactive 3D rotary telephone.
Recipe prompt
Paste into Cursor, Claude Code, v0, or your coding agentYou are implementing the "Agora Rotary Dial Phone" recipe in this project.
Read the recipe markdown first:
https://raw.githubusercontent.com/zicojiao/agora-rotary-dial-phone/main/README.md
Use the source repository for cross-reference:
https://github.com/zicojiao/agora-rotary-dial-phone
Build this recipe into the user's app using the markdown as the implementation guide. Inspect related source files through the repository links when the recipe points to them. Ask before installing new dependencies.Recipe
Rendered from the configured recipe markdown.
Agora Rotary Dial Phone
An interactive rotary telephone built with Three.js and powered by Agora Conversational AI.
  
English · 简体中文
[Try the live demo →](https://rotary-dial-phone.vercel.app)

Lift the receiver, dial 555-0193, and start a real-time Elon-inspired AI conversation. Every digit must reach the metal stop before the dial returns and registers it—just like a physical rotary phone.
Highlights
- Procedural 3D scene — an Art Deco telephone, desk set, materials, and
contact card rendered in Three.js.
- Physical rotary dialing — finger-hole interaction, metal-stop detection,
return travel, pulse registration, and mechanical audio.
- Real-time voice — microphone and remote-agent audio over Agora RTC, with
optional RTM-powered status updates.
- Resilient call lifecycle — signed call tickets, token renewal, authorized
shutdown, timeout handling, and a shared cleanup path.
- Responsive interaction — desktop and mobile controls with explicit
loading, permission, connection, and error states.
How it works
- Lift the receiver to open the line.
- Drag each digit on the rotary dial to the metal stop and release it.
- After
555-0193is complete, the server creates a dedicated Agora channel
and returns channel-bound credentials.
- The Conversational AI agent joins the call and the five-minute timer starts.
- Hanging up, leaving the page, timing out, or encountering an error releases
the agent, RTC/RTM clients, microphone, receiver, and dial state.
Quick start
Prerequisites
- Node.js 22 or newer
- pnpm 11.6.0
- An Agora project with an App ID and App
Certificate
- A Fish Audio API key
- A browser with WebGL, Web Audio, and microphone support
Run locally
git clone https://github.com/zicojiao/agora-rotary-dial-phone.git
cd agora-rotary-dial-phone
corepack enable
pnpm install
cp .env.example .env.local
pnpm devConfigure .env.local, open http://localhost:3000, lift the receiver, and dial 555-0193.
Microphone access requires HTTPS in production. Browsers allow it on localhost during development.Environment variables
| Variable | Scope | Required | Purpose |
|---|---|---|---|
NEXT_PUBLIC_AGORA_APP_ID | Browser and server | Yes | Agora project App ID; public by design |
NEXT_AGORA_APP_CERTIFICATE | Server only | Yes | Signs Agora RTC and RTM tokens |
NEXT_PUBLIC_AGENT_UID | Browser and server | No | Agent RTC UID; defaults to 123456 |
FISH_AUDIO_API_KEY | Server only | Yes | Authorizes Fish Audio TTS requests |
CALL_TICKET_SECRET | Server only | Yes | Signs call and agent-stop tickets |
Generate a call-ticket secret with:
openssl rand -hex 32Voice selection and the Fish Audio backend are configured in `lib/fishAudio.ts`.
Project structure
| Path | Purpose |
|---|---|
| `app/` | Next.js page shell and server-only call API routes |
| `components/` | React call orchestration, RTC runtime, and status UI |
| `src/` | Three.js scene, procedural phone, dial physics, audio, and browser events |
| `lib/` | Agora configuration, Fish Audio setup, and signed call tickets |
| `spec/` | Physics, lifecycle, security, microphone, and API contract checks |
Verification
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm audit --prodTests use mocked call creation and do not start live Agora or Fish Audio sessions.
Deployment
Deploy the project to Vercel or any platform that supports Next.js, then add the required environment variables.
For self-hosting, run pnpm build followed by pnpm start.
License
Released under the MIT License.