Generates modular VS Code dark themes from a single primary hex color using OKLCH palette derivation across 16 independent modules. Use when asked to "create a VS Code theme", "generate color theme", "add workbench colors", "update token colors", or "port theme to VS Code". Produces complete color-theme.json with workbench colors, TextMate tokenColors, and semanticTokenColors.
This skill generates complete VS Code dark color themes from a single primary hex color using a modular architecture where each UI region is an independent JSON fragment. The governing principle is modular isolation — each module owns its workbench color keys and token scopes, enabling targeted changes without editing the full theme file. Begin with <step_1_derive_palette> to generate the foundational color scales.
<use_cases>
</use_cases>
<module_architecture>
The theme is composed of 16 independent modules, each containing a subset of workbench color keys and/or token scopes. Modules are self-contained JSON fragments that are independently editable — changing one module does not affect any other. The assembly step merges all module fragments into the final .
<workflow> </workflow> <validation> </validation> <resources> </resources>*-color-theme.jsonLoad references/module-catalog.md for: the complete key listing per module with every workbench color key and token scope assignment.
| Module | Purpose | Keys |
|---|---|---|
| base | Core editor surface — background, foreground, selection, find, cursor, brackets | 15 |
| syntax | TextMate tokenColors + semanticTokenColors — 11 root scope groups, 21 semantic types, 10 modifiers | ~120 |
| activity-bar | Left-edge icon bar — background, foreground, active state, badge | 9 |
| sidebar | File explorer and side panels — background, foreground, headers, borders | 8 |
| tabs | Editor tab strip — active/inactive/hover states, borders, group headers | 15 |
| status-bar | Bottom status bar — normal, debugging, remote, prominent item states | 13 |
| terminal | Integrated terminal — surface, cursor, selection, 16 ANSI colors | 22 |
| panels | Bottom panels (output, debug console) — background, borders, titles | 10 |
| diff-merge | Diff editor and merge conflicts — inserted/removed/current/incoming | 17 |
| git-decorations | File tree git status — added, modified, deleted, renamed, untracked | 9 |
| inputs-buttons | Form controls — inputs, validation states, buttons, dropdowns, checkboxes | 29 |
| lists | Tree views and list selections — active/inactive/hover/focus states | 14 |
| notifications | Notification toasts and center — borders, backgrounds, icons | 11 |
| minimap | Minimap overview — highlights, slider, gutter indicators | 11 |
| title-bar | Window title bar — active/inactive background, foreground, border | 5 |
| breadcrumbs | Breadcrumb navigation — foreground, focus, selection, picker | 4 |
Module JSON fragment structure:
Each module produces a partial JSON object. Workbench modules produce colors entries. The syntax module produces tokenColors and semanticTokenColors entries. The assembly step merges all fragments.
{
"colors": {
"editor.background": "#1a1b2e",
"editor.foreground": "#e8e6e1"
}
}
{
"tokenColors": [
{
"scope": "comment",
"settings": { "foreground": "#8b8d98", "fontStyle": "italic" }
}
],
"semanticTokenColors": {
"variable.readonly": "#c4b5fd"
}
}
Isolation constraint: Each workbench color key belongs to exactly one module. No key appears in more than one module fragment. The syntax module exclusively owns tokenColors and semanticTokenColors.
</module_architecture>
Execute steps sequentially. Each step produces output that feeds the next — palette feeds semantic mapping, semantic mapping feeds module generation, modules merge into the final theme JSON.
<step_1_derive_palette>
Generate six 12-step Radix scales from the primary hex using OKLCH color space via coloraide.
Load color-derivation.instructions.md for: OKLCH-first derivation rules, Radix 12-step architecture, coloraide usage patterns, and contrast enforcement requirements.
Required scales:
| Scale | Purpose | Hue derivation |
|---|---|---|
| primary | Accents, selection, cursor, links, active states | Primary hex hue (constant) |
| neutral | Backgrounds, borders, text, gutter, surfaces | Primary hue with chroma 0.005–0.02 |
| red | Errors, invalid syntax, deletions, git removed | Hue rotation to ~25° |
| amber | Warnings, deprecated syntax, modified indicators | Hue rotation to ~70° |
| green | Success states, git additions, string literals | Hue rotation to ~145° |
| blue | Info states, links, type annotations | Hue rotation to ~245° |
Derivation rules:
coloraide gamut mapping (fit('srgb')) on every OKLCH→sRGB conversion#rrggbb), use 8-digit (#rrggbbaa) only for alpha</step_1_derive_palette>
<step_2_map_semantic_roles>
Assign palette scale steps to semantic roles following the cross-editor mapping.
Load theme-conventions.instructions.md for: the <semantic_mapping> table and VS Code-specific format constraints.
Core role assignments:
| Semantic role | Scale/step | VS Code key |
|---|---|---|
| App background (deepest) | neutral/1 | titleBar.activeBackground, activityBar.background |
| Editor background | neutral/2 | editor.background |
| Component background | neutral/3 | sideBar.background, panel.background |
| Hover state | neutral/4 | list.hoverBackground, tab.hoverBackground |
| Selection | primary/4 | editor.selectionBackground |
| Subtle border | neutral/6 | panel.border, sideBar.border |
| Default border | neutral/7 | input.border, dropdown.border |
| Strong border | neutral/8 | inputOption.activeBorder, focusBorder |
| Accent solid | primary/9 | activityBar.activeBorder, button.background |
| Accent hover | primary/10 | editorCursor.foreground, button.hoverBackground |
| Secondary text | neutral/11 | editorLineNumber.foreground, tab.inactiveForeground |
| Primary text | neutral/12 | editor.foreground, sideBarTitle.foreground |
Constraint: Every foreground/background pair formed by these assignments must pass dual-check contrast before proceeding — verify in <step_8_audit_contrast>.
</step_2_map_semantic_roles>
<step_3_generate_base_module>
Generate the base module containing core editor surface keys.
Load references/module-catalog.md for: the complete key listing for the base module.
Key assignments:
editor.background → neutral/2editor.foreground → neutral/12editor.lineHighlightBackground → neutral/3 (subtle active line)editor.selectionBackground → primary/4 with alpha (#rrggbbaa)editor.selectionHighlightBackground → primary/3 with alphaeditor.findMatchBackground → amber/5 with alphaeditor.findMatchHighlightBackground → amber/4 with alphaeditorCursor.foreground → primary/10editorBracketMatch.background → primary/4 with alphaeditorBracketMatch.border → primary/8Output: JSON fragment with colors object containing all 15 base keys.
</step_3_generate_base_module>
<step_4_generate_syntax_module>
Generate TextMate tokenColors and semanticTokenColors for syntax highlighting. This is the largest module.
Load references/module-catalog.md for: the complete scope listing and semantic type/modifier assignments for the syntax module.
TextMate tokenColors — 11 root scope groups:
| Scope group | Typical scale | fontStyle |
|---|---|---|
comment | neutral/11 (desaturated) | italic |
constant | amber/9 | — |
entity.name.function | blue/9 | — |
entity.name.type, entity.name.class | primary/11 | — |
entity.name.tag | red/9 | — |
invalid | red/9 fg, red/3 bg | — |
keyword | primary/9 | — |
markup.heading | primary/10 | bold |
punctuation | neutral/11 | — |
storage | primary/9 | — |
string | green/9 | — |
support.function | blue/9 | — |
variable | neutral/12 | — |
variable.parameter | amber/11 | — |
Semantic token types — 21 types with foreground assignments. Use key format type: "#hex" for unmodified types and type.modifier: "#hex" for modified variants.
Semantic token modifiers — 10 modifiers. Key overrides: *.readonly adds subtle chroma shift, *.deprecated adds "strikethrough" fontStyle, *.defaultLibrary uses desaturated variant.
Output: JSON fragment with tokenColors array and semanticTokenColors object.
</step_4_generate_syntax_module>
<step_5_generate_chrome_modules>
Generate the 11 UI chrome modules as independent JSON fragments. Each module owns its workbench color keys exclusively — no key appears in more than one module.
Load references/module-catalog.md for: the complete key listing for all chrome modules.
Modules to generate:
Output: 11 JSON fragments, each with a colors object containing module-specific keys.
</step_5_generate_chrome_modules>
<step_6_generate_terminal_module>
Generate the terminal module with surface colors and ANSI 16 palette.
Load references/module-catalog.md for: the complete key listing for the terminal module.
Terminal surface — 6 keys: background, foreground, cursor, selection.
ANSI 16 colors — map to palette scales:
| ANSI color | Normal scale/step | Bright scale/step |
|---|---|---|
| Black | neutral/1 | neutral/5 |
| Red | red/9 | red/10 |
| Green | green/9 | green/10 |
| Yellow | amber/9 | amber/10 |
| Blue | blue/9 | blue/10 |
| Magenta | primary/9 (hue ~320°) | primary/10 (hue ~320°) |
| Cyan | primary/9 | primary/10 |
| White | neutral/11 | neutral/12 |
Output: JSON fragment with colors object containing 22 terminal keys.
</step_6_generate_terminal_module>
<step_7_generate_diff_git_modules>
Generate the diff-merge and git-decorations modules.
Load references/module-catalog.md for: the complete key listings for both modules.
diff-merge — 17 keys using green (inserted), red (removed), blue (incoming), and neutral (common) scales. Use alpha-transparent backgrounds (#rrggbbaa) for diff highlights to allow underlying syntax to show through.
git-decorations — 9 keys mapping git states to semantic colors: green (added), amber (modified), red (deleted), blue (renamed), neutral (ignored). Use scale step 9 for foreground colors to ensure visibility against dark tree backgrounds.
Output: 2 JSON fragments with colors objects.
</step_7_generate_diff_git_modules>
<step_8_audit_contrast>
Run WCAG 2.1 AA + APCA dual-check on all foreground/background pairs generated in steps 3–7.
Load contrast-audit/SKILL.md for: the complete pair collection, classification, calculation, and reporting workflow.
Threshold quick reference:
| Context | WCAG minimum | APCA minimum | APCA preferred |
|---|---|---|---|
| Body text (code, comments) | 4.5:1 | Lc 75 | Lc 90 |
| Large text (headings, titles) | 3:1 | Lc 60 | Lc 75 |
| UI components (buttons, tabs) | 3:1 | Lc 60 | Lc 75 |
| Sub-text (line numbers, hints) | 3:1 | Lc 45 | Lc 60 |
| Non-text (borders, indicators) | 3:1 | Lc 30 | Lc 45 |
Remediation: When a pair fails contrast, adjust lightness in OKLCH — NEVER adjust hue or chroma to fix contrast. Increase foreground L or decrease background L until both thresholds pass.
Radix scale validation: Verify step 11 vs step 2 achieves Lc >= 60 and step 12 vs step 2 achieves Lc >= 90 for every scale.
</step_8_audit_contrast>
<step_9_validate_json>
Validate all module JSON fragments for correctness before assembly.
Syntax validation:
#[0-9a-f]{6} or #[0-9a-f]{8} (6-digit or 8-digit lowercase)Convention compliance:
tokenColors entries have scope (string or array) and settings (object with foreground, optional fontStyle)semanticTokenColors keys use format type, type.modifier, or type.modifier:languagesemanticHighlighting is set to truetype is set to "dark"Coverage completeness:
</step_9_validate_json>
<step_10_assemble_theme>
Merge all module JSON fragments into the final *-color-theme.json.
File structure:
{
"name": "Theme Name",
"type": "dark",
"semanticHighlighting": true,
"colors": { },
"tokenColors": [ ],
"semanticTokenColors": { }
}
Assembly rules:
colors objects into the top-level colors — keys must not conflicttokenColors array from the syntax module into the top-level tokenColorssemanticTokenColors object from the syntax module into the top-level semanticTokenColorsname, type: "dark", and semanticHighlighting: truePackage manifest — package.json must include:
{
"contributes": {
"themes": [
{
"label": "Theme Name",
"uiTheme": "vs-dark",
"path": "./themes/theme-name-color-theme.json"
}
]
},
"categories": ["Themes"]
}
Output verification: Parse the assembled JSON, confirm no duplicate keys, and verify the theme loads in VS Code without errors.
</step_10_assemble_theme>
<important_rules>
Critical rules that govern all VS Code theme generation. Violations cause broken themes or inconsistent output.
#rrggbb. Use 8-digit #rrggbbaa only for alpha transparency (selections, highlights, diff backgrounds). No shorthand, no uppercase, no named colorstokenColors and semanticTokenColorssemanticHighlighting: true to enable language-aware token coloring over TextMate fallbackstype: "dark" so VS Code applies the correct base theme defaults for uncustomized keystokenColors from general to specific so overrides work correctly</important_rules>
<error_handling>
package.json has correct contributes.themes path, JSON parses without errors, type is "dark", file extension is .json</error_handling>
P1 — Blocking (must pass before delivery):
tokenColors entries have valid scope and settings with foregroundsemanticTokenColors entries use valid type.modifier:language key formatsemanticHighlighting: true and type: "dark" present in assembled themeP2 — Quality (should pass):
package.json manifest includes correct contributes.themes configurationP3 — Polish (nice to have):
*.readonly, *.deprecated, *.defaultLibrary have distinct styling<semantic_mapping> table, VS Code format constraints, file naming conventions