Chroma’s generative workspace where one base color becomes a full palette through harmonies, tonal ramps, cel-shading tone sets, blackbody curves, jitter, noise, and seeded random walks.
The Theory tab is Chroma’s generative workspace. Seven section panels (Harmony, Tints / Shades / Tones, Material, Jitter, Blackbody, Noise, Random) each take a single Base color (or none) and produce a set of related colors. Every section has its own per-section count, configuration, and a pair of “Create Palette” / “Create Gradient” buttons that turn the preview into a real project asset.
Summary
Color theory has been an art-school discipline for decades and has accumulated a lot of named recipes: pick a base, rotate 180 degrees on the wheel for the complement, rotate 120 degrees for the two triadic neighbours, sample 16 evenly-spaced lightness values for tints and shades, and so on. None of these recipes are hard to compute; the difficulty is in cycling through them quickly and seeing which one actually lands for the specific scene or character you are designing.
The Theory tab does that cycling. Pick a Base color, watch every section panel update simultaneously, click Create Palette or Create Gradient on the one that works. Switch harmony types, switch hue-rotation backends (Oklch (perceptually-uniform) for balanced results, HSV for textbook color-wheel results, OkHSL (perceptually-uniform with saturation preservation) for the middle ground), or change the count on a generative section. Everything is non-destructive until a palette or gradient asset is explicitly created.
- Build a harmonious palette around a single base color, with the harmony type and the hue-rotation backend both configurable.
- Generate ramps of tints, shades, and tones around the base for cel-shading and posterised art.
- Author material tone sets (Shadow / Midtone / Highlight / Rim) for stylised lighting.
- Produce CCT (Correlated Color Temperature) blackbody ramps from a Kelvin range for fire, sky, and incandescent-light gradients.
- Generate jitter palettes (HSV variations of a base) and noise-driven palettes (coherent color paths through the hue wheel) for procedural content.
- Roll seeded random palettes with perceptual constraints (Oklab delta-E minimum, hue range, saturation and lightness clamps) when the goal is a usable surprise.
Features
- Local Base color. Tracks a Base color independent of the global active color, so exploratory tweaks in Theory do not bleed into the Old / New preview strip or the recent-color history. Persists across tab leave / re-enter and across window close / reopen via EditorPrefs.
- Import and export paths for the Base. Double-clicking the Base color swatch in the Theory header imports the global active color as the local Base. Apply Base (in the Harmony section) pushes the first generated harmony entry back into the global active color, propagating to every other tab.
- 10 harmony types. Complementary, SplitComplementary, Triadic, Tetradic (asymmetric rectangle, 0/60/180/240 degree offsets), Square (symmetric, 0/90/180/270 degree offsets), Analogous, Monochromatic (the only variable-size scheme; uses a separate Mono Count field), NearComplementary, DoubleComplementary, Rectangular (alias for Tetradic with the same offset set, surfaced for designers who know the term from other design tools).
- Three hue rotation backends. Oklch (perceptually uniform; companion colors share the base’s perceived lightness and chroma, so triadic palettes look balanced but the resulting hues differ from a textbook HSV wheel). HSV (classical color-theory wheel; red’s complement is pure cyan at 180 degrees, triadic gives pure red / green / blue at 120-degree spacing, but yellow looks much brighter than blue). OkHSL (perceptually uniform like Oklch but additionally preserves the base’s relative saturation; sweet spot between Oklch’s slight desaturation and HSV’s perceptual unevenness).
- Live hue wheel diagram. A circular widget that shows the base hue plus the harmony’s companion hues as markers around the wheel. Dragging any marker rotates the base; markers reposition in real time as the harmony type or hue mode changes.
- Tints / Shades / Tones / Ramp. Four preview rows that generate around the base in Oklab space. Tints mix toward white, Shades mix toward black, Tones mix toward gray, and Ramp produces a single black-to-base-to-white sweep as one continuous gradient. Default count 16 (choices 4 / 8 / 12 / 16 / 24).
- Material Tones. Four-color cel-shading set: Shadow, Midtone, Highlight, Rim. Derived from the base via Oklch deltas. The four-color result drops directly into a cel-shaded material’s color slots.
- CCT Blackbody ramp. Planckian-locus approximation across a user-defined Kelvin range (1500 K to 10000 K by default; the slider range spans 1000 K to 40000 K). Default count 16 (choices 4 / 8 / 12 / 16 / 24 / 32). The right primitive for fire, sun, incandescent bulb, and any physically-grounded color temperature gradient. Independent of the local Base color.
- Jitter palette. N seeded HSV variations around a base color with independent Hue, Saturation, and Value tolerance sliders and a Reroll button. Default count 32 (choices 4 / 8 / 12 / 16 / 24 / 32 / 64). Useful for foliage, organic tile patterns, and per-instance color variation.
- Noise-driven palette. N entries whose hue is driven by a single
NoiseGeneratorstratum (OpenSimplex2, Perlin, Value, ValueCubic) with configurable seed, frequency, hue center, and hue range. Consecutive entries form a coherent color path. Default count 32 (choices 8 / 12 / 16 / 24 / 32). Useful for biome palettes, sky strips, and any palette whose entries should feel related across a sweep. - Random palette. Seeded Xoshiro256 PRNG (via
RandomUtil.CreateXoshiro256) with HSL bounds (hue min/max, saturation min/max, lightness min/max), a minimum Oklab delta-E constraint to keep consecutive results perceptually distinct, and a max-attempts-per-entry fallback (default 32) to avoid infinite loops on tight constraints. Default count 32 (choices 4 / 8 / 12 / 16 / 24 / 32 / 64 / 128 / 256). - Per-section Create Palette and Create Gradient. Each section’s preview row has a pair of buttons that create a brand-new
ColorPaletteAssetorColorGradientAssetfrom the section’s current preview colors. The new asset auto-opens in the relevant editor tab and is selected in the library sidebar. See Palette and Gradient assets for the asset structure. - Reset path. The window-level Reset action clears the local Base color EditorPref so the next Theory tab activation re-seeds from the global active color.
Recipes
Each recipe below is a self-contained authoring workflow. You don’t need to read them in order – scan the names, find the one that matches what you are trying to generate, and follow the steps. The first recipe (“Set a base color”) is the entry point that every other recipe assumes you have already done.
Set a base color
Problem. Every generator on the Theory tab derives from a single local Base color. Before any harmony or ramp makes sense, you need to load a color into that Base slot. The Base is isolated from the global Chroma active color by design – exploration in Theory does not pollute your recent-color history.
Solution. There are three ways to set the Base, depending on where your starting color lives:
- From the active color. Double-click the Base color swatch in the Theory header bar. This pulls whatever is in the global Chroma active color (the color you last worked with in the Color Editor) into the Theory-local Base. All sections update immediately.
- From the hue wheel. Drag the base-hue marker on the Harmony section’s wheel to any hue. The Base updates in whichever hue space is currently selected (Oklch, HSV, or OkHSL) without leaving the tab.
- From a generated swatch. Double-click any swatch in any section’s preview row. That color becomes the new Base. This is the fastest iteration loop: generate a harmony, spot a companion color that looks more interesting than the base you started with, double-click it, and every section updates around the new choice.
The Base persists across tab leave / re-enter and across window close / reopen via EditorPrefs. The first time the Theory tab opens on a fresh install, it seeds from the global active color. After that, the persisted local store wins until you explicitly import a new color or run Reset.
To start fresh from scratch, use the window’s overflow menu Reset action. It clears the local Base store along with the rest of the transient window state, so the next Theory activation re-seeds from whatever the global active color is at that point.
Generate a triadic harmony from a base color
Problem. You are designing a three-faction sci-fi strategy game and you need a set of three colors that read as distinct but still belong together visually. Triadic is the textbook answer – three hues spaced 120 degrees apart on the wheel – but pure textbook triadic (HSV at 120 degrees) often gives you the saturated red / green / blue primary triangle, which feels generic. You want to push the result toward something with better perceptual balance.
Solution. Open the Harmony section. Set the Harmony Type dropdown to Triadic and the Hue Mode dropdown to Oklch. The hue wheel updates immediately, showing three markers at 120-degree Oklch spacing around your base hue. The preview swatch row shows the three resulting colors.
From here you can:
- Drag any marker on the hue wheel to rotate the entire harmony to a different hue base. The other two markers follow their 120-degree offsets automatically.
- Switch the Hue Mode to HSV if you need to match a print-design reference that uses the textbook color wheel (red’s complement is pure cyan, triadic gives you pure primaries).
- Use OkHSL if your base is highly saturated and you want the companions to match that boldness – Oklch can desaturate companions slightly when rotating into hues with a smaller sRGB (standard Red Green Blue) gamut.
- Click Create Palette to save the three colors as a
ColorPaletteAsset, or Create Gradient for a smooth three-stop ramp. The new asset opens in the Palette Editor or Gradient Editor automatically. - Click Apply Base to push the first harmony entry back into the global active color, propagating it to every other Chroma tab.
Build a tint, shade, and tone ramp for a UI palette
Problem. You have a brand color for a menu theme – say a mid-range teal – and you need a family of lighter and darker variants for button states, surface layers, hover highlights, and disabled text. Tints mix toward white, shades mix toward black, and tones mix toward gray; each ramp is a standard tool for UI color systems, and you want all three in Oklab space so the steps are perceptually even.
Solution. Open the Tints / Shades / Tones section. Set the Count button group to your desired number of steps (4 is tight but legible for a minimal palette; 16 gives you a full system to pick from). The section shows four labeled swatch rows:
- Tints – increasingly pale variations mixing toward white.
- Shades – increasingly dark variations mixing toward black.
- Tones – increasingly muted variations mixing toward gray (useful for atmospheric or desaturated UI surfaces).
- Ramp – a single black-to-base-to-white sweep as one continuous gradient, handy as a quick linear range reference.
Each row has its own Create Palette and Create Gradient pair. Create from the row that suits your use case: Tints for UI surface backgrounds and text layers, Shades for shadows and accent darks, Tones for muted or disabled states, Ramp when you want the full span as a single continuous gradient asset.
All four ramps update automatically when the local Base color changes, so you can keep iterating the Base from the Harmony section or a double-click swatch and watch the UI ramps update in sync.
Build a material tone set for a toon shader
Problem. You are working on a cel-shaded character and your toon shader has four color slots: a shadow color, a midtone (the base flat color), a highlight, and a rim light. Picking four coherent colors manually is slow, and the perceptual balance is easy to get wrong – the shadow needs to go cool and the rim needs to pop in saturation without clashing. You want a starting point derived mathematically from the character’s key color.
Solution. Open the Material Tone Set (cel-shading) section. It reads the local Base color and immediately produces four colors via Oklch deltas:
- Shadow – a lower-lightness, lower-chroma version of the base; the color a surface takes in low light.
- Midtone – the base color itself, with minor neutral adjustments.
- Highlight – a higher-lightness version; the color the surface takes under direct light.
- Rim – a high-saturation accent in a related hue; the color of the lit edge in a rim-lit pose.
The four-color swatch strip shows all four in order. Click Create Palette to save them as a named ColorPaletteAsset with Shadow / Midtone / Highlight / Rim labels. Click Create Gradient for a smooth four-stop ramp if your toon shader interpolates across the ramp texture rather than sampling discrete zones.
The set updates automatically any time the local Base changes, so you can iterate the base character color in the Color Editor, import it via double-click on the Base swatch, and immediately see how the material tones shift.
Generate a CCT blackbody temperature ramp
Problem. You are building a fire visual effect and you need a color gradient that runs from deep red-orange at the base through amber and white-yellow at the peak. Or you are building a time-of-day system and you want accurate sun color from sunrise (warm orange) through midday (near-white) into dusk (deep orange again). These are physically-grounded CCT (Correlated Color Temperature) transitions, and eyeballing them from memory is hard to get right.
Solution. Open the Blackbody Ramp (CCT) section. This generator is independent of the local Base color – it works entirely from the Kelvin range you specify.
Set the Min Kelvin and Max Kelvin sliders to define your range. Some reference points:
- ~1500 K: deep red-orange, close to a candle or ember.
- ~2700 K: warm incandescent bulb.
- ~5500 K: direct sunlight at noon.
- ~6500 K: overcast daylight.
- ~10000 K: blue-heavy shade or open sky.
The slider range covers 1000 K to 40000 K; the defaults (1500 K to 10000 K) cover the most useful artistic span. Set Count to match how many discrete palette swatches you need (4 for a tight FX palette, 32 for a finely graded ramp).
Click Create Palette for a discrete swatch set or Create Gradient for a continuous ramp. The gradient asset auto-opens in the Gradient Editor where you can adjust stop interpolation, blend mode, or color space for the final export.
Scatter a jittered color palette with a fixed seed
Problem. You have a forest with thousands of tree instances and you want each one to have a slightly different leaf color – close enough that they read as the same species, different enough that the canopy doesn’t look like a flat texture fill. You need N colors that are all recognizable variants of the same leaf-green base, and you need them to be reproducible so a teammate can generate the same palette tomorrow.
Solution. Open the Color Jitter section. Set your local Base to a representative leaf green, then tune the three tolerance sliders:
- Hue +/- – how far each variant can drift in hue from the base. A small value (0.03 to 0.05) gives siblings that all read as green; a wider value (0.1+) lets some tilt toward yellow or teal.
- Sat +/- – how wide the saturation range is. Higher values produce some washed-out and some vivid siblings.
- Val +/- – how wide the brightness range is. Useful for mimicking light variation through a canopy.
Set the Seed field to any fixed value (the default is 1). Every generation run with the same Seed + Base + tolerances produces exactly the same N colors, so your foliage palette is stable across teammates and sessions. Click Reroll to advance the seed by one and get an alternative draw without touching the tolerances.
Set Count to how many variants you need (32 is the default and a good starting point for a tile-variation set). Click Create Palette to save the result as a ColorPaletteAsset. You can then load that palette into the Palette and Gradient assets registry and look it up by name or tag at runtime.
Build a noise-driven biome palette
Problem. You are generating a top-down world map and you want a palette that represents a biome transition – say from deep forest green, through muted olive and tan scrub, to sandy desert yellow. You want the colors to feel like they belong to a continuous natural range, not a random scatter. The palette also needs to be reproducible from a seed so two players see the same biome map.
Solution. Open the Noise Palette section. This generator samples a coherent noise field and maps the result through a hue range to produce N colors that form a continuous color path.
Key controls:
- Seed – locks the noise sampling. Same seed + same settings = same palette every time. Hit Reroll to advance the seed and try an alternative path through the hue space.
- Algorithm – the noise function: OpenSimplex2 (the default; smooth and isotropic), Perlin (the classic Perlin look), Value (faster but blockier), ValueCubic (smoother than Value, less cost than OpenSimplex2). For a biome palette, OpenSimplex2 or Perlin give the most natural variation. See the Noise Utils page for algorithm trade-offs.
- Frequency – how quickly the noise traverses the hue range across the N entries. Low frequency (0.5 or less) gives long, gradual color transitions; high frequency (3.0+) gives rapid oscillation that can produce a broader color spread within the palette.
- Hue Center – the center hue around which the noise variation revolves (0.0 to 1.0 normalized, where 0.33 is green, 0.17 is yellow, 0.0/1.0 is red).
- Hue Range – how wide the hue sweep is around the center. A value of 0.15 gives a tight band (all recognizably the same color family); 0.5 sweeps half the wheel.
For a forest-to-desert biome transition, set Hue Center around 0.30 (green-yellow range), Hue Range around 0.15, and let the noise variation move through warm greens, olive, and tan. Set Count to 16 or 24 for a palette with enough steps to differentiate biome zones without redundant near-duplicates. Click Create Gradient for a continuous biome-color ramp or Create Palette for a discrete swatch set.
Generate a distinct random palette with a fixed seed
Problem. You are building a debug visualization system that needs to assign a unique color to each of 32 active AI agents so you can track them in the scene view. You want the colors to be visually distinct from each other (no two agents should be easily confused), reasonably saturated so they read against the game world, and reproducible between editor sessions so the same agent always gets the same color.
Solution. Open the Random Palette Generator section. Set the Seed field to a fixed value (the default is 1; any value works as long as you keep it stable). Same seed + same constraints = same palette every session.
Tune the HSL bounds to keep the colors in a usable range:
- Hue Min / Hue Max – set to 0.0 / 1.0 to allow any hue (the default). Narrow the range if you want all agents to read as “warm” or “cool” as a team signal.
- Sat Min / Sat Max – default 0.35 / 0.90. Keeping Sat Min above 0.3 avoids washed-out colors; keeping Sat Max below 1.0 avoids colors that are too harsh.
- Light Min / Light Max – default 0.35 / 0.85. This keeps very dark and very bright colors out of the set, improving readability against typical game backgrounds.
- Min Delta E – the minimum perceptual distance (Oklab delta-E) between any two colors in the result. The default (0.10) keeps colors reasonably distinct; raise it to 0.20 or higher if you need no two colors to be confusable under any circumstances. Each entry tries up to MaxAttemptsPerEntry (default 32) to find a valid candidate; if no candidate passes the constraint within that budget, the generator accepts the best candidate found rather than looping indefinitely.
Set Count to 32. Click Create Palette to save the result. The palette asset can be loaded via the Palette and Gradient assets registry and colors looked up by index at runtime to assign to agents.
Send generated colors to a palette or gradient asset
Problem. You have a preview swatch row in one of the Theory sections that looks exactly right, and you want to turn it into a project asset you can actually use – assign it to a material, load it at runtime, or open it in the Palette Editor for further editing.
Solution. Every section’s preview row has a Create Palette and a Create Gradient button.
- Create Palette creates a new
ColorPaletteAssetwith the preview colors as named entries. Entry names are resolved from your configured default named-color database so you get readable names rather than generic placeholders. The asset is saved under the configured palette directory (defaultAssets/Scylla/Resources/Color/Palettes/) and auto-opens in the Palette Editor. - Create Gradient creates a new
ColorGradientAssetwith the preview colors as evenly-spaced stops using smooth Oklab interpolation by default. The asset is saved under the configured gradient directory (defaultAssets/Scylla/Resources/Color/Gradients/) and auto-opens in the Gradient Editor.
Both assets are immediately available in the library sidebar’s corresponding sub-tab after creation. You can continue adjusting the Theory controls and create multiple assets in one session – each click always produces a new asset rather than overwriting the previous one.
The Harmony section has an additional Apply Base button. This pushes the first entry in the harmony preview back into the global Chroma active color, propagating it to every other tab in the window. Use this when you have found the base color you want through Theory exploration and you want to carry it back into the Color Editor or the Accessibility tab.
Tips and pitfalls
- The local Base is not the global active color. Dragging the hue wheel marker, double-clicking a generated swatch, or double-clicking the Base swatch header to import all change the local Base only. The global active color is left alone until Apply Base is clicked, on purpose, so exploratory tweaks do not pollute the recent-color history.
- Oklch vs HSV hue rotation produces visibly different complements. A pure-red base’s complement is steel-blue under Oklch (a color that perceptually balances red’s lightness and chroma) but pure cyan under HSV (the textbook 180-degree rotation). Neither is wrong; pick the one that matches the design reference.
- OkHSL is usually the right choice for saturated bases. Oklch preserves perceived lightness but can slightly desaturate companions when rotating into hues with a smaller sRGB gamut. HSV preserves saturation but loses perceived balance. OkHSL preserves the base’s relative saturation, keeping bold bases bold across the hue rotation.
- The Blackbody section ignores the Base color. It is driven entirely by the Kelvin range sliders. Changing the Base in Theory does not affect the Blackbody preview.
- The Noise section also ignores the Base color. Like Blackbody, it generates from its own seed and hue controls rather than from the Theory-local Base.
- Random with a tight constraint can produce fewer colors than requested. When Min Delta E is high and the hue range is narrow, the generator may run out of distinct candidates before reaching the requested count. Loosen the constraints or accept fewer colors.
- Jitter and Noise differ in continuity. Jitter produces independent variations (each entry is its own random offset from the base). Noise produces a continuous color path (entries are related to their neighbours). For sibling-color sets, use Jitter; for color sweeps, use Noise.
- The Reset action clears the local Base. The window-overflow Reset wipes the local Base EditorPref along with the rest of the transient state, so the next Theory activation re-seeds from the global active color. Reset is for starting fresh after a long session, not for minor adjustments.
- Create Palette creates a new asset every time. There is no “update the last palette” option; each click produces a fresh
ColorPaletteAssetwith a unique name. To replace a previous palette, delete it from the Project window first.