This demo showcases synchronized UI choreography between an Anam persona and a live 3D terrain view. As the persona speaks, the app flies to landmarks, highlights them, and opens contextual panels and media.
If the video does not render on GitHub, use this link and click View raw to download: Watch the demo video
Editable source: docs/editable-diagram.html
- Browser UI (React + Mapbox GL) orchestrates map, panels, and media.
- Backend API mints Anam session tokens and proxies media search.
- Anam Platform handles LLM, TTS, avatar video, and tool calls.
- Media providers: Pexels (photos + video) and Openverse (photos).
- Map providers: Mapbox tiles, Mapillary street imagery (optional).
- Node.js (v16+)
- Anam API key (from lab.anam.ai)
- Mapbox API token
- Optional: Pexels API key for live photos/videos
- Optional: Mapillary token for street imagery
cd backend
npm install
cd ../frontend
npm installOr run .\run-anam-travel.cmd -Install from the repo root (Windows).
Create .env files in backend/ and frontend/:
# backend
ANAM_API_KEY=your_anam_api_key_here
PORT=3001
CORS_ORIGINS=http://localhost:3000
PHOTO_PROVIDER=auto
VIDEO_PROVIDER=pexels
PEXELS_API_KEY=
# Optional provider overrides
OPENVERSE_API_URL=https://api.openverse.org/v1/images
OPENVERSE_LICENSE_TYPE=all
PEXELS_API_URL=https://api.pexels.com/v1/search
PEXELS_VIDEO_API_URL=https://api.pexels.com/videos/search
# frontend
VITE_MAPBOX_TOKEN=your_mapbox_token_here
VITE_BACKEND_URL=http://localhost:3001
VITE_CITY=tunis
VITE_DEMO_MODE=true
VITE_TOOL_FALLBACK=false
VITE_MAPILLARY_TOKEN=
VITE_LIVE_PHOTOS=false
VITE_PHOTO_PROVIDER=auto
VITE_VIDEO_PROVIDER=pexelsNotes:
- Set
VITE_CITYtotunisoristanbulto choose the default city. - Set
VITE_MAPILLARY_TOKENto enable street-level imagery. - Set
VITE_LIVE_PHOTOS=trueto fetch live media. - Keep
PHOTO_PROVIDERandVITE_PHOTO_PROVIDERaligned when using live photos. - Video search is currently supported via Pexels (
VIDEO_PROVIDER=pexels).
- Start backend and frontend:
.\run-anam-travel.cmd(Windows), ornpm startinbackend/andnpm run devinfrontend/
- Open http://localhost:3000
- Click "Start Your Journey"
- Ask Sofia about a city or landmark
- "Tell me about Tunis"
- "What can I see in the Medina?"
- "Tell me about the ancient ruins of Carthage"
- "What's the most beautiful spot in Tunis?"
- "I'm interested in historical sites"
The persona is configured with Client Tools. When Sofia decides to highlight a landmark, she calls a tool like fly_to_landmark, show_landmark_panel, or show_media.
client.addListener(AnamEvent.CLIENT_TOOL_EVENT_RECEIVED, (event) => {
// eventData can be a JSON string, so normalize before passing along.
orchestrator.handleToolCall(event.eventName, event.eventData);
});If your SDK still emits TOOL_CALL, register that event too and pass the same handler.
The UI reacts to speech state for indicators and interruptions.
client.addListener(AnamEvent.MESSAGE_STREAM_EVENT_RECEIVED, (event) => {
if (event.type === 'persona') {
setPersonaState('speaking');
}
});The orchestrator performs the actual choreography.
await orchestrator.handleToolCall('fly_to_landmark', { id: 'medina', zoom: 15 });- Curated media and search hints live in
frontend/src/data/landmarks_db.json. - Landmarks can define
imageUrls,videoUrl,photoQuery,videoQuery,videoInclude,videoExclude, andphotoExclude. - When
VITE_LIVE_PHOTOS=true, the frontend merges live results from/api/photosand/api/videoswith the curated URLs. - If live search returns nothing, the UI falls back to curated media.
Edit frontend/src/data/landmarks_db.json:
{
"paris": {
"city": {
"name": "Paris",
"coordinates": [2.3522, 48.8566],
"zoom": 12
},
"landmarks": [
{
"id": "eiffel-tower",
"name": "Eiffel Tower",
"coordinates": [2.2945, 48.8584],
"description": "Iconic iron lattice tower...",
"zoom": 16
}
]
}
}Update the system prompt and persona config in frontend/src/components/TravelAgentDemo.tsx.
- Verify the Mapbox token is present and valid.
- Check browser console for errors.
- Ensure hardware acceleration is enabled if the map appears black.
- Confirm the backend is running and reachable at
VITE_BACKEND_URL. - Verify
ANAM_API_KEYand CORS settings. - Check the browser console for WebRTC errors.
- Tune
photoQueryandvideoQueryper landmark. - Update
videoInclude/videoExcludeandphotoExcludeto filter noisy results.
- Expand curated media coverage with verified, relevant sources.
- Improve media relevance filters per landmark.
- Add additional cities and landmark packs.
- Layout modes for intro, tour, and wrap-up states.
- Preference-driven itineraries (vibe, walking level, budget).
- Optional low-bandwidth / map-performance presets.
MIT License - Feel free to use and modify
- Anam AI for persona technology
- Mapbox for mapping platform
- OpenStreetMap for geographic data
- Openverse for live photo search
- Pexels for live photo and video search
- Landmark photos and attribution details in
docs/ASSETS.md
