Campaign app layout
Configure you app's navigation, pages, access, and styling.
The app layout defines navigation and page presentation for visitors and authenticated users of your app. The layout is configured through menu items, app pages, and styling options. The app's content is configured separately in Campaign content.
Menu items
GameBus lets you configure navigation through the app using its side menu. GameBus Core provides the following menu item types.
| Type | Purpose |
|---|---|
Single item | Open an app page or configured route. |
List of items | Generate menu entries from an input collection. |
Heading | Display a section heading without a link. |
Account | Display the authenticated user's account dropdown. |
Custom embed | Display an external iframe inside the menu. |
Each item has a slot (top, center, or bottom) and an optional order. Items are sorted by slot, then by order. Items without an order appear last in their slot.
Depending on its type, an item can also have a translatable title and subtitle, an icon, an associated app page—that is opened when the item is clicked—and optional configuration parameters.
Who sees a menu item
Menu item availability depends on waves and, optionally, groups:
- Waves. An item must be linked to at least one active wave. A wave is active when its start is unset or in the past and its end is unset or in the future.
- Groups. An item without group links is unrestricted by group. Otherwise, the user needs a
Participant-membership in at least one linked group. Other membership types, includingGhost-memberships, do not grant access.
Users see all menu items available through these wave and group rules. For example, a Team progress menu item linked to Team A and the October wave is available to Team A's participants while that wave is active.
Unfamiliar with groups or waves?
Mission availability depends on groups, memberships, and waves. See Campaign for an explanation of these concepts.
Generate a list of menu items
The list of items-menu item is a somewhat special type.
It creates one menu entry for each value selected by its iterable path. The data comes from linked input collections, which contain input requests. Each request has a key and an endpoint.
The iterable is a plain path. It supports object properties, array indexes such as [3], and array expansion with [*]. For example: $participantMissions.missions[*].
Each selected value is available as both row and item. Use expressions such as $row.name, $row.description, or $row.slug in menu fields and route parameters through configuration.params.
This example creates one menu entry for each active mission returned by /api/me/missions:
inputCollections:
- key: participantMissions
inputRequests:
- key: missions
endpoint: /api/me/missions
doFailOnError: true
doFailOnEmpty: false
appPages:
- type: showMission
slug: /missions/[missionSlug]
requiresAuthentication: true
isGloballyAvailable: false
layout: HEADER
menuItems:
- type: LIST_OF_ITEMS
appPageSlug: /missions/[missionSlug]
iterable: participantMissions.missions
slot: CENTER
order: 1
title:
default: $row.name
subtitle:
default: $row.description
hideWhenAuthenticated: false
configuration:
params:
missionSlug: $row.slug
inputCollectionKeys:
- participantMissionsCustom menu items
A Custom embed-menu item displays its embed URL in an iframe inside the side menu. It communicates with the app through iframe messages. See Custom menu items for the protocol and implementation details.
App pages
An app page defines what appears at a route and who can access it.
| Attribute | Purpose |
|---|---|
Type | The page type, options are listed below. |
Slug | The route, such as /my-missions. Must start with / and may contain required parameters such as [groupSlug] or optional parameters such as [[optionalParameter]]. This allows you to define dynamic routes with variable path segments, such as /missions/[missionSlug] to display the details of a single Mission. |
Requires authentication | Whether users must sign in. Defaults to true. |
Globally available | Whether any authenticated user can access the page without an available menu item. Defaults to false. |
Layout | Header retains the standard app header; Fullscreen omits it. |
Configuration | Page-specific JSON settings, including optional fallback route parameters. |
Where a page type accepts fallback route parameters, values captured from the slug take precedence over matching values in configuration.params.
Who can access a page
Page access depends on authentication and global availability:
| Requires authentication | Globally available | Access requirement |
|---|---|---|
| No | Either | Publicly accessible; no menu item is needed. |
| Yes | Yes | The user must be signed in; no menu item is needed. |
| Yes | No | The user must be signed in and have at least one available menu item linked to the page. |
For pages that require menu access, the menu item's wave and group restrictions also apply to direct URLs. When several menu items link to a page, access through any one qualifying item is enough.
Page types may apply additional checks, such as whether the requested group belongs to the current user.
Page types
GameBus Core provides the following page types. The routes below are defaults; use the page's slug to set a different route.
| Page type | Default route | Purpose |
|---|---|---|
Client information | / | Display client information. |
List my groups | /groups | List and search the user's groups. |
Show group | /groups/[groupSlug] | Display and manage a group. |
List my activities | /activities | List the user's activities. |
Create activity | /activities/create/[activityTemplateSlug] | Create an activity from a template. |
List activities across my groups | /groups/activities | List activities across all the user's groups. |
List activities in my group | /groups/[groupSlug]/activities | List activities for one of the user's groups. |
List my missions | /missions | List the user's missions. |
List mission tasks | /missions/tasks | List tasks from the user's missions. |
Show mission | /missions/[missionSlug] | Display one mission. |
Show milestone | /missions/[missionSlug]/[milestoneSlug] | Display one milestone. |
Group leaderboard for subscribed skills | /skills/groups/leaderboard | Show group results for the user's subscribed skills. |
Individual leaderboard for subscribed skills | /skills/groups/[groupSlug]/leaderboard | Show individual results for subscribed skills in a group. |
Group leaderboard for a skill | /skills/[skillSlug]/groups/leaderboard | Show group results for one skill. |
Individual leaderboard for a skill | /skills/[skillSlug]/groups/[groupSlug]/leaderboard | Show individual results for one skill within a group. |
External page | /external | Display an external page in an iframe. |
Unfamiliar concepts?
Some page types refer to concepts introduced later, see Campaign content.
Custom pages
An External page-page displays an external URL at its configured app route. It follows the same access rules as built-in pages. These pages need some additional configuration:
| Attribute | Purpose |
|---|---|
| Embed URL | The iframe URL. Required for external pages and ignored by built-in pages. |
| Input collections | Optional collections resolved for the page. External pages also receive the results in their iframe. |
For example, a Team progress menu item can open an external team dashboard. Input collections supply its data, while iframe messages let it communicate with Core.
See Custom pages for the protocol and implementation details.
Styling
Set CSS variables under :root for the light theme and .dark for dark mode. Settings merge recursively with the application defaults, so you only need to supply the values you want to change.
{
":root": {
"--primary": "#0057b8",
"--primary-foreground": "#ffffff",
"--background": "#ffffff",
"--foreground": "#172033",
"--radius": "0.75rem"
},
".dark": {
"--primary": "#78b7ff",
"--primary-foreground": "#071525",
"--background": "#071525",
"--foreground": "#f4f7fb"
}
}Theme variables
For each color pair, choose a foreground color that provides enough contrast with its background.
| Variables | Control |
|---|---|
--radius | Base corner radius, used to derive other radius sizes. |
--background, --foreground | Main app background and text. |
--primary, --primary-foreground | Primary actions and prominent brand elements. |
--secondary, --secondary-foreground | Secondary actions and surfaces. |
--muted, --muted-foreground | Subdued backgrounds and secondary text. |
--accent, --accent-foreground | Highlighted or interactive surfaces and their content. |
--border | Borders and separators. |
--input | Input borders and background styling. |
--ring | Focus rings and control outlines. |
--destructive | Errors, destructive actions, and danger states. |
--sidebar, --sidebar-foreground | Sidebar background and text. |
--sidebar-primary, --sidebar-primary-foreground | Primary sidebar actions or selections and their content. |
--sidebar-accent, --sidebar-accent-foreground | Hovered or highlighted sidebar items and their content. |
--sidebar-border | Sidebar borders. |
--sidebar-ring | Sidebar focus rings. |
--card, --card-foreground | Card backgrounds and text. |
--popover, --popover-foreground | Menu, dialog, tooltip, and popover backgrounds and text. |
--chart-1 through --chart-5 | Chart and data-visualization colors. |
Design your theme visually
Use tweakcn.com to explore and customize themes in a visual editor. It also includes several ready-made themes you can use as a starting point.
Browser theme colors
The app publishes the --background values from :root and .dark as separate <meta name="theme-color"> tags. Supporting browsers can use these light and dark colors for their interface.
Progressive web app (PWA)
The app can be installed as a progressive web app (PWA). Use a web app manifest to define its name, icons, launch behavior, and installation appearance.
Manifest settings
| Setting | Purpose |
|---|---|
| Name | Full name shown during installation and in app listings. |
| Short name | Name used where space is limited. |
| Description | Brief description of the app. |
| Language | Default language. |
| Text direction | Left to right (ltr), right to left (rtl), or automatic (auto). |
| Categories | Categories such as productivity, education, or health. |
| Start URL | URL opened when the installed app launches. |
| Scope | URLs treated as part of the installed app. |
| Theme color | Suggested color for the browser or operating-system interface. |
| Background color | Initial background or splash-screen color while the app loads. |
| Screenshots | Images shown in supported installation interfaces. |
| Shortcuts | Context-menu links to frequently used routes. |
Manifest colors are configured separately from CSS. Keep them aligned with the app's theme, but note that each manifest color has one static value rather than separate light and dark values.
Support for installation features varies by browser and operating system.
Display mode
The display setting controls how the installed app appears:
| Mode | Behavior |
|---|---|
| Browser | Open in a regular browser tab. |
| Minimal UI | Show a reduced set of browser navigation controls. |
| Standalone | Open in an app-like window without the usual browser interface. |
| Fullscreen | Use the entire available display. |
Icons
Provide icons as an array of definitions. Each icon supports:
| Attribute | Purpose |
|---|---|
| Source | Icon URL. |
| Sizes | Dimensions such as 192x192, 512x512, or any. |
| Type | MIME type, such as image/png. |
| Purpose | General use (any), safe cropping (maskable), or single-color rendering (monochrome). |
Include a maskable icon so supporting platforms can crop it to their required shape.
Example manifest
{
"name": "Example Missions",
"short_name": "Missions",
"description": "Achieve your missions.",
"lang": "en",
"scope": "/",
"start_url": "/",
"display": "standalone",
"orientation": "any",
"background_color": "#ffffff",
"theme_color": "#0057b8",
"icons": [
{
"src": "/core-logo.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "/core-logo-maskable.png",
"sizes": "1024x1024",
"type": "image/png",
"purpose": "maskable"
}
]
}