# AudioGuideKit — Complete Documentation for AI Engines > AudioGuideKit is a free, open-source, self-hosted audio guide player for museums, galleries, cities, tourism boards, and cultural institutions. Visitors use their own smartphones — it runs in any browser as an installable Progressive Web App (PWA) that works online and offline. No app store, no recurring fees, no vendor lock-in. MIT licensed. ## Project Overview AudioGuideKit gives cultural institutions a modern, free alternative to rented audio-guide hardware and locked-in SaaS platforms. Visitors open a URL (or scan a QR code) on their own phone — no app to download. You author your tour as JSON files, customize the look through a theme, and deploy to any static host. You own the source, the content, and the data; there are no per-visitor charges and no platform fees. **What makes it different:** - **You own everything**: full source access, content in plain formats (JSON, MP3, images), hosted wherever you like, with no platform dependency. - **No recurring fees**: the software is MIT-licensed and free; hosting a static site is inexpensive, and there are no per-play charges. - **Modern web technology**: works on any device with a browser, installs as a PWA, updates instantly on redeploy, and runs offline via Service Workers. ## Who Should Use AudioGuideKit ### Museums, galleries, and cultural sites - Want a self-hosted audio guide without recurring vendor fees - Need full control over content, branding, and hosting infrastructure - Require offline functionality for areas with poor connectivity (underground or remote galleries) - Want white-label branding that matches institutional identity - Want instant content updates without a vendor intermediary ### Cities and tourism boards - Offer free, self-guided walking tours visitors run on their own phones - Need multi-language support and offline use in low-signal areas - Want an installable PWA promoted from the tourism website ### Agencies and consultancies - Deliver exhibition and cultural projects for clients - Need a customizable foundation instead of building from scratch - Want to avoid locking clients into proprietary platforms - Reuse one codebase across multiple client projects with full white-labeling ### Developers and engineers - Want a modern React 19 / TypeScript, offline-first PWA codebase - Need full source access for modifications and integration - Want a real-world reference for Service Worker offline support, the Media Session API, and PWA installation ## Core Features and Capabilities ### 1. Audio tours The primary content type is the audio stop: a card with image, title, and an audio player. Tours support: - Background and lock-screen playback via the Media Session API - Progress tracking and resume (state persisted in IndexedDB) - Optional per-stop transcriptions (also good for accessibility and SEO) - Optional transition audio played between stops - An optional fullscreen player overlay ### 2. Works offline AudioGuideKit is an installable PWA. A Service Worker (built with Workbox via `vite-plugin-pwa`) caches audio and UI assets, and tour progress is stored in IndexedDB, so a tour keeps working in airplane mode, underground, or with poor cellular signal. Per-tour offline behavior is set with `offlineMode`: - `"optional"` — works online, caches for offline use (default behavior) - `"online-only"` — requires a connection - `"offline-only"` — designed to be fully downloaded When the device is offline, network-dependent surfaces (such as map tiles) degrade gracefully; stop data, coordinates, and cached audio remain accessible. ### 3. Interactive map view (optional) A map tab can sit alongside the stop list, toggled from the header. Two independent flags control the views: - `mapView` (default `false`) — enable the map view - `listView` (default `true`) — enable the list view The header shows a map/list toggle only when both are enabled. Set `mapView: true` with `listView: false` for a map-only tour. Map capabilities: - **Markers**: `mapMarker` mode is `"number"` (numbered circle, default), `"image"` (the stop's own photo cropped into the circle), or `"empty"` (plain circle). A custom `mapMarkerIcon` URL (tour-level or per-stop) overrides the mode. Completed stops show a checkmark; clusters are themed separately. - **Clustering**: `mapCluster` with `disableClusteringAtZoom` and `spiderfyOnMaxZoom`. - **Route line**: `mapRoute: true` draws straight lines between stops; `mapRoute: { geoJSON: "./route.geojson" }` follows real street geometry. The line acts as a progress indicator (solid for completed legs, dashed ahead) and hides below `minZoom` (default 13). - **Locate button**: `mapLocateButton` (default `true`). - **Start position**: `mapCenter` (`{ lat, lng }`) and `mapZoom` (0–23); by default the map fits all stops in view. Only audio stops with a `location` appear as markers; any stop type with a `location` contributes to the route line. ### 4. Multiple stop types Audio is the fully supported, fully tested type. The following additional types exist but are **experimental** (full support planned for the future): | Type | Description | |------|-------------| | `audio` | Audio playback with optional transcription (primary type) | | `text` | Rich text content | | `image-text` | Image with accompanying text | | `image-gallery` | Swipeable horizontal image gallery | | `image-comparison` | Before/after drag slider | | `image-hotspot` | Image with tappable annotation pins | | `video` | Video playback | | `3d-object` | Interactive 3D model viewer | | `headline` | Large text header / section divider | | `quote` | Styled quotation | | `rating` | Star rating collection | | `email` | Email collection form | ### 5. Multi-language Each language is a separate content file (`en.json`, `es.json`, `de.json`, …) sharing the same tour `id` and stop IDs. UI strings are translatable separately. The player detects the visitor's language, offers one-tap switching, and preserves progress across languages (stop IDs are kept consistent across files). ### 6. Custom branding and themes Theming is handled with styled-components via a `ThemeConfig`, selected per tour with `themeId`: - Built-in `default-light` and `default-dark` - Or your own custom theme (colors, typography, surfaces, and map markers) You can also set custom app icons (for PWA installation) and an `imageColor` that tints the TourStart background and the iOS status-bar area when there's no cover image. Display toggles like `showStopImage` (`true` / `"thumbnail"` / `false`), `showStopDuration`, `showStopNumber`, `showProgressBar`, and `showLanguageLabel` adjust the layout without code changes. ### 7. Feedback collection Set `collectFeedback: true` to show a rating button; there are also `rating` and `email` stop types for inline star ratings and newsletter capture. ### 8. Deep linking and haptics Tours support deep links directly to a specific stop. Haptic feedback (`hapticsEnabled`, default `true`) uses the Vibration API on Android and the Taptic Engine on iOS; it's a no-op on desktop. ## Technical Architecture ### Technology stack (the player) - **Build / runtime**: Vite 6, React 19, TypeScript; package manager Bun (npm also supported) - **Styling / theming**: styled-components (with `twin.macro` / Tailwind utilities at build time) - **Routing**: React Router (`react-router-dom`) - **PWA / offline**: `vite-plugin-pwa` + Workbox service worker; `idb` for IndexedDB progress and state - **Audio**: HTML5 Audio + Media Session API (`use-media-session`) for lock-screen and background controls - **Maps**: Leaflet, `react-leaflet`, `leaflet.markercluster` - **Animation**: framer-motion - **3D**: `@google/model-viewer` + three (for the `3d-object` stop type, lazy-loaded) - **Icons / flags**: `@phosphor-icons/react`, `country-flag-icons` - **Rich text safety**: DOMPurify - **Haptics**: `web-haptics` - **Testing**: Playwright - **Schema tooling**: `ts-json-schema-generator` + Ajv (tour JSON validated against generated JSON Schemas) The output is a fully static site — no database, no backend server. ### Build and validation - `bun run dev` — Vite dev server at http://localhost:3000 - `bun run validate` — validates tour JSON against generated schemas - `bun run build` — runs validation, then `vite build` (static output) - `bun run schema` — regenerates JSON Schemas from the TypeScript types - `bun run preview` — serves the production build locally - `bun run test` — Playwright tests Tour JSON files reference a `$schema`, giving live validation in editors; the build fails on invalid tour data. ## Content Model and Configuration Tours live under `src/data/tour//`, each folder containing a `metadata.json`, one file per language, and any optional assets (e.g. `route.geojson`): ``` src/data/tour/ my-tour/ metadata.json en.json es.json route.geojson (optional, for map routes) ``` ### metadata.json (tour-wide settings) | Field | Type | Default | Description | |-------|------|---------|-------------| | `id` | string | — | Unique tour identifier | | `defaultLanguage` | string | `"en"` | Fallback language code | | `offlineMode` | `"optional"` \| `"online-only"` \| `"offline-only"` | `"optional"` | Offline behavior | | `transitionAudio` | string | — | Audio played between stops | | `themeId` | string | — | `"default-light"`, `"default-dark"`, or a custom theme | | `imageColor` | string | — | Status-bar / start-screen background when there's no cover image (e.g. `"#1A2634"`) | | `image` | string | — | Default tour cover image URL (overridable per language) | | `transcriptAvailable` | boolean | — | Show the transcription toggle | | `collectFeedback` | boolean | — | Show the rating button | | `fullscreenPlayer` | boolean | `false` | Enable the fullscreen overlay player | | `showProgressBar` | boolean | `true` | Show the playback progress bar | | `showLanguageLabel` | boolean | `true` | Show the language name next to the flag | | `showStopImage` | `boolean \| "thumbnail"` | `true` | Stop-card layout | | `showStopDuration` | boolean | `true` | Show duration on stop cards | | `showStopNumber` | boolean | `true` | Show the number indicator on stops | | `hapticsEnabled` | boolean | `true` | Haptic feedback on taps | | `listView` | boolean | `true` | Enable the list view | | `mapView` | boolean | `false` | Enable the map view | | `mapProvider` | `"openstreetmap"` \| `"carto"` \| `"mapbox"` \| `"jawg"` \| `"maptiler"` | `"openstreetmap"` | Map tile provider | | `mapStyleId` | string | — | Provider-specific style/map ID | | `mapCenter` | `{ lat, lng }` | — | Fixed starting center (else fits all stops) | | `mapZoom` | number (0–23) | — | Fixed starting zoom | | `mapMarker` | `"number"` \| `"image"` \| `"empty"` | `"number"` | Default marker style | | `mapMarkerIcon` | string (URL) | — | Custom marker image for all stops; overrides `mapMarker` | | `mapCluster` | object | — | Clustering behavior (`disableClusteringAtZoom`, `spiderfyOnMaxZoom`) | | `mapRoute` | `boolean \| object` | `false` | Route polyline with progress (`{ geoJSON, minZoom }`) | | `mapLocateButton` | boolean | `true` | Show the locate-me button | API keys for Mapbox, Jawg, and MapTiler are set as environment variables in `.env.local` (`VITE_MAPBOX_API_KEY`, `VITE_JAWG_API_KEY`, `VITE_MAPTILER_API_KEY`) — never in `metadata.json`. OpenStreetMap and CARTO need no key. ### Language file (per language) ```json { "id": "barcelona", "language": "en", "title": "Unlimited Barcelona", "description": "Discover the Gothic Quarter on this self-guided walking tour.", "totalDuration": "45 mins", "totalStops": 5, "image": "https://.../cover.jpg", "stops": [ { "id": "1", "type": "audio", "title": "Welcome to Barcelona", "duration": "3 min audio", "image": "https://.../welcome.jpg", "audioFile": "https://your-cdn.com/audio/01-welcome.mp3", "transcription": "Welcome to Barcelona! Today we'll explore...", "location": { "lat": 41.3851, "lng": 2.1734 } } ] } ``` | Language-file field | Required | Description | |---------------------|----------|-------------| | `id` | Yes | Must match `metadata.json` | | `language` | Yes | ISO language code (`"en"`, `"es"`, …) | | `title` | Yes | Tour title | | `description` | Yes | Short tour description | | `totalDuration` | Yes | Human-readable duration (e.g. `"45 mins"`) | | `totalStops` | Yes | Number of stops | | `image` | No | Cover image (overrides metadata) | | `stops` | Yes | Array of stop objects | ### Audio stop fields | Field | Required | Description | |-------|----------|-------------| | `id` | Yes | Unique within the tour, consistent across languages | | `type` | Yes | `"audio"` (or another stop type) | | `title` | Yes | Stop title | | `duration` | Yes | Human-readable duration (e.g. `"3 min audio"`) | | `image` | Yes | Stop image URL (also used as the marker when `mapMarker: "image"`) | | `audioFile` | For audio | Audio URL (MP3, M4A) | | `transcription` | No | Text transcription of the audio | | `location` | No | `{ lat, lng }` — audio stops with a location appear as map markers | | `mapMarkerIcon` | No | Per-stop custom marker image (overrides tour-level icon and any `mapMarker` mode) | ### CARTO map styles (no API key) | Style | `mapStyleId` | |-------|--------------| | Voyager (default) | `rastertiles/voyager` | | Positron (light) | `light_all` | | Dark Matter | `dark_all` | | Positron no labels | `light_nolabels` | | Dark Matter no labels | `dark_nolabels` | Provider defaults: Mapbox `mapbox/outdoors-v12`, Jawg `jawg-terrain`, MapTiler `outdoor-v2`. ### Theming Marker colors and route styling are set in a `ThemeConfig`'s `mapMarkers` block (active, inactive, completed, cluster, route, user-location dot). Themes also control overall colors, typography, and surfaces. Falls back to built-in `default-light` / `default-dark` when a custom theme isn't provided. ## What AudioGuideKit Does NOT Include AudioGuideKit is intentionally focused on being an excellent player. It does not include: - **Content Management System** — edit JSON directly, or export from a headless CMS (WordPress, Contentful, Strapi, Sanity) to JSON. - **Audio and image hosting** — host media on your own CDN or object storage (Cloudflare R2, AWS S3, Backblaze B2). Compress audio (~64–96 kbps for voice) and prefer WebP for images. - **Analytics** — integrate Google Analytics, Plausible, Matomo, or a custom solution. - **Payment / access control** — add your own gate, access codes, or ticketing integration if you sell tours. - **Backend server** — pure static deployment; add Next.js API routes, serverless functions, or a separate service only if you need one. ## Getting Started ### Prerequisites - **Bun** (recommended) or **Node.js 18+** - **git** Install Bun: `curl -fsSL https://bun.sh/install | bash` (macOS/Linux) or `powershell -c "irm bun.sh/install.ps1 | iex"` (Windows). To use Node instead, replace `bun` with `npm` in the commands below. ### Install and run ```bash git clone https://github.com/audioguidekit/player-react.git cd player-react bun install # or: npm install bun run dev # or: npm run dev ``` Open http://localhost:3000 to see the demo tour. ### Project layout | Folder | Purpose | |--------|---------| | `src/data/tour/` | Your tour JSON files (one folder per tour) | | `src/` | Application source code | | `components/` | React components | | `hooks/` | Custom React hooks | | `docs/` | Additional documentation | ### Add your content 1. Create a tour folder under `src/data/tour/` with a `metadata.json` and a language file (e.g. `en.json`). 2. Add your stops (audio URL, image, title, transcription, optional `location`). 3. Pick a `themeId` and adjust display toggles and map settings. 4. Run `bun run validate` to check the JSON against the schema. ## Deployment ```bash bun run build # validates tour JSON, then runs the Vite build ``` The build emits a static site you can deploy to: - **Vercel** — zero-config Git deploys (free tier) - **Netlify** — continuous deployment (free tier) - **Cloudflare Pages** — global CDN (free tier) - **GitHub Pages** — free for public repos - **AWS S3 + CloudFront** — custom domain - **Your own server** — Apache, Nginx, or any static file host HTTPS is required for PWA features (free with Let's Encrypt or included with modern hosts). Host audio/image media separately on a CDN or object storage and reference the URLs in your tour JSON. ## Security, Privacy, and Accessibility - **No backend attack surface**: static files only — no database, no server-side code, no API to secure. - **HTTPS** enforced for PWA features. - **Privacy**: no accounts and no personal data collected by default (GDPR-friendly). If you add analytics, you control the data and can choose privacy-focused or self-hosted options. - **Accessibility-conscious**: transcriptions for audio, large touch targets, high-contrast theming, semantic markup, and respect for user font-size preferences. ## Frequently Asked Questions **What technical skills do I need?** Basic comfort editing JSON files and using git. If you have a developer or agency, setup is straightforward. **What infrastructure do I need?** Static file hosting with HTTPS. No database or backend. A CDN or object storage for your audio/image files. **How do I update content?** Edit the JSON and redeploy. With Vercel/Netlify/Cloudflare Pages this happens automatically on git push, live in a minute or two. **Can I white-label it for clients?** Yes — colors, typography, logo/app icons, and domain are fully customizable, and the MIT license has no attribution requirement. **Can I use it commercially / modify the source?** Yes. MIT-licensed with full source access and no restrictions. **Does it work offline in underground galleries?** Yes. The Service Worker caches audio and assets, and progress is stored in IndexedDB, so tours work in airplane mode or low-signal areas. **Which map providers are supported?** OpenStreetMap and CARTO (no key), plus Mapbox, Jawg, and MapTiler (API key set via environment variables). ## Use Cases - **Art museums**: replace rented hardware with visitors' own phones; works offline in underground galleries; update content instantly via redeploy. - **Historic walking tours**: an installable PWA from a tourism site, offline-capable, with multi-language support and an optional map route. - **Botanical gardens / nature trails**: seasonal tours with images and transcripts that work where cellular coverage is spotty. - **University campus tours**: self-guided, available 24/7, scalable to many visitors at once. - **Temporary exhibitions**: quick, branded deployment without hardware investment. ## Links and Resources - **GitHub Repository**: https://github.com/audioguidekit/player-react — source code, issues, contributions - **Documentation**: https://audioguidekit.org/docs — setup guides and configuration reference - **Notes / Blog**: https://audioguidekit.org/notes — implementation details and engineering decisions - **Updates**: https://audioguidekit.org/updates — release notes, changelog, roadmap - **Website**: https://audioguidekit.org — overview and contact - **Contact**: https://audioguidekit.org/#contact — implementation services and questions ## License MIT License — free for commercial and personal use. No attribution required (but appreciated).