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.

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.