Skip to content

Build License PRs Welcome


The SmartCompanion Audioguide App is a free and open-source Progressive Web App (PWA) that delivers interactive audioguide experiences for museums and cultural institutions. It runs seamlessly in any modern mobile browser — no installation required.

The app is fully customizable, allowing you to adapt content, colors, text, and images to fit your institution's needs. It also includes offline functionality powered by a service worker, ensuring smooth use even without an internet connection.

Table of Contents

Features

  • 🎧 Interactive Audioguide — station-based audio playback for museum tours
  • 📱 Progressive Web App — works in any modern browser, no app store needed
  • 🌐 Multilingual — built-in i18n support for multiple languages
  • 📶 Offline Support — optional service worker caching for use without internet
  • 🎨 Fully Customizable — adapt colors, content, images, and branding
  • 🌗 Light & Dark Mode — automatically follows the user's system preference
  • ⚡ Lightweight — built with Stencil.js and Ionic for fast performance
  • 🆓 Open Source — BSD 2-Clause license

Examples

Castle Tratzberg Museum Landeck Example App (Animals) Example App (Leon)
Castle Tratzberg App Museum Landeck App Example App (Animals) Example App (Leon)

Browser Support

Visitor devices need Chrome/Edge 110+, Safari 16.4+ (iOS 16.4+), or Firefox 110+. The station list and image slideshow are built on swiper 14, which sets this floor. If you need to support older devices, stay on a release before @smartcompanion/ui 1.0.0.

Getting Started

Fork and clone the repo, then:

npm install        # Install dependencies
npm start          # Dev server with hot reload at http://localhost:3333
npm run build      # Production build → www/
npm test           # Build, then run the end-to-end suite

See CONTRIBUTING.md for the rest of the scripts, how the offline test mode works, and how to work on the customization template.

Deployment Options

Service Description
SmartCompanion We offer a hosting service including a content management system, continuous updates, security fixes, custom domains, support and further services.
GitHub Pages GitHub Pages offers a free option for open source repositories and supports custom domains. The example apps are hosted on GitHub Pages.
Netlify Netlify offers a free option and supports custom domains also for private GitHub repositories.

Customization

Customization is handled via engraft, which is included as the @smartcompanion/engraft devDependency. After npm install, apply a values file with:

npx engraft apply --template engraft.template.yml --values customization/leon/engraft.variables.yml

A ready-to-use example lives in customization/leon/ — copy that directory to start your own variant. All configurable variables defined in engraft.template.yml are listed below:

Variable Description Default
title_short Short app title Animals
title App title Animals Audioguide
description App description A sample audioguide app for animals
lang Language code for manifest.json en
data_url URL to the audioguide data JSON, or a repo-relative path to bundle it into the build Sample JSON
offline_support Enable offline support (true/false) false
messaging_support Enable postMessage listener for iframe embedding (true/false) true
background_color App background color #faefdc
primary_color Primary brand color #8fc0bd
primary_color_contrast Text color on primary color #ffffff
logo Path to app logo image src/assets/logo.png
logo_dark Path to app logo image (dark mode) src/assets/logo-dark.png
icon_source Repo-relative path to the image the whole PWA icon set is generated from src/icon.png

Bundling the data with the app

data_url normally points at data hosted somewhere else. Point it at a path inside this repo instead and the data ships inside the build, so the deployed app needs nothing but its own static host:

data_url: customization/leon/data/data.json

The folder holding that data.json is copied into the build as its top-level data/ folder, wherever it happens to sit in the repo, and the app addresses it as data/data.json. Assets inside data.json are addressed the same way — by the served path, not the repo path:

{ "id": "i11", "filename": "i11.png", "externalUrl": "data/assets/i11.png" }

The leon variant works this way, with its data in customization/leon/data/. To bundle your own, put data.json next to an assets/ folder anywhere in the repo, write every externalUrl as data/assets/<filename>, and point data_url at the data.json. Those URLs are relative to the page rather than rooted at /, so this keeps working when the app is served from a subpath such as https://<user>.github.io/<repo>/.

With offline_support: "true" the bundled data.json and any .png beside it are also swept into the service worker precache. That makes the install larger but guarantees they are present offline; audio is still fetched by the offline load service, which is what reports download progress.

Icons

An app names one image — icon_source — and the whole icon set is generated from it at build time by scripts/generate-icons.mjs, into a gitignored .pwa-assets/ folder the build copies in as assets/icon/. Nothing derived is committed, so a variant carries one file rather than three that have to be kept in step:

Generated file Purpose
pwa-64x64.png, pwa-192x192.png, pwa-512x512.png Manifest icons, drawn whole
maskable-icon-512x512.png Manifest maskable icon — the artwork centered on a solid ground, filling 70% of the canvas so no mask shape crops it
apple-touch-icon-180x180.png iOS home screen. Full-bleed and opaque, because iOS applies its own mask and composites transparency onto black
favicon.ico 16, 32 and 48px frames

An SVG source is preferred — it is rasterized at full density for every size — but any format works. Use a square canvas: the artwork is never cropped, so whatever ground it sits on is what the icons show. icon_source is a repo-relative path, so a variant's image can live anywhere — the default is src/icon.png, while leon keeps its own beside the rest of its files. It sits next to src/assets/ rather than inside it because everything under src/assets/ is published, and the source itself is only ever read at build time.

icon_background fills the margin around the padded maskable and Apple icons. Left unset it is sampled from the source's own corners, which is what a full-bleed image wants; a source whose corners disagree (a photograph, a gradient) or are transparent falls back to background_color. The build logs which of the three applied:

icons: generated from src/icon.png on #8dbeba (sampled from the source's corners)

A maskable icon and a plain one are different images, and this is why they are generated separately rather than declared as the same file twice: the maskable one is cropped to the platform's shape within a safe zone, so an icon that fills its canvas would lose its edges.

Colors

An app names two colors — background_color and primary_color — and the rest of the palette is computed from them at build time by src/global/_color-helpers.scss. Surfaces step off the background (darker in light mode, lighter in dark mode), the dark palette is the light background at low lightness, and shades and tints match the Ionic Color Creator exactly.

Every derived color can still be set explicitly. These variables have no default — name one in your values file and it wins, leave it out and it is derived:

Variable Description Derived from
background_color_dark App background color (dark mode) background_color, same hue at 11% lightness
card_background_color Card background color background_color, one step off it
card_background_color_dark Card background color (dark mode) background_color_dark, one step off it
menu_border_color Menu item border color background_color, two steps off it
menu_border_color_dark Menu item border color (dark mode) background_color_dark, two steps off it
station_icon_progress_color Station icon progress color primary_color, pushed away from the background
station_icon_progress_color_dark Station icon progress color (dark mode) primary_color, pushed away from the dark background
light_color Ionic's light color background_color
light_color_dark Ionic's light color (dark mode) background_color_dark
icon_background Color behind the padded artwork on the maskable and Apple icons icon_source, sampled from its corners

primary_color_contrast is the one color that is not derived: the same rule Ionic uses resolves the default primary to black text, so which text color sits on a brand color stays a design decision.

The theme-color meta tags in index.html are the light background at build time and are kept on the active background color at runtime by src/global/app.ts, so they follow both the system palette and a palette forced with UPDATE_DARK_MODE.

Versioning

Releases are versioned as YYYY.MINOR.MICRO — the CalVer scheme PyCharm and Unity use. This is a deployed application, not a library, so a version says when a build is from rather than what it promises about an API.

The year is the only calendar claim; MINOR and MICRO are plain sequences within it:

2026.1.0 → 2026.1.1 → 2026.2.0 → … → 2027.0.0

Because the scheme is CalVer rather than semver, the bump levels mean something different from usual:

Bump Meaning
major a new calendar year — used once a year, nothing else
minor new features, and anything that breaks a fork's customization
patch fixes, dependency bumps, internal changes

Breaking changes are therefore described in the changelog rather than signalled by the version. That is deliberate: if you maintain a customized fork, "the engraft variable x was renamed to y" is something you can act on, whereas an incremented number is not.

The version is stamped into each build as a version meta tag, which is the quickest way to tell which build a device is actually running:

document.querySelector('meta[name="version"]').content; // "2026.1.0"

Local builds report dev.

How a release is cut, and how to redeploy an earlier tag, is covered in CONTRIBUTING.md.

Contributing

Contributions are welcome. See CONTRIBUTING.md for the local setup, the two test modes, and how releases work. Everyone taking part is expected to follow the Code of Conduct. Security issues go through SECURITY.md, not the issue tracker.

License

The SmartCompanion Audioguide App is licensed under the terms of the BSD 2-Clause license. Check the LICENSE file for further details.

Links

Releases

Used by

Contributors

Languages