Skip to content

Color Roles

Vinícius Campos edited this page Aug 22, 2026 · 1 revision

Color Roles

Both theme families paint from a small set of named roles rather than colouring each Visual Studio classification individually. A role is a decision — "this is what a type name looks like" — and the classifications listed under it are the places that decision lands.

The tables below are the Focus mapping, read from the TEMPLATE in FocusThemes/Themes/gen-themes.py. Graphite uses the same roles, minus the split across type kinds: see Graphite Themes.

The type kinds

The Focus family gives each of the five C# type kinds a colour of its own. Roslyn ships a separate classification for each, so all five are reachable from Fonts and Colors without an extension — only the italic on interfaces needs one.

Role Classifications
class class name, module name, type parameter name, delegate name, array name, pointer name, function pointer name, User Types, User Types(Delegates), User Types(Type parameters)
interface interface name, User Types(Interfaces)
record record class name, record struct name
struct struct name, User Types(Value types)
enum enum name, User Types(Enums)

class is the fallback for anything that is a type but is not one of the four kinds singled out. interface is a lighter tint of the class hue rather than a hue of its own: it is the same family, and italic is what tells the two apart.

enum member name is deliberately not on the enum row. The design colours the name of the type, not its members, and a member is read as a value — so it sits with variable.

Syntax

Role Classifications
keyword keyword, keyword - control, preprocessor keyword, label name, mismatched brace, plus the XML, XAML and CSS keyword classifications
method method name, extension method name
variable local name, field name, property name, event name, parameter name, enum member name, Identifier, and the XML/XAML/HTML attribute names
operator operator, operator - overloaded, HTML Operator
string string, string - verbatim, and the attribute-value classifications
number number, constant name, string - escape character, Literal, XML CData Section
comment comment, the xml doc comment text, punctuation, namespace name, preprocessor text

Two of these share a colour with another role by design. Constants and escape sequences ride with number, because both are literal values. Punctuation and namespace names ride with comment, because both are structure the eye should be able to skip.

Why variable and operator are tints

Every other role is a hue drawn in the design. These two are not, and that is a decision rather than a shortage of hues.

variable is the theme's plain-text hue, desaturated. Names are the most frequent thing on a screen of code. Giving them a full-strength hue of their own would make every line compete with itself, so they read as text — present, but not claiming attention. They still carry some colour, because the alternative (leaving identifiers at plain text) collapses locals, fields and properties into the same read as punctuation, and "what is this name" stops being answerable at a glance.

operator is the keyword hue, lightened. An operator is syntax, in the same way a keyword is, so it belongs to that family. But it recurs several times per line, and a fully saturated hue on every = and . reads as noise rather than as structure. Lightening it keeps the relationship and drops the volume.

A consequence worth knowing when reading the generator's output: operator sits within a few degrees of keyword on the colour wheel, and variable within a few degrees of the plain-text hue. The separation report printed on every run measures hue only, so it flags those two pairs every time. That is why it reports rather than fails — for these, saturation and lightness are the channels doing the work.

Nesting

Brace pairs cycle through three roles by depth: class, then method, then string. A mismatched brace uses keyword, and the keyword hue is kept out of the cycle for that reason — the warning only reads as a warning if nothing else on the line is already wearing it.

Weight and slant

A .vstheme carries colour only. It has no attribute for weight or slant, so emphasis comes from MEF ClassificationFormatDefinition exports instead — FocusThemes/FocusEmphasis.cs and GraphiteTheme/GraphiteEmphasis.cs.

Italic: comment, the three xml doc comment classifications, keyword, keyword - control, interface name, type parameter name, parameter name, extension method name.

Bold: class name, record class name, keyword - control, operator - overloaded.

Two notes on that split. keyword is italic in its entirety because C# has no separate classification for predefined types: int and string are plain keyword, exactly like public and class, so slanting primitives means slanting every keyword. And interface name is italic but not bold — it is already marked as abstract by the slant, and stacking bold on top would make interfaces the loudest thing on screen rather than types in general.

These definitions set only the weight and slant flags and never touch ForegroundColor, so the active theme still owns the colour. That also means the emphasis applies under every theme, not just these: MEF format definitions are static metadata and cannot be scoped to one theme. Switching to the built-in Dark keeps comments italic.

Anything you have changed yourself in Fonts and Colors wins over all of it. See Customizing.

Clone this wiki locally