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.
Generation Principles
Section titled “Generation Principles”- 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
#RRGGBBhex only, for example#101416. Do not outputrgb(),rgba(),hsl(), transparency, or gradient strings. - Field names must match this document exactly. Do not invent new fields.
- Provide at least one of
lightordark. 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.
Top-Level Structure
Section titled “Top-Level Structure”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:
| Field | Required | Meaning |
|---|---|---|
schema | Yes | Fixed value echo-next.custom-theme |
version | Yes | Fixed value 2 |
exportedAt | Yes | ISO timestamp string |
theme.id | Yes | 1-80 characters; letters, digits, underscores, dots, colons, hyphens only |
theme.name | Yes | The name shown to the user, up to 48 characters |
theme.basePreset | Yes | Base preset name, see the list below |
theme.createdAt | Yes | ISO timestamp string |
theme.updatedAt | Yes | ISO timestamp string |
theme.light | No | Light-mode override parameters |
theme.dark | No | Dark-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, frostJazzUse classic when unsure. If the user asks to “keep the feel of a preset and fine-tune it”, write that preset into basePreset.
Tone Structure
Section titled “Tone Structure”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}Color Field Meanings
Section titled “Color Field Meanings”| Field | Used for | Generation advice |
|---|---|---|
appBg | Main window background | Sets the theme’s first impression |
appBg2 | Background gradient midpoint | Same mood as appBg but with depth |
appBg3 | Background gradient tail | May add a slight warm/cool contrast |
panel | Primary panel color | Must carry body text and buttons |
panelSoft | Lower-emphasis panels | Sidebar, secondary areas, soft backgrounds |
accent | Primary accent | Primary buttons, progress, focus |
accentStrong | Strong accent | Heading highlights, emphasis layers |
secondary | Third accent | Small states and highlight touches |
heading | Primary text | Titles and important text |
text | Body text | Track names, settings copy, list text |
muted | Secondary text | Descriptions and helper text |
border | Borders and dividers | Should not outshout the text |
onAccent | Text on accent buttons | Must hold up against accent |
buttonText | Regular button text | Usually close to text |
titlebar | Window top bar | Usually close to panel or appBg |
sidebar | Left navigation background | Usually close to panelSoft |
player | Bottom player background | May be slightly deeper or more solid than panel |
field | Inputs and search boxes | Needs readable contrast with text |
row | Normal list rows | Usually close to panel |
rowHover | Hovered list rows | Slightly different from row |
rowActive | Selected list rows | Carries a hint of accent |
chip | Filter chips, small buttons | Usually close to field |
focus | Keyboard focus and outline highlight | Usually equal or close to accent |
danger | Danger color | Delete, errors |
success | Success color | Healthy states, successful connections |
warning | Warning color | Reminders, caution |
Numeric Field Ranges
Section titled “Numeric Field Ranges”| Field | Range | Meaning |
|---|---|---|
panelOpacityPercent | 40-100 | Panel opacity; lower is more transparent |
glassPercent | 0-80 | Glass feel and background blur layering |
shadowPercent | 0-100 | Shadow strength |
cornerRadiusPx | 0-28 | Corner radius |
panelBlurPx | 0-32 | Panel blur amount |
saturationPercent | 60-140 | Overall saturation |
motionEnabled | true / false | Whether theme motion is enabled |
motionSpeedSeconds | 0.12-8 | Motion speed; smaller is faster |
motionIntensityPercent | 0-160 | Motion intensity |
Contrast Advice
Section titled “Contrast Advice”ECHO lets users save low-contrast themes, but AI should favor readability.
Recommended checks:
textagainstappBg: aim for 4.5:1.headingagainstappBg: aim for 4.5:1.buttonTextagainstpanel: aim for 4.5:1.onAccentagainstaccent: aim for 3:1.
Common light-theme practice:
- Light backgrounds with dark text.
- If
accentis dark, use#ffffffforonAccent. - Panels should not equal the background exactly; keep at least a subtle layer.
Common dark-theme practice:
- Dark backgrounds with light text.
accentmay be brighter, but avoid heavy neon.- Do not make
mutedtoo dark, or helper text becomes unreadable.
Complete Example
Section titled “Complete Example”{ "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 } }}User Prompt Template
Section titled “User Prompt Template”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:Pre-Generation Checklist
Section titled “Pre-Generation Checklist”Before emitting JSON, verify:
schemaisecho-next.custom-theme.versionis2.theme.idcontains only safe characters and is at most 80 characters.theme.nameis at most 48 characters.basePresetis in the allowed list.- At least one of
lightordarkis 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.
Advanced: Plugin Theme Structure
Section titled “Advanced: Plugin Theme Structure”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. previewmay only be a solid color orlinear-gradient(...).swatchesmay only contain#RRGGBBcolors.- 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.