Invariant grew from an Eclipse theme I started using in 2014 and is primarily maintained for IntelliJ IDEA, with ports for Visual Studio Code and Vim/Neovim.
The scheme uses color to identify what a symbol is and formatting to show how it is being used. Common code stays relatively quiet, while types, parameters, methods, and reserved words remain easy to find.
Visual Studio Code: Invariant Complete installs both the Invariant theme and Invariant Highlighter. Each component remains independently manageable.
The same kind of symbol should keep the same foreground wherever it appears. A class stays cyan as a declaration, type, or static qualifier; constructor declarations and calls are green because they invoke behavior. A field does not become a different color merely because it is read from another expression.
Comments are intentionally prominent. A comment should be noticed, and a file with too many comments should look like it has too many comments.
Context normally adds formatting without replacing a symbol's identity color:
- A reassigned variable or parameter gains an underline but keeps its foreground.
- Static members are italic; instance members are not.
- Inspection results add their underline, wave, border, or background over the existing syntax colors.
- Constancy does not change variable or field formatting.
A captured Java variable is a useful boundary case. A method parameter is blue in the enclosing method, but IntelliJ presents its use inside a lambda as a neutral field-like capture. Its semantic role has changed: the generated lambda object effectively carries that value as state.
Method implementation is the deliberate foreground exception. Concrete methods are green, while methods that only provide a signature are pale blue. This makes calls through an interface or abstract type distinguishable without navigating to the declaration first.
The Java example includes a record, fields, parameters, a reassigned local, static members, an interface method, and captured values inside lambdas. The parameter declarations are blue; their captured uses inside the lambda are neutral. Concrete calls are green, while the interface call uses the signature-only method color.
The lambda parameter remains blue, while values captured from the enclosing method gain a neutral highlight without changing their underlying semantic color. The same capture with IntelliJ inlay hints enabled is also kept for comparison.
Kotlin follows the same language-default meanings for types, parameters, variables, and functions. Kotlin-specific entries are kept only where the plugin exposes a distinct concept, such as named arguments, smart casts, or function-literal punctuation. Lambda arrows remain neutral, matching Java.
Python keeps parameters blue, fields neutral, calls green, and reserved names such as self and cls pink. Built-in names remain pale blue. Special names such as __init__ are green where they are defined and neutral where they are read, matching what Visual Studio Code and Neovim can express.
Imported modules and packages read as ordinary identifiers in the warm neutral #cfbfad. IntelliJ's Python plugin exposes no color key for module references, so the name in import os or in an os.path qualifier simply keeps the default foreground. The other ports are pinned to match: without an explicit rule, Visual Studio Code would color modules with the cyan namespace token and Neovim would inherit a type-like default from the @module capture, both of which would make a module read as a type in one editor but not another.
IntelliJ's Language Defaults provide the base mapping for every language that uses them. The following languages also have explicit entries in the scheme:
| Language | Explicit coverage |
|---|---|
| Java | Primary target; declarations, calls, fields, captures, records, annotations, and implementation distinctions |
| Kotlin | Kotlin-specific operators, arrows, dynamic calls, named arguments, and smart-cast contexts |
| Python | Built-ins, self, predefined names, annotations, and type parameters |
| CSS | Classes, functions, hashes, identifiers, and property names |
| Shell Script | External commands, subshell commands, and here-document delimiters |
| Markdown | Headings, emphasis, links, and autolinks |
| HTML and XML | Tag names and brackets, attribute names, custom tags, and entity references |
| YAML | Anchors and aliases |
Other IntelliJ languages receive the semantic Language Defaults automatically. Their plugins may add concepts that have not yet been tuned here.
Install Invariant from the Plugins Marketplace, or import jetbrains/invariant.icls manually from Settings → Editor → Color Scheme → Import Scheme.
Install Invariant from the Extensions Marketplace and select it from Preferences: Color Theme. To test the source locally, open the vscode directory in Visual Studio Code and press F5.
Visual Studio Code users can choose among three independently manageable extensions:
| Extension | Purpose |
|---|---|
| Invariant | Passive color theme only |
| Invariant Highlighter | Incremental parameter and reassignment enhancements |
| Invariant Complete | Extension pack containing both |
Invariant Highlighter is optional. Its invariantHighlighter.languages setting can
disable individual language adapters or all highlighting.
From the Command Palette, run:
ext install andrebrait.invariant-colors
With lazy.nvim, add:
{
"andrebrait/invariant-colors",
lazy = false,
priority = 1000,
config = function()
vim.cmd.colorscheme("invariant")
end,
}For vim-plug, use Plug 'andrebrait/invariant-colors'. You can also copy colors/invariant.vim into ~/.vim/colors/ or ~/.config/nvim/colors/. Then configure:
colorscheme invariantTrue-color terminals give the intended palette; a 256-color fallback is included.
JetBrains IDEs can distinguish captures and whether a Java method has an implementation. Visual Studio Code and Neovim preserve the distinctions emitted by their language services, but a color theme cannot infer semantic information that the service does not provide. Plain Vim syntax highlighting cannot determine captures or abstract versus concrete methods.
The IntelliJ scheme inherits from Darcula. A bundled color scheme may only name a parent the platform is certain to have registered, and Darcula is one of the two schemes DefaultColorSchemesManager always provides. Islands Dark, which this scheme named until 1.3.1, is contributed by a plugin and is absent unless the Islands UI is active; naming it made the IDE discard the whole scheme on load. Islands Dark is itself Darcula plus overrides, so every override it used to supply is now written out in the .icls file and the rendering is unchanged.
IntelliJ inherits a text-attribute entry as a whole, so the scheme cannot keep its warm-neutral default foreground while inheriting only the editor background. The TEXT background therefore copies Islands Dark 2026.2's #191a1c value.
The console, documentation popup, completion popup, and gutter backgrounds are set explicitly to the Islands Dark 2026.2 values they previously inherited. The Vim port uses those same fixed surfaces.
The Visual Studio Code port instead uses the current VS Code Dark surfaces: #121314 for the editor and gutter, #191a1b for the terminal and peek views, and #202122 for documentation and completion widgets.
npm test --prefix vscode
npm run package --prefix vscode
gradle -p jetbrains buildPlugin verifyPluginPublishing a GitHub Release runs the release workflow. Use an invariant-vX.Y.Z tag whose version matches vscode/package.json. The workflow attaches both installable archives to the GitHub Release. Stable releases also publish the VS Code extension and JetBrains plugin; prereleases remain downloadable from GitHub only. Vim and Neovim package managers use the same Git tag directly.
Invariant Highlighter and Invariant Complete release independently through their Highlighter and Complete workflows. Use highlighter-vX.Y.Z and complete-vX.Y.Z tags matching their respective package.json versions. Complete references extension IDs rather than versions, so it only needs another release when its membership or metadata changes.
Before the first stable release, create the JetBrains Marketplace plugin and add the INTELLIJ_PUBLISH_TOKEN Actions secret. Add the Visual Studio Marketplace and Open VSX tokens as the VSCE_PAT and OVSX_PAT Actions secrets. These extensions do not require signing certificates.
Invariant descends from the Sublime Text 2 Eclipse color theme by Filip Minev, distributed with Eclipse Color Theme under EPL-1.0. That scheme is based on Monokai, created by Wimer Hazenberg. Invariant preserves its distinctive semantic palette while incorporating years of changes and ports to current editors.
Invariant is licensed under the Eclipse Public License 2.0. Its source is available in this repository under the same license.



