Kt Color
KtColor is an HSL-based color type for KimTools WinForms controls. It replaces System.Drawing.Color with named palette colors, semantic theme variables, per-shade indexing, and operators for the common adjustments (lighten/darken, opacity, contrast, blending). It converts implicitly to and from Color, so it drops into any WinForms API that expects one.
Every example below builds a KtColor through an implicit conversion, an operator, or a static factory - never the constructor directly.
Creating a Color
The most common path is assigning a string; itβs parsed automatically:
KtColor named = "Blue"; // palette color using system named colors
KtColor tailwind = "@Blue"; // palette color using Tailwind color system
KtColor variable = "$Primary"; // theme variable
KtColor hex = "#FF5733";
KtColor rgb = "rgb(255,87,51)";
KtColor rgba = "rgba(255,87,51,0.5)";
KtColor hsl = "hsl(9,100%,60%)";
KtColor shaded = "Blue[70]"; // 70% lightness baked into the string
KtColor faded = "Blue[70]%50"; // 70% lightness, 50% opacity
From System.Drawing:
KtColor fromColor = Color.Red;
KtColor fromKnown = KnownColor.CornflowerBlue;
KtColor fromArgb = 0xFF3B82F6; // packed ARGB int
From a KtBrush (explicit - a gradientβs start/stop colors are averaged):
KtColor fromBrush = (KtColor)someBrush;
Static factories, for when you have raw components instead of a string:
KtColor c1 = KtColor.FromRGBA(59, 130, 246); // r, g, b, alpha?
KtColor c2 = KtColor.HSL(217f, 0.91f, 0.60f); // hue, saturation, lightness
KtColor c3 = KtColor.Random(); // random palette color
KtColor c4 = KtColor.Random(30); // random palette color at 30% lightness
For untrusted input, TryParse avoids throwing:
if (KtColor.TryParse(userInput, out var parsed)) { /* ... */ }
Palette
21 named colors, grouped as 4 neutral bases and 17 accents. Each is a static property and also carries the full shade range (see Shades).
| Base / Neutral | |
|---|---|
| Stone | 78716C |
| Zinc | 71717A |
| Gray | 6B7280 |
| Slate | 64748B |
| Rose | F43F5E | Emerald | 10B981 |
| Pink | EC4899 | Green | 22C55E |
| Fuchsia | D946EF | Lime | 84CC16 |
| Purple | A855F7 | Yellow | EAB308 |
| Violet | 8B5CF6 | Amber | F59E0B |
| Indigo | 6366F1 | Orange | F97316 |
| Blue | 3B82F6 | Red | EF4444 |
| Sky | 0EA5E9 | ||
| Cyan | 06B6D4 | ||
| Teal | 14B8A6 |
Plus four fixed colors that sit outside the shade system: KtColor.Empty, KtColor.White, KtColor.Transparent, KtColor.Black.
KtColor.All, KtColor.PaletteMainColors, and KtColor.PaletteBaseColors return these as arrays - useful for building a color picker.
Theme Variables
13 static properties represent semantic, re-themeable colors:
| Variable | Default |
|---|---|
| PRIMARY | RoyalBlue |
| SECONDARY | BlueViolet |
| ACCENT | DarkTurquoise |
| NEUTRAL | #515765 |
| CONTENT | White |
| SUCCESS | MediumSeaGreen |
| INFO | DodgerBlue |
| WARNING | Goldenrod |
| ERROR | Red |
| BASE_1 / BASE_2 / BASE_3 | #0F172B / #1E2939 / #314158 |
| BASE | alias for BASE_2 |
Every variable except BASE/CONTENT has a matching *Content counterpart ($PrimaryContent, $ErrorContent, etc.) for text/icons drawn on top of it. Thereβs no static property for these - reach them with the ! operator (see Content & Contrast).
Shades
Every palette color and theme variable exposes 0β100% lightness through an indexer:
KtColor light = KtColor.Blue[70]; // 70% lightness (percent, int)
KtColor light2 = KtColor.Blue[0.7f]; // 70% lightness (fraction, float)
KtColor root = KtColor.Blue[null]; // back to the root/default shade
KtColor themed = KtColor.PRIMARY[80, 20]; // 80% in light mode, 20% in dark mode - picked automatically
foreach (var shade in KtColor.Blue) iterates 11 shades from ~5% to ~95% lightness in 10% steps.
Adjusting Lightness, Saturation & Opacity
var hover = baseColor + 10; // +10% lightness (int = percentage points)
var hover2 = baseColor + 0.10f; // +10% lightness (float = fraction)
var pressed = baseColor - 10; // -10% lightness
var step = ++baseColor; // +10% lightness, one "step"
var stepD = --baseColor; // -10% lightness
var vivid = baseColor.Saturate(0.9f); // set saturation directly (same hue & lightness)
var dimmed = baseColor.Luminate(0.3f); // set lightness directly - alternative to baseColor[30]
var faded = baseColor % 40; // opacity -> 40% (int/int? on the right = opacity)
var same = 40 % baseColor; // order doesn't matter
var halved = baseColor / 2; // opacity divided by 2
Content & Contrast
KtColor text = !background; // content / contrast color
KtColor inverse = ~background; // contrast from lightness only, ignoring theme name mapping
!colorreturns a readable foreground color. For a theme variableβs root value it looks up that variableβs dedicated*Contentcounterpart (!PRIMARYβ PrimaryContent,!BASEβ CONTENT,!CONTENTβ BASE, and this applies toBASE_1/BASE_2/BASE_3as well). For anything else - palette colors, hex, custom RGB, or a shade of a theme variable (e.g.PRIMARY[70]) - it falls back to computing near-black or near-white from lightness.~coloralways computes contrast from lightness directly, skipping the theme name lookup.
Blending & Compositing
KtColor midpoint = colorA + colorB; // channel-wise average of both colors
KtColor flattened = translucentColor % background; // alpha-composite onto a background
KtColor blend30 = KtColor.Mix(colorA, colorB, 30f); // 30% colorB, 70% colorA
% has two meanings depending on the right-hand type: an int/int? sets opacity (above); a Color or KtColor composites - flattening a translucent color onto that background. + between two colors is a simple average, not alpha-aware; use % when one side is meant to be translucent.
Conditional & Fallback
KtColor a = isActive & KtColor.PRIMARY; // PRIMARY when true, its content color when false
KtColor b = isActive | KtColor.PRIMARY; // content color when true, PRIMARY when false
KtColor c = userColor | KtColor.PRIMARY; // userColor, unless it's empty - then PRIMARY
Comparison & Equality
if (colorA == colorB) { }
if (colorA != colorB) { }
bool brighter = colorA > colorB; // compares packed ARGB int
==/!=compare the canonical string form (name, hex, or token) rather than the resolved pixel - a theme variable and a literal that currently render the same color wonβt necessarily be==. Compare.Render()results (or the implicitColorconversion) if you need pixel equality.<and>are both implemented asInt() > Int()in the current source, so ordering comparisons - and<=/>=, which build on them - donβt currently distinguish direction. Worth verifying before relying on it.
Formatting & Inspection
string hex = someColor.Hex(); // "#3B82F6"
string rgb = someColor.RGB(); // "rgb(59,130,246)" or "rgba(...)" if translucent
string hsl = someColor.HSL(); // "hsl(217.0,91.2%,59.8%)"
string web = someColor.Web(); // named color if it is one, otherwise hex
string token = someColor; // implicit -> canonical token, e.g. "Blue[60]%80"
int argb = someColor.Int();
if (someColor) { } // implicit bool: true unless Empty
Common state checks: IsEmpty, IsOpaque, IsTranslucent, IsVariable, IsTheme, IsRoot.
Global Theming
KtColor.Render(true); // dark mode - derives Base_1β3 & Content from the current BASE
KtColor.Render(false); // light mode, same idea
KtColor.Render(null); // no palette change - just re-raises ThemeChanged (e.g. after editing variables)
KtColor.DarkMode(); // same as Render(true)
KtColor.LightMode(); // same as Render(false)
KtColor.Toggle(); // flips based on the current mode
bool dark = KtColor.IsDark();
KtColor.@default("Primary", Color.FromArgb(96, 93, 255)); // set a variable at runtime
KtColor.Presets.Dracula(); // apply a built-in preset
KtColor.ThemeChanged += isDark => RefreshUI();
KtColor.VariableChanged += (value, e) => Invalidate(); // e.PropertyName, e.g. "Primary"
35 built-in presets (KtColor.Presets.<Name>()), ported from DaisyUI:
Light, Dark, Cupcake, Bumblebee, Emerald, Corporate, Synthwave, Retro, Cyberpunk, Valentine, Halloween, Garden, Forest, Aqua, Lofi, Pastel, Fantasy, Wireframe, Black, Luxury, Dracula, CMYK, Autumn, Business, Acid, Lemonade, Night, Coffee, Winter, Dim, Nord, Sunset, CaramelLatte, Abyss, Silk
KtBrush:
KtBrush fill = KtColor.PRIMARY; // implicit: becomes a solid brush
KtColor back = (KtColor)someBrush; // explicit: gradients average their start/stop colors
Design-time - a public KtColor property on a control gets full Visual Studio designer support automatically (PropertyGrid dropdown of palette/theme names, color picker for custom values, correct serialization) with no extra code required.