UI Themes
UI Themes control the visual appearance of GEM user interfaces. Each theme includes CSS styles, icons, and background images for creating consistent, branded experiences across all UIs.
Overview
The UI Themes page provides complete theme management:
- CSS Editor: Customize styles and colors
- Background Management: Upload and map background images
- Icon Library: Manage icon sets
- Theme Assignment: Apply themes to specific UIs
- Preview: Test themes before deployment
Theme Selector
Top toolbar provides theme selection and management:
Theme Selector
- Dropdown of all themes
- Select to edit
- Shows theme name
Actions:
- Copy - Duplicate existing theme
- New - Create blank theme
- Export - Export theme files to filesystem
UI Selector
- Choose UI to apply theme to
- Shows current theme for each UI
Set Button
- Apply selected theme to selected UI
- Saves theme attribute for UI
Preview Button
- Open theme in live preview window
- Test in real environment
Theme Tabs
Themes have four tabs: Styles, Layout, Backgrounds, and Icons.
1. Styles Tab
CSS editor for theme styling. Every theme has two stylesheets, selected with the file toggle above the editor:
- Custom CSS (
custom.css) — site-specific overrides, opened by default. It loads after the base stylesheet, so rules here win at equal specificity. This file is yours: GEM updates never modify it. - Base CSS (
style.css) — the theme's base stylesheet. For official themes (prodigy,ember,carbon, andappeal) the base is release-managed: GEM updates refresh it automatically, the editor shows it read-only, and the server rejects writes to it — put site overrides in Custom CSS instead. For user-created themes the base is fully editable.
Features:
- Syntax-highlighted CSS editor
- Auto-complete (basic)
- Search and replace (
Ctrl+F/Ctrl+H) - Code formatting (
Ctrl+Shift+B) - Status bar showing cursor position (line, column)
- Unsaved changes warning when navigating away or switching between Custom and Base
- Save button to apply changes
The first boot after updating runs a one-shot migration for official themes: site edits found in style.css are extracted into custom.css (rules identical to official release CSS stay in the base), and a verbatim backup of the pre-split stylesheet is kept in the theme as style.pre-migration.css. When edits can't be confidently separated, the entire previous stylesheet is carried into custom.css — it then overrides the base completely, so the rendered result is unchanged either way.
The migration is tracked per theme, so a theme that becomes official in a later release (Appeal, for one) gets its own split on the first boot after that release — your edits to its style.css are moved to custom.css before the release-managed base takes over. Until that split has run, GEM will not refresh that theme's base stylesheet.
CSS Variables:
Themes should define CSS variables for consistency:
:root {
/* Colors */
--primary-color: #277ad4;
--secondary-color: #1e5ba8;
--background-color: #ffffff;
--surface-color: #f9f9f9;
--text-primary: #1f2937;
--text-secondary: #6b7280;
--border-color: #e5e7eb;
/* Spacing */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
/* Typography */
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
--font-size-base: 16px;
--font-size-lg: 18px;
--font-size-xl: 24px;
/* Layout */
--border-radius: 8px;
--shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
Component Styles:
Style GEM components:
/* Zone Cards */
.zone-card {
background: var(--surface-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: var(--spacing-md);
}
.zone-card.on {
background: var(--primary-color);
color: white;
}
/* Buttons */
.btn-primary {
background: var(--primary-color);
color: white;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius);
}
/* Navigation */
.nav-control {
font-size: var(--font-size-base);
padding: var(--spacing-sm);
}
Saving:
- Click Save button after editing
- Changes apply immediately to preview window (if open)
- UIs reload automatically (if configured)
2. Layout Tab
Theme-wide Layout & Presentation defaults. These are stored on ui_theme.config and apply to every UI using this theme. Changes take effect on the next reload (or immediately in an open Preview window). Unlike Styles, they resolve from the theme row rather than a stylesheet — GEM re-queries the config on reload.
| Control | Config key | Options | Effect |
|---|---|---|---|
| Navigation | nav_layout | Top bar (classic) / Left rail + tab bar | rail shows a left icon rail in landscape and a bottom tab bar in portrait. In portrait the media bar is replaced by a compact media strip above the tab bar (now playing + zone off + volume, with a room chip on the second line doubling as the "control which room?" picker). Overridable per-UI with the UI's nav_layout attribute — the per-UI value wins over the theme default. |
| Rectangle buttons | rect_style | Default / State dot | state_dot renders rect controls as list-tile cards with a coloured state dot. |
| Scene chips | scene_chips | checkbox | When enabled, light/shade scene shortcuts render as state-disc chips. |
Click Save to write the options back to the theme. Only these keys are managed here — other config entries (background maps, etc.) are preserved.
GEM ships the rail/tab-bar geometry for every theme, but only Ember and Appeal (and copies of them) skin those surfaces. Selecting Left rail + tab bar on another theme renders the rail on a plain surface until you add rail styles to its CSS — the tab shows a warning in that case. See the theme contract for the variant-selection model.
3. Backgrounds Tab
Manage background images for pages and routes:
Background Selector
- Dropdown of uploaded background images
- Preview changes background display
Route Selector
- Dropdown of all routes/pages
- Special route
*= default background for all pages
Mapping Actions:
- Set - Map selected background to selected route
- Unset - Remove background mapping for route
Upload:
- File input to select image files
- Upload button to upload to theme
Preview:
- Large preview area shows selected background
- Scaled to fit display area
Background Mapping
Assign different backgrounds to different pages:
Example Configuration:
Route: * (default)
Background: neutral_texture.png
Route: /controls/lighting
Background: lighting_ambient.jpg
Route: /av
Background: theater_room.jpg
Route: /dashboard
Background: dashboard_bg.png
Result: Each page shows its configured background, or default if not mapped.
Uploading Backgrounds
- Click file input
- Select PNG or JPG file
- Click Upload
- Background added to theme
- Appears in background selector
Images uploaded here also appear in the wallpaper picker on Personal Settings whenever this theme is active — a user's choice is stored by filename, so it follows a theme switch as long as the new theme has an image of that name. For a set of wallpapers that should be offered regardless of the active theme (a client's own photographs, for instance), drop the files into static/backgrounds/ on the controller instead of into a theme.
A personal wallpaper replaces the theme's default (*) background but not a background mapped to a specific route — a page deliberately dressed by the theme keeps its artwork for everyone.
Image Requirements:
- Format: PNG or JPG
- Recommended Size: 1920x1080 or higher for large displays
- File Size: < 5MB for performance
- Aspect Ratio: Match target screen (16:9, 4:3, etc.)
4. Icons Tab
Manage theme icon library:
For official themes (prodigy, ember, carbon, and appeal), the shipped icons, backgrounds, and maps are release-managed like the base stylesheet: when a GEM update changes one of these files, the update replaces it automatically at the next boot. An asset you have edited or replaced in the theme editor is recognized as a site customization and is never overwritten — it keeps winning over the shipped version until you delete it. Assets you add under your own names are untouched by updates.
Browse Material Icons:
- Click Browse Material Icons to search and import icons from Google Fonts without leaving the admin
- Type to search by name, category, or tag (e.g.
light,lock,fan); results are ranked by relevance then popularity - Pick a style: Outlined (default), Filled, Rounded, Sharp, or Two Tone
- Click icons to multi-select, then Import Selected
- Choose a Format: SVG (default — scalable, recolorable via CSS) or PNG; for PNG pick a Size (64–256px)
- Save as — the selected icons list shows an editable filename per icon (defaulting to the material name). Rename any of them before importing to match GEM's expected icon names (e.g. import the material
lightbulbaslighting); leave blank to keep the material name. Names are normalized to lowercase[a-z0-9_] - Each icon is fetched server-side and saved to the theme's
/icons/directory as<name>.svgor<name>.png(e.g.lightbulb.svg); PNGs are rasterized with a transparent background at the chosen size - Requires the GEM server to have internet access; previews load from Google's CDN
Upload Icons:
- File input supports multiple files
- Click Upload Icons to upload
- Icons added to theme's
/icons/directory
Icon Grid:
- Visual display of all icons
- Checkbox for batch selection
- Icon filename shown below each icon
- Hover an icon and click the pencil (rename) button to rename it in place — enter the new base name (normalized to lowercase
[a-z0-9_], extension preserved). The rename moves both the asset row's path and the on-disk file while keeping the asset id, so anything referencing the icon by id is unaffected; UIs that reference it by filename must be repointed to the new name
Delete Selected:
- Select icons with checkboxes
- Click Delete Selected
- Confirm deletion
- Icons removed from theme
Icon Count:
- Display shows total icon count
- Helps track theme assets
Icon Requirements
- Format: PNG or SVG
- Size: 64x64 to 128x128 pixels recommended
- Style: Should match theme aesthetic (flat, skeuomorphic, etc.)
- Naming: Descriptive lowercase names (e.g.,
power.png,volume.svg) - Transparency: Use transparent backgrounds for flexibility
Standard Icons
Icons resolve theme-first across the UI (nav buttons, controls-grid tiles, room-picker glyphs): a file in the theme's /icons/ directory overrides GEM's built-in icon of the same name, and anything the theme doesn't ship falls back to the built-in set — so a theme only needs the icons it restyles. Common names to override:
Control Icons:
lighting,audio,video,shades,climate,securitycamera,pool,irrigation,lock,gate
Action Icons:
power,power_on,power_off,volume,volume_up,volume_down,muteup,down,left,right,select,back,homeplay,pause,stop,next,previous
State Icons:
on,off,open,closed,locked,unlockedonline,offline,warning,error,success
Misc Icons:
settings,user,notification,calendar,weather
Zone maps have moved
Floor-plan zone maps used to be authored here: you uploaded a plan image as a theme asset, then dragged one pin per zone onto it, per image, per theme.
They are now built automatically from site space geometry, because a zone's position on a plan is its physical location and does not belong to a theme. See Site Spaces for how it works and what to set up.
The map_coordinate zone attribute the old editor wrote is no longer read.
Existing values are left in place, inert — nothing needs cleaning up.
Theme Assignment
Assigning Theme to UI
- Select theme from dropdown
- Select UI from UI selector
- Click Set button
- Theme attribute set for UI:
theme = "theme_name" - UI immediately uses new theme (on next load)
Global vs. UI-Specific Themes
Global Theme:
- Set on UI with ID 0
- Default for all UIs
- Fallback when UI has no theme
UI-Specific Themes:
- Set on specific UI IDs
- Overrides global theme
- Allows per-location branding
Example:
Global (UI 0): professional_theme
Kitchen Panel (UI 2): bright_theme
Master Bedroom (UI 5): dark_theme
Result:
- Kitchen shows bright theme
- Master bedroom shows dark theme
- All other UIs show professional theme
Theme Preview
Click Preview button to test theme:
Preview Window
Opens new browser window with:
- Selected UI loaded
- Selected theme applied
- Live, functional interface
Use Preview For:
- Testing color changes
- Verifying icon compatibility
- Checking background images
- Ensuring readability
- Client demonstrations
After Preview:
- Close preview window when done
- Returns to theme editor
Creating a New Theme
To create a theme from scratch:
- Click New button
- Enter theme name (e.g.,
custom_dark) - Theme created with minimal starter CSS
- Edit CSS in Styles tab
- Upload icons and backgrounds
- Assign to UI and test
The name becomes a directory on disk (static/themes/{name}/), so it is normalized to lowercase
letters, digits and underscores — My Theme is stored as my_theme. A name that normalizes to
nothing is rejected. The same rule applies to every asset path inside a theme: a file must live
within its own theme directory, and one that would land outside it is refused on save, rename,
delete and export.
Copying a Theme
To create a variation of an existing theme:
- Select source theme
- Click Copy button
- Enter new theme name (e.g.,
carbon_blue) - Complete theme duplicated:
- All CSS copied (base
style.cssandcustom.css) - All icons copied
- All backgrounds copied
- All maps copied
- All CSS copied (base
- Edit as needed
A copy is an ordinary user theme even when the source is official — its base CSS becomes editable, and neither its CSS nor its icons/backgrounds/maps are refreshed by GEM updates. The style.pre-migration.css migration backup is not carried into copies.
Use Cases:
- Client-specific branding
- Seasonal variations
- Dark/light mode versions
- Testing major changes without affecting original
Exporting Themes
Click Export to write theme to filesystem:
Result:
- Theme files written to
static/themes/{theme_name}/ - Includes:
style.csscustom.css/icons/directory/backgrounds/directory/maps/directory, on themes that still carry legacy zone-map images. The files are exported as-is but nothing reads them any more; see Zone maps have moved.
Use Cases:
- Version control
- Backup before changes
- Sharing themes
- External editing
Built-In Themes
GEM ships four official themes — prodigy, ember, appeal, and carbon. These are the only themes with release-managed CSS and assets, and the only ones a new install starts with.
prodigy
- Default modern theme (official)
- Glassmorphic surfaces with translucency
- Cinematic background imagery
- On a phone the media bar carries the room's controls — volume and zone off — instead of transports, which stay one tap away on the source page
- Best for residential touchpanels and large displays
ember
- Brass-on-matte dark theme (official)
- Left icon rail navigation in landscape, bottom tab bar in portrait (
nav_layout: rail— see the theme contract) - Scene chips, matte chip surfaces, Instrument Sans typography, its own full icon set and background
- Best for dedicated wall panels and high-end residential installs
appeal
- iOS-style dark theme (official)
- Left icon rail navigation in landscape, bottom tab bar in portrait (
nav_layout: rail— see the theme contract) - System materials, vibrancy, SF-style typography; system blue accent throughout
- Pill-and-card components, hairline separators instead of shadows
- No background image — the page ground is a cool near-black gradient lit from two corners, the way iOS dark mode builds one. Set a wallpaper on the UI or in the Backgrounds tab and it wins over the gradient as usual
- On a phone the media bar carries the room's controls — volume and zone off — instead of transports, which stay one tap away on the source page
- On a phone the AV sidebar presents as a bottom sheet — grabber, sized to its own content, dimmed page behind it — rather than a full-height side panel
- Rooms playing a different source read system purple rather than the amber other themes use
- Best for mobile clients and minimalist installations
Appeal ships defaulting to the rail/tab-bar layout, but that default seeds new theme rows only. A site that already has an Appeal theme row keeps whatever navigation it is on — switch it in Layout & Presentation above if you want the tab bar.
The same is true of its background: Appeal is seeded with no background image, but that seeds new theme rows only. A site whose Appeal row still carries one keeps it — clear it in the Backgrounds tab to get the gradient ground.
carbon
- Neutral near-black dark theme (official) — prodigy's layout with a graphite skin in place of the navy glass
- Metallic gradients on the top bar and media nav, dark media bar
- High contrast, professional aesthetic
Customize: Copy built-in theme and modify rather than editing directly.
Older installs also created flat and legacy theme rows. Neither ships any files, so they showed in the theme picker with nothing behind them and rendered unstyled. New installs no longer create them. An existing site keeps its rows untouched — if one is in use, either leave it (nothing changes) or switch the UI to an official theme in the UI Selector above.
Theme files shipped with a release (e.g. new icons under static/themes/{name}/icons/) are backfilled into the database the first time GEM boots on the new version — so they behave like any other tracked asset (carried across copies, included in exports, served from disk after the next theme export). Existing rows are never overwritten, with one exception: the release-managed files of official themes — the base style.css, plus shipped icons, backgrounds, and maps you haven't edited — are refreshed from the release at boot. That's how theme fixes reach deployed sites. Assets a release no longer ships are removed the same way, again only when never site-edited. Site customizations are safe: an asset you've edited or replaced is detected and preserved, and CSS overrides live in custom.css.
This also covers newly shipped official themes: if a site's database predates one (e.g. Ember on an older install), its theme record is created at startup with the shipped default Layout & Presentation configuration, and its CSS, icons, and backgrounds are imported in the same boot — the theme simply appears in the pickers after updating. An existing theme record is never modified, so site edits to a theme's configuration are preserved.
Theme Development
CSS Architecture
Recommended Structure:
/* 1. CSS Variables */
:root {
--primary-color: ...;
}
/* 2. Base Styles */
body, html {
font-family: ...;
}
/* 3. Layout */
.container, .grid {
...
}
/* 4. Components */
.zone-card, .btn, .nav {
...
}
/* 5. States */
.on, .off, .active {
...
}
/* 6. Responsive */
@media (max-width: 768px) {
...
}
Responsive Design
Support multiple screen sizes:
/* Desktop */
.zone-grid {
grid-template-columns: repeat(4, 1fr);
}
/* Tablet */
@media (max-width: 1024px) {
.zone-grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Mobile */
@media (max-width: 768px) {
.zone-grid {
grid-template-columns: repeat(2, 1fr);
}
}
Dark Mode Themes
Considerations for dark themes:
:root {
--background-color: #1a1a1a;
--surface-color: #2a2a2a;
--text-primary: #e5e5e5;
--text-secondary: #a0a0a0;
/* Reduce contrast for readability */
--border-color: #444444;
/* Muted accent colors */
--primary-color: #4a90e2;
}
Dark Mode Best Practices:
- Reduce pure white (#fff) to off-white (#e5e5e5)
- Increase border subtlety
- Use muted accent colors
- Test readability extensively
- Consider eye strain for long viewing
Floor plans
Zone maps are generated from site space geometry, so the only artwork you supply is the plan image on the space. What makes a good one:
-
Clarity: Ensure floor plans are clear and easy to understand
-
Orientation: Orient plans consistently (north up, entrance at bottom, etc.)
-
Simplification: Remove unnecessary detail — room outlines are what matter
-
Format: PNG or JPG, around 1920x1080, ideally under 2MB. The image is stored on the site space and delivered to panels over the authenticated socket, so oversized files cost load time on every wall panel.
-
Updates: Replace the plan when the physical layout changes. Room rectangles are stored as percentages, so they survive a same-aspect replacement; a re-crop or a different aspect needs the rooms redrawn.
Advanced Topics
Theme Versioning
Maintain theme versions:
- Copy theme before major changes
- Name with version:
carbon_v1,carbon_v2 - Test new version thoroughly
- Switch UIs to new version when ready
- Keep old version as fallback
Multi-Brand Themes
For service providers managing multiple clients:
- Create base theme with common structure
- Copy for each client
- Customize colors, logos, backgrounds
- Assign client-specific themes to their UIs
- Maintain base theme for updates
Theme Inheritance
While not directly supported, simulate with:
- Create base theme with core styles
- Copy for variations
- Only modify differences in copies
- Maintain consistent variable names
Dynamic Theming
CSS can respond to attributes:
/* Controlled by attribute: ui.color_scheme */
.zone-card[data-scheme="warm"] {
--primary-color: #ff6b35;
}
.zone-card[data-scheme="cool"] {
--primary-color: #4a90e2;
}
Set via JavaScript in theme or widgets.
Animations and Transitions
Enhance user experience:
.zone-card {
transition: all 0.3s ease;
}
.zone-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.zone-card.on {
animation: pulse 0.5s ease;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
Use Sparingly: Too much animation can be distracting.
Troubleshooting
Theme Not Applying
Check:
- Theme Assignment: UI has theme attribute set
- Browser Cache: Clear cache and hard reload (Ctrl+F5)
- CSS Errors: Check browser console for CSS errors
- File Path: Verify
style.cssexists in theme directory
Icons Not Displaying
Check:
- Theme Assignment: UI using correct theme
- Icon Exists: Icon file exists in theme's
/icons/directory - Icon Name: Reference matches filename (without extension)
- File Format: PNG or SVG
- Cache: Clear browser cache
Background Not Showing
Check:
- Mapping: Background mapped to route in Backgrounds tab
- Route Match: Current page route matches mapping
- File Exists: Background file uploaded successfully
- Image Format: PNG or JPG
- File Size: Not too large (< 5MB)
Zone Map Not Loading
Zone maps come from site spaces, not from the theme. Check:
- UI is space-linked: the UI has a Site Space set (System > UIs). A UI with no space has no physical layout, so no map can be derived.
- A plan exists: the space, or an ancestor of it, has a floor plan image uploaded (Site > Site Spaces).
- Rooms are drawn: the zones' rooms have bounds on that plan. A room with no bounds, or a gap in the chain between the room and the plan, cannot be placed.
- Zones are assigned: the zones have a Site Space set on the zone record.
- Subsystem Match: you are viewing the subsystem those zones belong to.
- Console Errors: the map logs any zone it could not place, with a reason.
A pin that seems missing may simply be inside a count marker — a room too small to show its pins individually collapses into one. Tap the marker to zoom into the room and the pins spread out. See Site Spaces → Room clusters and drilling in.
Some Pins Have No Name Under Them
Names are printed only where they fit without overlapping a neighbouring pin or count marker, measured in pixels against the plan as currently rendered — so a crowded floor drops names on a phone that it prints on a wall panel. Touch and hold any pin to name it, or drill into the room: as the pins spread apart the names appear. See Site Spaces → Knowing which zone a pin is.
CSS Changes Not Reflecting
Try:
- Click Save button in Styles tab
- Hard refresh browser (Ctrl+F5 or Cmd+Shift+R)
- Close and reopen preview window
- Verify no CSS syntax errors
- Check browser developer tools for applied styles
Related Documentation
- UIs - Assigning themes to UIs
- UI Pages - Using themes on pages
- UI Widgets - Widget styling
- Gallery - Background image sources