Skip to content

Theme Pack Development Guide ​

Songloft supports customizing the app's color scheme, border radii, and player gradient effects through .songloft-theme theme packs. This guide covers the format specification, creation workflow, and best practices.


Overview ​

A theme pack is a JSON file (with .songloft-theme extension) that declares color schemes for light/dark modes and UI visual parameters. The theme pack system is built on Material 3 design specifications:

  • A single seed color automatically generates the complete color palette
  • Optional overrides for background and surface colors
  • Independent control over player gradient, border radii, and other visual parameters
  • Theme mode (light/dark/system) and theme packs are independent — one theme pack defines both light and dark color schemes

Full Schema ​

json
{
  "schemaVersion": 1,
  "id": "author.theme-name",
  "name": "Theme Name",
  "version": "1.0.0",
  "author": "Author Name",
  "description": "Short description",
  "light": {
    "seedColor": "#6750A4",
    "backgroundColor": "#FFF7FF",
    "surfaceColor": "#FFFFFF",
    "glassColor": "#9C7CF4"
  },
  "dark": {
    "seedColor": "#D0BCFF",
    "backgroundColor": "#141218",
    "surfaceColor": "#211F26",
    "glassColor": "#B39DDB"
  },
  "playerGradient": ["#4A148C", "#1A237E"],
  "cardRadius": 16,
  "controlRadius": 20,
  "navigationRadius": 18,
  "navigationStyle": "standard"
}

Field Reference ​

Metadata ​

FieldTypeRequiredDescription
schemaVersionint✅Must be 1 (current version)
idstring✅Globally unique ID, format: author.theme-name, e.g. songloft.neon-night
namestring✅Display name
versionstring✅Semantic version, e.g. 1.0.0
authorstringNoAuthor name
descriptionstringNoShort description (max ~50 characters recommended)

Colors (light / dark) ​

light and dark define color schemes for each mode. At least one must be provided.

FieldTypeRequiredDescription
seedColorstring✅Seed color in #RRGGBB format. Material 3 generates the full primary, secondary, tertiary palette from this color
backgroundColorstringNoOverride default background color, #RRGGBB format
surfaceColorstringNoOverride default surface color (cards, dialogs), #RRGGBB format
glassColorstringNoLiquid Glass base color (derives glassGlow / glassGlowFaint / glassSheen), #RRGGBB format. Without this field, light falls back to #3BAEEF, dark to #5BC0F5

How seedColor Works ​

Songloft uses Flutter's ColorScheme.fromSeed() method, which derives ~30 semantic color roles (primary, secondary, tertiary, error, etc.) from the seed color. You only need to pick a main hue — the Material 3 algorithm ensures contrast ratios and color harmony across all derived colors.

Light and dark can use different seed colors

Light mode typically uses a more saturated, deeper seed color; dark mode uses a brighter one for better visual results. See the Neon Night theme: light #6750A4, dark #D0BCFF.

Player Gradient ​

FieldTypeRequiredDescription
playerGradientstring[]NoFull-screen player background gradient, array of 2 #RRGGBB colors, top-to-bottom. Layered above cover art color extraction at 40% opacity

Border Radii ​

FieldTypeRequiredRangeDescription
cardRadiusnumberNo0-100Border radius for cards
controlRadiusnumberNo0-100Border radius for inputs, buttons, controls
navigationRadiusnumberNo0-100Border radius for navigation indicators
FieldTypeRequiredDescription
navigationStylestringNoNavigation bar appearance. "standard" (default) = standard navigation indicator; "capsule" = capsule-shaped glass navigation bar (designed for use with the Liquid Glass theme)

Creation Workflow ​

Step 1: Choose a Color Scheme ​

Recommended tools for picking seed colors:

Enter your seed color in Material Theme Builder to preview the full palette.

Step 2: Create the Theme File ​

Create a .songloft-theme file. Minimal template:

json
{
  "schemaVersion": 1,
  "id": "yourname.mytheme",
  "name": "My Theme",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "A brief description",
  "light": {
    "seedColor": "#your-light-seed-color"
  },
  "dark": {
    "seedColor": "#your-dark-seed-color"
  }
}

A single seedColor is all you need. backgroundColor, surfaceColor, playerGradient, and radii are all optional.

Step 3: Test Locally ​

  1. Open the Songloft app
  2. Go to Settings → Appearance → Theme Packs → Import
  3. Select your .songloft-theme file
  4. Tap the imported theme to activate it
  5. Toggle light/dark mode to verify both color schemes
  6. Open the full-screen player to check gradient effects

Step 4: Submit to the Community ​

  1. Fork songloft-org/songloft-themes
  2. Create a directory under themes/: themes/your-theme-name/
  3. Add your theme.songloft-theme file
  4. Submit a PR — maintainers will update index.json after review

Best Practices ​

Color Tips ​

  • Seed color: Pick a hue that represents your theme's mood — Material 3 handles saturation and lightness automatically
  • Light vs dark: Dark mode seedColor should be brighter than light mode, otherwise the primary color won't be prominent enough
  • Override cautiously: Only override backgroundColor/surfaceColor when M3's auto-generated colors don't match your design intent. In most cases, seedColor alone works great
  • Gradient colors: Use dark, same-hue colors for playerGradient — they're layered at 40% opacity over the cover art's extracted colors

ID Naming ​

  • Format: author.theme-name, all lowercase, hyphen-separated words
  • Examples: songloft.neon-night, alice.ocean-breeze
  • Never change the ID after publishing — it's the unique identifier. Changing it causes users to lose their install state

Versioning ​

Follow Semantic Versioning:

  • Fix color issues: 1.0.0 → 1.0.1
  • Add gradient effects: 1.0.0 → 1.1.0
  • Major color scheme redesign: 1.0.0 → 2.0.0

Examples ​

Neon Night ​

Purple and blue neon style, great for nighttime:

json
{
  "schemaVersion": 1,
  "id": "songloft.neon-night",
  "name": "Neon Night",
  "version": "1.1.0",
  "author": "Songloft",
  "description": "A dark theme with purple and blue neon accents",
  "light": {
    "seedColor": "#6750A4",
    "backgroundColor": "#FFF7FF",
    "surfaceColor": "#FFFFFF",
    "glassColor": "#9C7CF4"
  },
  "dark": {
    "seedColor": "#D0BCFF",
    "backgroundColor": "#141218",
    "surfaceColor": "#211F26",
    "glassColor": "#B39DDB"
  },
  "playerGradient": ["#4A148C", "#1A237E"],
  "cardRadius": 16,
  "controlRadius": 20,
  "navigationRadius": 18,
  "navigationStyle": "standard"
}

Sakura ​

Warm cherry-blossom pink tones, gentle and romantic:

json
{
  "schemaVersion": 1,
  "id": "songloft.sakura",
  "name": "Sakura",
  "version": "1.1.0",
  "author": "Songloft",
  "description": "A warm cherry-blossom theme with pink accents",
  "light": {
    "seedColor": "#D81B60",
    "backgroundColor": "#FFF0F5",
    "surfaceColor": "#FFFFFF",
    "glassColor": "#F06292"
  },
  "dark": {
    "seedColor": "#F48FB1",
    "backgroundColor": "#1A0A10",
    "surfaceColor": "#261418",
    "glassColor": "#F48FB1"
  },
  "playerGradient": ["#880E4F", "#4A148C"],
  "cardRadius": 14,
  "controlRadius": 16,
  "navigationRadius": 14,
  "navigationStyle": "standard"
}

Minimal Theme (seed color only) ​

Let Material 3 do all the work with just a seed color:

json
{
  "schemaVersion": 1,
  "id": "demo.minimal",
  "name": "Minimal Green",
  "version": "1.0.0",
  "light": {
    "seedColor": "#2E7D32"
  },
  "dark": {
    "seedColor": "#81C784"
  }
}

Troubleshooting ​

ProblemCauseSolution
Import fails with format errorJSON syntax error or missing required fieldsValidate JSON syntax, ensure schemaVersion, id, name are present
Colors don't applyIncorrect color formatMust be #RRGGBB format (6-digit hex with # prefix)
Radii unchangedRadius value out of rangeMust be between 0-100
Online install failsNetwork issue or SHA-256 mismatchCheck network; for custom sources, ensure SHA-256 in index.json matches the file
Dark mode too darkseedColor too deepUse a brighter seed color for dark mode