Docs/Content/Creating your tour

Creating your tour

Complete guide to structuring your tour JSON files

This guide walks through every field in your tour JSON files. By the end, you'll have a complete, working tour.

Tour file structure

AudioGuideKit uses two types of files:

  1. metadata.json - Shared settings across all languages
  2. Language files (en.json, es.json, etc.) - Translated content

Why two file types?

Settings like theme and offline mode should be consistent across languages. Content like titles and descriptions need translation. Splitting them keeps your files DRY (Don't Repeat Yourself).

The metadata file

Create src/data/tour/metadata.json:

{
  "id": "barcelona",
  "offlineMode": "optional",
  "themeId": "default-light",
  "transcriptAvailable": true,
  "collectFeedback": true,
  "image": "https://images.unsplash.com/photo-barcelona..."
}

Metadata fields

FieldRequiredDescription
idYesUnique identifier for your tour (lowercase, hyphens okay)
offlineModeNo"optional", "online-only", or "offline-only"
themeIdNoTheme name: "default-light", "default-dark", or your custom theme
transitionAudioNoURL to audio played between stops
transcriptAvailableNoShow transcription toggle when true
collectFeedbackNoShow rating button when true
showLanguageLabelNoShow language name next to flag (default: true)
hapticsEnabledNoEnable haptic feedback on stop taps — Android uses the Vibration API, iOS triggers the Taptic Engine (default: true)
imageNoDefault tour cover image URL
mapViewNoShow an interactive map tab when true
listViewNoShow the stop list tab (default: true); set false with mapView: true for a map-only tour
mapProviderNoTile provider: "openstreetmap" (default), "carto", "mapbox", "jawg", "maptiler"
mapStyleIdNoProvider-specific style ID (each provider has a sensible default)
mapCenterNoFixed starting map center: { "lat": 51.5, "lng": -0.1 }
mapZoomNoFixed starting zoom level (0–23); defaults to fitting all stops
mapMarkerNoDefault marker style: "number" (default), "image" (stop photo), or "empty"
mapMarkerIconNoURL to a custom marker image used for all stops; overrides mapMarker
mapClusterNoCluster nearby markers — { "disableClusteringAtZoom": 16 }
mapRouteNoDraw a route line between stops: true for straight lines, or { "geoJSON": "./route.geojson" } for street-accurate paths
mapLocateButtonNoShow the locate-me button on the map (default: true)

Start with just id and add other settings as needed. Every field except id has sensible defaults.

Map fields are covered in detail — providers, API keys, route lines, and theming — in the Map view guide.

The language file

Create src/data/tour/en.json for English content:

{
  "id": "barcelona",
  "language": "en",
  "title": "Unlimited Barcelona",
  "description": "Discover the rich history and hidden gems of Barcelona's Gothic Quarter on this self-guided walking tour.",
  "totalDuration": "45 mins",
  "totalStops": 5,
  "image": "https://images.unsplash.com/photo-barcelona...",
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Welcome to Barcelona",
      "duration": "3 min audio",
      "image": "https://images.unsplash.com/photo-welcome...",
      "audioFile": "https://your-storage.com/audio/01-welcome.mp3"
    }
  ]
}

Language file fields

FieldRequiredDescription
idYesMust match metadata.json
languageYesISO language code ("en", "es", "de", etc.)
titleYesTour title (displayed on start screen)
descriptionYesTour description (1-2 engaging sentences)
totalDurationYesHuman-readable duration ("45 mins")
totalStopsYesNumber of stops in the tour
imageNoTour cover image (overrides metadata)
stopsYesArray of stop objects

The language field determines the language, not the filename. You could name your file english.json and it would still work if "language": "en" is set. (But please don't—use en.json for sanity.)

Stop objects

Each item in the stops array represents one tour stop:

{
  "id": "1",
  "type": "audio",
  "title": "Welcome to Barcelona",
  "duration": "3 min audio",
  "image": "https://images.unsplash.com/photo-xxx",
  "audioFile": "https://your-storage.com/audio/01-welcome.mp3",
  "transcription": "Welcome to Barcelona! Today we'll explore..."
}

Stop fields

FieldRequiredDescription
idYesUnique within the tour ("1", "2", etc.)
typeYesStop type (see Stop types)
titleYesStop title
durationYesHuman-readable duration ("3 min audio")
imageYesStop image URL
audioFileFor audioAudio file URL (MP3 or M4A)
transcriptionNoText transcription of the audio
locationNoGPS coordinates for the map pin: { "lat": 51.5007, "lng": -0.1246 } — audio stops only
mapMarkerIconNoCustom marker image URL for this stop only (overrides the tour-level mapMarkerIcon and any mapMarker mode)

Stop IDs must be unique within a tour and consistent across all language files. If English stop "3" is about the cathedral, Spanish stop "3" must also be about the cathedral.

Complete example: London tour

Let's build a real tour from scratch.

Step 1: Create metadata.json

{
  "id": "london-highlights",
  "offlineMode": "optional",
  "themeId": "default-light",
  "transcriptAvailable": true,
  "collectFeedback": true,
  "image": "https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?w=1000",
  "mapView": true,
  "mapProvider": "openstreetmap",
  "mapRoute": true
}

Step 2: Create en.json

{
  "id": "london-highlights",
  "language": "en",
  "title": "London Highlights",
  "description": "Discover London's most iconic landmarks on this walking tour through Westminster and the South Bank.",
  "totalDuration": "60 mins",
  "totalStops": 4,
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Big Ben & Parliament",
      "duration": "8 min audio",
      "image": "https://images.unsplash.com/photo-1529655683826-aba9b3e77383?w=800",
      "audioFile": "https://your-storage.com/london/01-big-ben.mp3",
      "transcription": "Welcome to Westminster! Standing before you is the Elizabeth Tower, home to Big Ben...",
      "location": { "lat": 51.5007, "lng": -0.1246 }
    },
    {
      "id": "2",
      "type": "audio",
      "title": "Westminster Abbey",
      "duration": "10 min audio",
      "image": "https://images.unsplash.com/photo-1520986606214-8b456906c813?w=800",
      "audioFile": "https://your-storage.com/london/02-abbey.mp3",
      "location": { "lat": 51.4994, "lng": -0.1273 }
    },
    {
      "id": "3",
      "type": "audio",
      "title": "London Eye",
      "duration": "6 min audio",
      "image": "https://images.unsplash.com/photo-1567157577867-05ccb1388e66?w=800",
      "audioFile": "https://your-storage.com/london/03-eye.mp3",
      "location": { "lat": 51.5033, "lng": -0.1195 }
    },
    {
      "id": "4",
      "type": "audio",
      "title": "Tower Bridge",
      "duration": "7 min audio",
      "image": "https://images.unsplash.com/photo-1461949814715-0e9ad3b9e75a?w=800",
      "audioFile": "https://your-storage.com/london/04-bridge.mp3",
      "location": { "lat": 51.5055, "lng": -0.0754 }
    }
  ]
}

Step 3: Save to src/data/tour/

Place your files in the src/data/tour/ directory:

src/data/tour/
├── metadata.json
└── en.json

Step 4: Test

bun run dev

Open http://localhost:3000 and your London tour should appear!

Adding another language

To add Spanish, create src/data/tour/es.json:

{
  "id": "london-highlights",
  "language": "es",
  "title": "Lo Mejor de Londres",
  "description": "Descubre los monumentos más icónicos de Londres en este recorrido a pie por Westminster y South Bank.",
  "totalDuration": "60 mins",
  "totalStops": 4,
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Big Ben y el Parlamento",
      "duration": "8 min audio",
      "image": "https://images.unsplash.com/photo-1529655683826-aba9b3e77383?w=800",
      "audioFile": "https://your-storage.com/london/es/01-big-ben.mp3"
    }
  ]
}

Notice the audio file points to a Spanish version. You need separate audio recordings for each language (unless you want all languages to hear the same audio, which... don't do that).