Sleepy Theme
A VSCode theme with GitHub Dark syntax colors on a deep neutral background with a single soft accent — in nine flavors.
📷 Previews
🌙 Sleepy
Screenshots for the other eight are still to come — they share Sleepy's layout exactly, only the chrome hue differs.
🔧 Usage
Marketplace
Search for Sleepy Theme in the Extensions view, or:
code --install-extension PcoiDev.sleepy-theme
Releases
- Download the
.vsix file from the Releases page.
- Open the Command Palette (
Ctrl+Shift+P or Cmd+Shift+P) in VS Code.
- Run the
Extensions: Install from VSIX... command.
From source
just deploy
This regenerates the themes, builds the .vsix with vsce, and installs it via code --install-extension.
However you install it: Ctrl+Shift+P → Preferences: Color Theme → pick a Sleepy flavor.
🎨 Flavors
Nine flavors, all sharing the exact same syntax palette. Only the chrome — backgrounds, sidebar,
accent — changes.
| Flavor |
Stone |
Editor background |
Accent |
| Sleepy |
the original steel blue-black |
#0d1117 |
#8eaabb |
| Sleepy Aquamarine |
cool cyan-teal |
#061315 |
#7cb0b3 |
| Sleepy Sapphire |
deep vivid blue |
#0d101a |
#90a7cb |
| Sleepy Tanzanite |
blue-violet |
#100f1a |
#9ea2cb |
| Sleepy Amethyst |
violet |
#140e17 |
#ae9cc4 |
| Sleepy Ruby |
deep red |
#13100f |
#ca9692 |
| Sleepy Topaz |
warm gold |
#12110e |
#b6a37c |
| Sleepy Emerald |
green |
#09140e |
#8bb094 |
| Sleepy Onyx |
pure neutral greyscale |
#111111 |
#a5a5a5 |
Each is defined by a reference gemstone hex in src/flavors.mjs; only its Oklab hue is used,
never the color itself. The ramp is re-centred on that hue at the original lightness curve, so all
nine have identical contrast. Sleepy is the hand-tuned original and comes out of the transform
byte-identical; Onyx drops chroma to zero.
Two corrections make the rotation survive contact with the whole hue wheel:
- Hue spread is compressed. The ramp spans ~65° internally, which reads as depth inside the
blues but falls apart rotated elsewhere — +40° off red is orange, off violet is pink. Rotated
flavors keep a third of it.
- Surface chroma is damped by warmth. A dark, low-chroma warm tone reads as dirt; the same
chroma in a cool tone reads as a clean neutral with a cast. That is exactly why Sapphire worked
and Ruby looked like mud — every flavor was tinting its surfaces equally. Surfaces are now damped
by how close the hue sits to the muddiest part of the wheel (~55°), so warm flavors keep
near-neutral backgrounds and carry their color in the accent, where the lightness is high enough
for it to read as color. Ruby's editor background went from
#1a0d0b (chroma 0.023, visibly
brown) to #13100f (0.005); Sapphire, being cool, is untouched.
✨ Syntax colors
GitHub Dark, the palette this theme has always used — vendored verbatim in src/github-dark.json
so any divergence from it stays visible in one place.
| Role |
Color |
| parameters, properties, plain identifiers |
#e6edf3 |
keywords, storage, self |
#ff7b72 |
| strings |
#87d8f7 |
| numbers, booleans, constants, enum members |
#58C4F5 |
| types, classes, namespaces, variables |
#ffa657 |
| functions, methods |
#d2a8ff |
| tags, JSON keys |
#7ee787 |
| comments |
#8b949e |
Three deliberate overrides on top of it, all in src/syntax.mjs:
self reads as a keyword. luau-lsp emits it as property.defaultLibrary, so the generic
property rule painted it plain white next to a red local.
- Builtin types are types.
number/string/boolean in type position were keyword-red while
a class like Model was orange; both are orange now.
- TOML has its own identity. It used to borrow the code palette wholesale and read as just
another source file, with
= and [ ] sharing the exact comment grey. Keys are now the neutral
subject, values carry the color, headers anchor in a violet no other language uses for a
declaration, and punctuation drops back to #59667a.
- Types are orange, functions are violet, constants are blue — everywhere. Python's
int,
str, its exception classes and inherited bases were all landing on the constant blue via the
bare support rule, so one color carried constants, types and builtin functions at once.
- Keyword arguments are parameters.
variable.parameter.function-call isn't matched by the
base variable.parameter.function rule, so Python kwargs (frozen=True, key=) fell through to
the orange meant for variables and shouted over everything near them.
self is one color. In both Luau and Python it rendered as a keyword in a body but as a plain
parameter in the signature — the same word in two colors, one line apart.
| TOML |
Color |
[table] / [[array]] header |
#d2a8ff bold |
| key |
#e6edf3 |
= [ ] . , { } |
#59667a |
| string |
#87d8f7 |
| number, bool, date-time |
#ffa657 |
| comment |
#8b949e |
Full semantic highlighting support, and consistent hover/selection surfaces across editor, panel,
lists, and buttons. examples/ has Luau, TOML, Python and JSON files covering every scope involved; each was
tokenized with its real grammar to find these, rather than guessing at scope names.
🛠️ Development
themes/*.json are generated — don't edit them by hand. The sources live in src/:
src/github-dark.json — the syntax layer, vendored verbatim
src/syntax.mjs — the overrides applied on top of it, shared by every flavor
src/ui.json — the base chrome ramp (Sleepy's, hand-tuned)
src/flavors.mjs — the flavor list and the hue rotation each one applies
src/oklch.mjs — sRGB ↔ Oklab conversion
src/check-scopes.mjs — resolves representative scope stacks against the built theme (just check)
src/analyze.mjs — prints each flavor's Oklab lightness/chroma/hue, for tuning the ramp
Flavors are derived by re-centring the base ramp's hue in Oklab, which keeps the lightness curve identical across all nine. Adding a flavor means adding one entry to src/flavors.mjs; package.json's contributes.themes is regenerated too.
just gen
🙌 Recommendations
Settings
{
"editor.fontFamily": "JetBrains Mono",
"editor.fontLigatures": true,
}
Icon theme
Charmed Icons by littensy pairs especially well with this theme.
Sleepy Theme is released under the MIT License.