Skip to content
⌂ Home

AI Theme Guide

This document is written for AI to read. Send it to an AI together with a description of your taste, and the AI can generate a custom theme JSON that ECHO can import.

Goal: produce one echo-next.custom-theme JSON file. Import it in ECHO under Settings -> Appearance -> Customize Current Theme -> Import Parameters and you get your own theme.

  • Output JSON only. No CSS, JS, HTML, or explanatory text.
  • The JSON must survive JSON.parse: no comments, no trailing commas, no single quotes.
  • Colors use #RRGGBB hex only, for example #101416. Do not output rgb(), rgba(), hsl(), transparency, or gradient strings.
  • Field names must match this document exactly. Do not invent new fields.
  • Provide at least one of light or dark. Providing both is recommended.
  • A theme may be intentionally low-contrast, but know that it can hurt readability. ECHO only warns; it never blocks saving.
  • Prefer aesthetically consistent themes: background, panels, player, sidebar, text, and accents should feel like one design system.
  • Do not just shift every color to shades of a single hue. Use at least one primary accent, one secondary accent, and a set of neutrals.

Output this structure:

{
"schema": "echo-next.custom-theme",
"version": 2,
"exportedAt": "2026-06-03T00:00:00.000Z",
"theme": {
"id": "theme-ai-example",
"name": "AI Example",
"basePreset": "classic",
"createdAt": "2026-06-03T00:00:00.000Z",
"updatedAt": "2026-06-03T00:00:00.000Z",
"light": {},
"dark": {}
}
}

Field reference:

FieldRequiredMeaning
schemaYesFixed value echo-next.custom-theme
versionYesFixed value 2
exportedAtYesISO timestamp string
theme.idYes1-80 characters; letters, digits, underscores, dots, colons, hyphens only
theme.nameYesThe name shown to the user, up to 48 characters
theme.basePresetYesBase preset name, see the list below
theme.createdAtYesISO timestamp string
theme.updatedAtYesISO timestamp string
theme.lightNoLight-mode override parameters
theme.darkNoDark-mode override parameters

Available basePreset values:

classic, echoTwilight, sakuraMilk, peachSoda, mintCandy, berryDream,
matchaCream, lemonMochi, cottonCloud, melonCream, seaSaltJelly,
caramelPudding, neonCandy, nyanCat, childrenDoodle, wisteriaBubble,
strawberryCookie, graphiteAurora, amberNoir, oceanStudio, rosewoodVinyl,
darkSideMoon, shibuyaNight, kyotoKurenai, ukiyoIndigo, fujiSnow,
matsuriLantern, ginzaNoir, frostJazz

Use classic when unsure. If the user asks to “keep the feel of a preset and fine-tune it”, write that preset into basePreset.

light and dark share the same fields. You may write only the fields you override, but generating the full set is recommended so the user gets a complete result on import.

{
"appBg": "#f4f8fb",
"appBg2": "#d8e8ef",
"appBg3": "#dce3f2",
"panel": "#fbfdff",
"panelSoft": "#e6eef4",
"accent": "#245f9e",
"accentStrong": "#163f70",
"secondary": "#7f3e70",
"heading": "#142234",
"text": "#34495f",
"muted": "#546a80",
"border": "#5c7da9",
"onAccent": "#ffffff",
"buttonText": "#34495f",
"titlebar": "#fbfdff",
"sidebar": "#e6eef4",
"player": "#fbfdff",
"field": "#ffffff",
"row": "#ffffff",
"rowHover": "#eef4fa",
"rowActive": "#dce9ff",
"chip": "#ffffff",
"focus": "#245f9e",
"danger": "#d64545",
"success": "#2f8f72",
"warning": "#c98a16",
"panelOpacityPercent": 78,
"glassPercent": 20,
"shadowPercent": 82,
"cornerRadiusPx": 14,
"panelBlurPx": 15,
"saturationPercent": 100,
"motionEnabled": true,
"motionSpeedSeconds": 0.18,
"motionIntensityPercent": 64
}
FieldUsed forGeneration advice
appBgMain window backgroundSets the theme’s first impression
appBg2Background gradient midpointSame mood as appBg but with depth
appBg3Background gradient tailMay add a slight warm/cool contrast
panelPrimary panel colorMust carry body text and buttons
panelSoftLower-emphasis panelsSidebar, secondary areas, soft backgrounds
accentPrimary accentPrimary buttons, progress, focus
accentStrongStrong accentHeading highlights, emphasis layers
secondaryThird accentSmall states and highlight touches
headingPrimary textTitles and important text
textBody textTrack names, settings copy, list text
mutedSecondary textDescriptions and helper text
borderBorders and dividersShould not outshout the text
onAccentText on accent buttonsMust hold up against accent
buttonTextRegular button textUsually close to text
titlebarWindow top barUsually close to panel or appBg
sidebarLeft navigation backgroundUsually close to panelSoft
playerBottom player backgroundMay be slightly deeper or more solid than panel
fieldInputs and search boxesNeeds readable contrast with text
rowNormal list rowsUsually close to panel
rowHoverHovered list rowsSlightly different from row
rowActiveSelected list rowsCarries a hint of accent
chipFilter chips, small buttonsUsually close to field
focusKeyboard focus and outline highlightUsually equal or close to accent
dangerDanger colorDelete, errors
successSuccess colorHealthy states, successful connections
warningWarning colorReminders, caution
FieldRangeMeaning
panelOpacityPercent40-100Panel opacity; lower is more transparent
glassPercent0-80Glass feel and background blur layering
shadowPercent0-100Shadow strength
cornerRadiusPx0-28Corner radius
panelBlurPx0-32Panel blur amount
saturationPercent60-140Overall saturation
motionEnabledtrue / falseWhether theme motion is enabled
motionSpeedSeconds0.12-8Motion speed; smaller is faster
motionIntensityPercent0-160Motion intensity

ECHO lets users save low-contrast themes, but AI should favor readability.

Recommended checks:

  • text against appBg: aim for 4.5:1.
  • heading against appBg: aim for 4.5:1.
  • buttonText against panel: aim for 4.5:1.
  • onAccent against accent: aim for 3:1.

Common light-theme practice:

  • Light backgrounds with dark text.
  • If accent is dark, use #ffffff for onAccent.
  • Panels should not equal the background exactly; keep at least a subtle layer.

Common dark-theme practice:

  • Dark backgrounds with light text.
  • accent may be brighter, but avoid heavy neon.
  • Do not make muted too dark, or helper text becomes unreadable.
{
"schema": "echo-next.custom-theme",
"version": 2,
"exportedAt": "2026-06-03T00:00:00.000Z",
"theme": {
"id": "theme-ai-midnight-lychee",
"name": "Midnight Lychee",
"basePreset": "classic",
"createdAt": "2026-06-03T00:00:00.000Z",
"updatedAt": "2026-06-03T00:00:00.000Z",
"light": {
"appBg": "#f8f1f5",
"appBg2": "#ead8e8",
"appBg3": "#d7edf0",
"panel": "#fffafd",
"panelSoft": "#efe2eb",
"accent": "#9f3d72",
"accentStrong": "#67264b",
"secondary": "#2f7f87",
"heading": "#2a1724",
"text": "#4b3241",
"muted": "#735b69",
"border": "#b67598",
"onAccent": "#ffffff",
"buttonText": "#4b3241",
"titlebar": "#fffafd",
"sidebar": "#efe2eb",
"player": "#fff7fb",
"field": "#ffffff",
"row": "#ffffff",
"rowHover": "#f5edf2",
"rowActive": "#efd4e4",
"chip": "#fffafd",
"focus": "#9f3d72",
"danger": "#c84355",
"success": "#2f8f72",
"warning": "#bd7a1c",
"panelOpacityPercent": 80,
"glassPercent": 18,
"shadowPercent": 78,
"cornerRadiusPx": 14,
"panelBlurPx": 14,
"saturationPercent": 104,
"motionEnabled": true,
"motionSpeedSeconds": 0.22,
"motionIntensityPercent": 58
},
"dark": {
"appBg": "#0d0910",
"appBg2": "#1d1020",
"appBg3": "#0b2428",
"panel": "#211725",
"panelSoft": "#17101a",
"accent": "#f08abd",
"accentStrong": "#ffd6ea",
"secondary": "#72d0d7",
"heading": "#fff6fb",
"text": "#eadce7",
"muted": "#c8aeba",
"border": "#c875a4",
"onAccent": "#321020",
"buttonText": "#eadce7",
"titlebar": "#18101b",
"sidebar": "#17101a",
"player": "#211725",
"field": "#17101a",
"row": "#201522",
"rowHover": "#2a1a2e",
"rowActive": "#3a2039",
"chip": "#26192b",
"focus": "#f08abd",
"danger": "#ff6b7a",
"success": "#65d6a1",
"warning": "#f0b45b",
"panelOpacityPercent": 88,
"glassPercent": 24,
"shadowPercent": 96,
"cornerRadiusPx": 14,
"panelBlurPx": 18,
"saturationPercent": 108,
"motionEnabled": true,
"motionSpeedSeconds": 0.22,
"motionIntensityPercent": 70
}
}
}

Send the following to an AI, and add your style description at the end:

Using the ECHO AI Theme Guide I provided, generate an importable custom theme JSON for ECHO.
Requirements:
- Output exactly one JSON code block.
- Use schema = "echo-next.custom-theme", version = 2.
- Generate both light and dark tone sets.
- All colors must be #RRGGBB.
- Do not output CSS, JS, explanations, or comments.
- Fields must follow the guide; do not add fields that do not exist.
- Keep body text, headings, buttons, and accent buttons readable.
My theme request:
Theme name:
Keywords:
Desired mood:
Colors I like:
Colors I dislike:
Light-leaning or dark-leaning:
Need high contrast:
Need motion:
Reference works or imagery:

Before emitting JSON, verify:

  • schema is echo-next.custom-theme.
  • version is 2.
  • theme.id contains only safe characters and is at most 80 characters.
  • theme.name is at most 48 characters.
  • basePreset is in the allowed list.
  • At least one of light or dark is present.
  • Every color is #RRGGBB.
  • Every numeric value is within range.
  • The JSON has no comments and no trailing commas.
  • The theme matches the user’s description instead of stacking random colors.

If the user wants a theme plugin rather than a single importable JSON, use contributes.themePresets. Plugin themes are not this document’s main goal, but the structure looks like this:

{
"id": "echo.ai-theme-pack",
"name": "AI Theme Pack",
"version": "0.1.0",
"apiVersion": 2,
"entry": "plugin.js",
"permissions": [],
"contributes": {
"themePresets": [
{
"id": "midnight-lychee",
"title": "Midnight Lychee",
"description": "Lychee pink, night purple, and cool teal highlights.",
"basePreset": "classic",
"preview": "linear-gradient(135deg, #0d0910 0%, #1d1020 50%, #72d0d7 100%)",
"swatches": ["#0d0910", "#f08abd", "#72d0d7", "#eadce7"],
"light": {
"appBg": "#f8f1f5",
"panel": "#fffafd",
"accent": "#9f3d72",
"heading": "#2a1724",
"text": "#4b3241",
"onAccent": "#ffffff"
},
"dark": {
"appBg": "#0d0910",
"panel": "#211725",
"accent": "#f08abd",
"heading": "#fff6fb",
"text": "#eadce7",
"onAccent": "#321020"
}
}
]
}
}

Additional plugin-theme rules:

  • At most 12 entries in themePresets.
  • preview may only be a solid color or linear-gradient(...).
  • swatches may only contain #RRGGBB colors.
  • Theme plugins need no permissions and inject no arbitrary CSS.

For plugin directory structure, permissions, and the enabling flow, see the Plugin Authoring Guide.

To publish themes or sandbox plug-ins on Steam Workshop (not Settings import JSON), see the Workshop SDK tutorial.