Docs/Branding/Branding

Branding

Customize how your tour looks and feels

Built-in branding and theming system gives you complete control over the visual appearance. Change colors, fonts, and styling to match your brand or create a unique experience.

Default theme

There is one main theme with two variants:

Default Light

Clean, distraction-free light aesthetic with high legibility and soft gray accents.

Default Dark

Refined dark aesthetic with grayscale palette and sans-serif typography.

Using a theme

Set the theme in your metadata.json:

{
  "id": "barcelona",
  "themeId": "default-light"
}

Or "default-dark" for the dark theme.

That's it! The entire app adopts the theme—cards, buttons, player, sheets, everything.

Tour layout options

Themes control colors, fonts, and visual styling — but several layout and UI visibility options are configured per-tour in metadata.json, not in the theme file.

PropertyTypeDescription
showStopImageboolean | "thumbnail"Stop card layout: true = full image card, "thumbnail" = compact row with small thumbnail, false = text-only list
showStopDurationbooleanShow/hide the duration badge on stop cards
showStopNumberbooleanShow/hide the numbered circle indicator on stop cards
showProgressBarbooleanShow/hide the playback progress bar
showLanguageLabelbooleanShow/hide the language name next to the flag in the language selector
fullscreenPlayerbooleanEnable the fullscreen overlay player (slides up over the stop list)
backgroundColorstringBackground color of the TourStart screen and its status bar area

These work alongside your theme — you can define card colors in the theme while controlling whether cards show images or render as a plain list via showStopImage in metadata.

Status bar background

The narrow safe-area region at the very top of the screen (behind the iOS clock, battery, and signal icons) is automatically filled. The color depends on which screen is active:

ScreenColor source
TourStartbackgroundColor in metadata.json
TourDetailheader.backgroundColor from the active theme

Add backgroundColor to your metadata.json to control the TourStart status bar:

{
  "backgroundColor": "#1A2634"
}

Pick a color that matches the top edge of your cover image — this makes the status bar feel like a natural extension of the photo. If omitted, the theme's header.backgroundColor is used on both screens.

Both values also update the <meta name="theme-color"> tag, which tints the browser chrome on iOS and influences status bar icon contrast (light/dark).

What you can customize

Themes control virtually every visual aspect:

AreaWhat You Control
ColorsBackgrounds, text, borders, accents
TypographyFont families, sizes, weights
CardsBackground, borders, shadows, corner radius
ButtonsPrimary, secondary, and download button styles
Mini PlayerProgress bar, controls, transcription text
Bottom SheetsBackground, handle color, title styling
Step IndicatorsActive, inactive, and completed states
BrandingCustom logo on start screen

You can tweak individual properties or create an entirely new theme from scratch. It's up to you how far you want to go.

Theme structure

Themes are TypeScript objects with a specific structure. Here's a simplified view:

const myTheme = {
  id: 'my-theme',
  name: 'My Theme',
 
  header: { /* colors, progress bar */ },
  mainContent: { /* background */ },
  cards: { /* colors, typography, shadows */ },
  buttons: { /* primary, secondary styles */ },
  miniPlayer: { /* player controls, progress */ },
  sheets: { /* bottom sheet styles */ },
  typography: { /* font families */ },
  colors: { /* semantic color palette */ },
  // ...and more
};

Each section controls a specific part of the UI. We'll cover all of them in Theme Reference.

Quick customization

Want to just change the accent color? You don't need a full custom theme.

The easiest approach is to copy an existing theme and modify it:

Copy a theme file

cp src/theme/themes/default-light.ts src/theme/themes/my-brand.ts

Change the accent color

Find all instances of the primary color (like #6366F1) and replace with your brand color.

Register the theme

Add to src/theme/themes/index.ts:

import { myBrandTheme } from './my-brand';
 
export const themes = {
  'default-light': defaultLightTheme,
  'default-dark': defaultDarkTheme,
  'my-brand': myBrandTheme,
};

Use it

Set "themeId": "my-brand" in your metadata.json.

Per-language themes

You can use different themes for different languages by overriding in the language file:

// es.json
{
  "id": "barcelona",
  "language": "es",
  "themeId": "warm-theme"
}

Spanish visitors would see warm-theme while others see whatever's in metadata.json.

Custom fonts

Themes support custom fonts from Google Fonts (or self-hosted):

typography: {
  fontFamily: {
    sans: ['Roboto', 'system-ui', 'sans-serif'],
    heading: ['Playfair Display', 'serif'],
    numbers: ['JetBrains Mono', 'monospace'],
  },
}

Remember to add the font to index.html:

<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&display=swap" rel="stylesheet">

Branding: Custom logo

Display your logo on the tour start screen:

branding: {
  logoUrl: 'https://your-domain.com/logo.svg',
  showLogoBorder: true,
  logoSize: 'fit',  // or 'original'
}
OptionEffect
showLogoBorder: trueLogo in a rounded rectangle with shadow
showLogoBorder: falseLogo displayed directly, no container
logoSize: 'fit'Constrained to 48x48px
logoSize: 'original'Natural image dimensions

What you can't customize

Some things are intentionally fixed:

  • Component layout - Where elements are positioned
  • Animation types - Transitions use spring physics
  • Icon shapes - Only colors are themeable
  • Spacing between elements - Some spacing is hardcoded

These constraints ensure the app remains usable and visually consistent regardless of theme choices.