39948-vm/documentation/global-ui-controls.md
2026-07-03 16:11:24 +02:00

8.7 KiB

Global UI Controls

Overview

Global UI controls are system-owned presentation buttons for fullscreen, global sound mute, and offline mode. They are not regular canvas elements and are not stored in tour_pages.ui_schema_json.elements.

They behave like runtime chrome:

  • button dimensions use canvas-relative percentages
  • button positions are relative to the visible canvas using xPercent/yPercent
  • constructor edit mode renders controls even when hidden
  • controls can be disabled or hidden, but cannot be deleted
  • each control can use custom default and active icons from Assets

Implementation Files

Backend:

  • backend/src/db/models/global_ui_control_defaults.js
  • backend/src/db/models/project_ui_control_settings.js
  • backend/src/db/api/global_ui_control_defaults.ts
  • backend/src/db/api/project_ui_control_settings.ts
  • backend/src/routes/global_ui_control_defaults.ts
  • backend/src/routes/project_ui_control_settings.ts
  • backend/src/services/global_ui_control_defaults.ts
  • backend/src/services/project_ui_control_settings.ts

Frontend:

  • frontend/src/types/uiControls.ts
  • frontend/src/components/UiControls/UiControlsSettingsForm.tsx
  • frontend/src/components/Runtime/RuntimeControls.tsx
  • frontend/src/components/Constructor/ElementEditorPanel.tsx
  • frontend/src/stores/global_ui_control_defaults/globalUiControlDefaultsSlice.ts
  • frontend/src/stores/project_ui_control_settings/projectUiControlSettingsSlice.ts
  • frontend/src/components/RuntimePresentation.tsx
  • frontend/src/pages/constructor.tsx
  • frontend/src/pages/global-ui-control-defaults.tsx
  • frontend/src/pages/global-ui-control-defaults/[controlType].tsx
  • frontend/src/pages/project-ui-control-settings.tsx

Cascade

Settings resolve field-by-field:

global_ui_control_defaults
  -> project_ui_control_settings (project + environment)
  -> tour_pages.global_ui_controls_settings_json

Missing fields inherit from the previous cascade level: page settings override project settings, project settings override global defaults, and frontend hardcoded defaults are only a safety fallback.

Data Shape

Each control (fullscreen, sound, offline) supports:

Field Purpose
enabled Disable action while keeping the control selectable in edit mode
hidden Hide in runtime/preview; still render as ghost in constructor edit mode
xPercent, yPercent Canvas-relative position
anchor Which button point is placed at the coordinate
buttonSizePercent, iconSizePercent, borderRadiusPercent Canvas-width-relative dimensions
defaultIconUrl, activeIconUrl Optional custom asset URL/storage key per state
defaultBackgroundColor, activeBackgroundColor Button background color per state
defaultBorderColor, activeBorderColor Button border color per state
hoverBackgroundColor, color Shared hover background and icon color
opacity, boxShadow, zIndex, order Presentation and initial ordering

Active state means downloaded/offline for the offline button, muted for the sound button, and fullscreen for the fullscreen button.

When runtime is embedded in an iframe, the fullscreen control first tries the browser Fullscreen API for the presentation document, then tries to fullscreen the embedding iframe when same-origin access is available. For cross-origin wrappers it posts tour-builder:request-fullscreen to window.parent; exit attempts post tour-builder:exit-fullscreen.

<iframe id="tour-frame" src="https://example.com/p/project" allow="fullscreen" allowfullscreen></iframe>
<script>
  window.addEventListener('message', async (event) => {
    const frame = document.getElementById('tour-frame');

    if (event.data?.type === 'tour-builder:request-fullscreen') {
      await frame?.requestFullscreen?.();
    }

    if (event.data?.type === 'tour-builder:exit-fullscreen' && document.fullscreenElement) {
      await document.exitFullscreen();
    }
  });
</script>

Dimensions are stored as percentages of canvas width. buttonSizePercent and iconSizePercent resolve from the displayed canvas width. Vertical bounds use the canvas aspect ratio, so buttons remain fully inside the visible canvas for non-16:9 projects as well.

Default global values:

Control X Y Size Icon Radius Order
offline 89.5 6 2.6 1.35 0.42 1
fullscreen 92.75 6 2.6 1.35 0.42 2
sound 96 6 2.6 1.35 0.42 3

APIs

  • GET /api/global-ui-control-defaults
  • PUT /api/global-ui-control-defaults/:id
  • GET /api/project-ui-control-settings/project/:projectId/env/:environment
  • PUT /api/project-ui-control-settings/project/:projectId/env/:environment
  • DELETE /api/project-ui-control-settings/project/:projectId/env/:environment

Production project settings reads follow the same public/private access rules as runtime transition settings. Dev/stage and writes require JWT.

GET /api/global-ui-control-defaults is public-readable for runtime. Updates require JWT and UPDATE_PAGE_ELEMENTS; these settings are authored with the same permission family as element defaults. Project-level production reads are public only for public production presentations; private production presentations require JWT and presentation access.

Project override writes require UPDATE_PAGE_ELEMENTS. The project environment reset endpoint is implemented as DELETE because it removes the override row, but authorization treats it as an update operation: it also requires UPDATE_PAGE_ELEMENTS, not DELETE_PAGE_ELEMENTS.

Constructor Behavior

Constructor renders controls through RuntimeControls with editMode=true. Selecting a system control opens the element editor in system-control mode.

System controls:

  • can be dragged to update xPercent/yPercent
  • can be edited with coordinate inputs
  • can choose separate default and active custom icons
  • can edit default/active background colors and border colors
  • can edit hidden/disabled state, order, z-index, opacity, shadow, size, radius, and anchor
  • cannot be removed, copied, or pasted

Constructor system-control opacity is edited as a clamped percentage from 0 to 100 and converted to the stored runtime opacity number from 0 to 1.

Constructor edit mode blocks runtime actions. Clicking or dragging system controls does not toggle fullscreen, sound, or offline mode. Hidden controls are rendered as ghost controls so authors can reselect and unhide them.

Admin Editing UI

Global defaults are listed at /global-ui-control-defaults and edited per control:

  • /global-ui-control-defaults/offline
  • /global-ui-control-defaults/fullscreen
  • /global-ui-control-defaults/sound

Project-level overrides are edited from /project-ui-control-settings?projectId=....

The per-control global pages and project page use UiControlsSettingsForm, a typed editor with the same tab model used by element defaults:

  • General Settings: enabled/hidden state, canvas-relative position, anchor, order, and default/active icon URLs
  • CSS Styles: button/icon sizing, radius, icon color, background colors, and border colors
  • Effects: opacity, z-index, and box shadow

Opacity inputs in the constructor/editor UI are percentage-based for authors; stored settings_json.opacity remains a numeric CSS opacity value.

Project settings can be cleared with Use Global Defaults, which deletes the project/environment override so the project inherits global defaults again.

Publishing

project_ui_control_settings is environment-aware and is copied by the publish workflow:

dev -> stage -> production

Page-level overrides live on tour_pages and are copied with page records. Project clone copies project UI-control settings for each environment, and page duplication copies page-level global_ui_controls_settings_json.

Migrations

  • 20260628000001-create-ui-control-settings.js creates the two DB models, adds tour_pages.global_ui_controls_settings_json, creates the project/env unique index, and seeds the initial global defaults.
  • 20260628000005-snapshot-existing-project-ui-controls.js snapshots project-level settings for existing projects that do not already have project UI-control overrides.

Existing Projects

Migration 20260628000005-snapshot-existing-project-ui-controls.js snapshots the previous runtime chrome layout into project-level settings for existing projects in dev, stage, and production when no project UI-control override already exists. The snapshot keeps the old top-right grouped placement offsets and previous runtime z-index, but stores dimensions with the same canvas-relative defaults used by new projects (2.6% button size, 1.35% icon size, 0.42% radius).